您的位置:首页 > 数据库 > Oracle

如何在SAS中直接使用Oracle特有函数--sas Pass-Through Facility

2013-07-25 10:25 447 查看
           声明:参考了百度文库中的文档,向有关作者表示感谢!

     在使用sas进行行转列的字符串合并时,发现sas中并没有合适的方法,而oracle在10g之后包含了WMSYS.WM_CONCAT函数,可以轻松的解决这类问题:

     

select t.rank, t.Name from t_menu_item t;

10 CLARK
10 KING
10 MILLER
20 ADAMS
20 FORD
20 JONES
20 SCOTT
20 SMITH
30 ALLEN
30 BLAKE
30 JAMES
30 MARTIN
30 TURNER
30 WARD

--------------------------------

我们通过 10g 所提供的 WMSYS.WM_CONCAT 函数即可以完成 行转列的效果

select t.rank, WMSYS.WM_CONCAT(t.Name) TIME From t_menu_item t GROUP BY t.rank;

DEPTNO ENAME

------ ----------
10 CLARK, KING, MILLER
20 ADAMS, FORD, JONES, SCOTT, SMITH
30 ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD

例子如下:

SQL> create table idtable (id number,name varchar2(30));

Table created

SQL> insert into idtable values(10,'ab');

1 row inserted

SQL> insert into idtable values(10,'bc');

1 row inserted

SQL> insert into idtable values(10,'cd');

1 row inserted

SQL> insert into idtable values(20,'hi');

1 row inserted

SQL> insert into idtable values(20,'ij');

1 row inserted

SQL> insert into idtable values(20,'mn');

1 row inserted

SQL> select * from idtable;

ID NAME

---------- ------------------------------
10 ab
10 bc
10 cd
20 hi
20 ij
20 mn

6 rows selected

SQL> select id,wmsys.wm_concat(name) name from idtable

2 group by id;

ID NAME

---------- --------------------------------------------------------------------------------
10 ab,bc,cd
20 hi,ij,mn

SQL> select id,wmsys.wm_concat(name) over (order by id) name from idtable;

ID NAME

---------- --------------------------------------------------------------------------------
10 ab,bc,cd
10 ab,bc,cd
10 ab,bc,cd
20 ab,bc,cd,hi,ij,mn
20 ab,bc,cd,hi,ij,mn
20 ab,bc,cd,hi,ij,mn

6 rows selected

SQL> select id,wmsys.wm_concat(name) over (order by id,name) name from idtable;

ID NAME

---------- --------------------------------------------------------------------------------
10 ab
10 ab,bc
10 ab,bc,cd
20 ab,bc,cd,hi
20 ab,bc,cd,hi,ij
20 ab,bc,cd,hi,ij,mn

6 rows selected

个人觉得这个用法比较有趣.

SQL> select id,wmsys.wm_concat(name) over (partition by id) name from idtable;

ID NAME

---------- --------------------------------------------------------------------------------
10 ab,bc,cd
10 ab,bc,cd
10 ab,bc,cd
20 hi,ij,mn
20 hi,ij,mn
20 hi,ij,mn

6 rows selected

SQL> select id,wmsys.wm_concat(name) over (partition by id,name) name from idtable;

ID NAME

---------- --------------------------------------------------------------------------------
10 ab
10 bc
10 cd
20 hi
20 ij
20 mn

6 rows selected

ps:

wmsys.wm_concat、sys_connect_by_path、自定义行数实现行列转换:

CREATE TABLE tab_name(ID INTEGER NOT NULL PRIMARY KEY,cName VARCHAR2(20));

CREATE TABLE tab_name2(ID INTEGER NOT NULL,pName VARCHAR2(20));

INSERT INTO tab_name(ID,cName) VALUES (1,'百度');

INSERT INTO tab_name(ID,cName) VALUES (2,'Google');

INSERT INTO tab_name(ID,cName) VALUES (3,'网易');

INSERT INTO tab_name2(ID,pName) VALUES (1,'研发部');

INSERT INTO tab_name2(ID,pName) VALUES (1,'市场部');

INSERT INTO tab_name2(ID,pName) VALUES (2,'研发部');

INSERT INTO tab_name2(ID,pName) VALUES (2,'平台架构');

INSERT INTO tab_name2(ID,pName) VALUES (3,'研发部');

COMMIT;

期望结果:

ID
cName pName

1
百度
研发部,市场部

2
Google
研发部

3
网易
研发部,平台架构

方法一:使用wmsys.wm_concat()

SELECT t1.ID,t1.cName,wmsys.wm_concat(t2.pName) FROM tab_name t1,tab_name2 t2 WHERE t1.ID=t2.ID GROUP BY t1.cName,t1.id;

方法二:使用sys_connect_by_path

select id, cName, ltrim(max(sys_connect_by_path(pName, ',')), ',') from (select row_number() over(PARTITION by t1.id ORDER by cName) r,t1.*, t2.pName from tab_name t1, tab_name2
t2 where t1.id = t2.id)

start with r=1 CONNECT by prior r =r-1 and prior id = id group by id ,cName order by id;

方法三:使用自定义函数

create or replace function coltorow(midId INT) RETURN VARCHAR2 is

Result VARCHAR2(1000);

begin

FOR cur IN (SELECT pName FROM tab_name2 t2 WHERE midId=t2.id) LOOP

RESULT:=RESULT||cur.pName||',';

END LOOP;

RESULT:=rtrim(RESULT,',');

return(Result);

end coltorow;

SELECT t1.*,coltorow(t1.ID) FROM tab_name t1,tab_name2 t2 WHERE t1.ID=t2.ID GROUP BY t1.ID,t1.cname ORDER BY t1.ID;

转自百度空间

        这就引出了另外一个问题,如何在sas中使用oracle语句或者说如何直接使用oracle中存在的功能强大的函数呢,这就需要使用sas的pass-through功能。

       

SQL Procedure Pass-Through Facility: ORACLE Specifics

For a complete description of the PROC SQL statements, see
SQL Procedure Pass-Through Facility Statements.

CONNECT statement, see The following section describes the ORACLE-specific arguments that you use in the
CONNECT statement.

 

Arguments to Connect to ORACLE
The CONNECT statement is optional when connecting to ORACLE. If you omit the CONNECT statement, an implicit connection is made with your OPS$sysid, if it is enabled. When you omit a CONNECT
statement, an implicit connection is performed when the first EXECUTE statement or CONNECTION TO component is passed to ORACLE. In this case you must use the default DBMS name
ORACLE
. The interface to ORACLE can connect to multiple databases (both local and remote) and to multiple user IDs. If you use multiple simultaneous connections, you must use an
alias argument to identify each connection. If you do not specify an alias, the default alias
ORACLE
is used.

 

CONNECT TO ORACLE <AS alias> (USER=ORACLE-user-name

PASSWORD=ORACLE-password PATH="ORACLE-path-designation" BUFFSIZE=number-of-rows PRESERVE_COMMENTS);
USER=<'>ORACLE-user-name<'>
specifies an optional ORACLE user name. If you omit an ORACLE password and user name, the default ORACLE user ID OPS$sysid is used if it is enabled. If you specify USER=, you must also specify ORAPW=.

ORAPW= | PASSWORD= | PW= <'>ORACLE-password<'>
specifies an optional ORACLE password that is associated with the ORACLE user name. If you omit an ORACLE password, the default ORACLE user ID OPS$sysid is used, if it is enabled. If you specify ORAPW=, you
must also specify USER=.

BUFFSIZE=number-of-rows
specifies the number of rows to retrieve from an ORACLE table or view with each fetch. Using this argument can improve the performance of any query to ORACLE.

By setting the value of the BUFFSIZE= argument in your SAS programs, you can find the optimal number of rows for a given query on a given table. The default buffer size is 25 rows per fetch. The limit is 32,767 rows per fetch,
although a practical limit for most applications is less, depending on the available memory.

PRESERVE_COMMENTS
enables you to pass additional information (called "hints") to ORACLE for processing. These hints might direct the ORACLE query optimizer to choose the best processing method based on your hint.

You specify PRESERVE_COMMENTS as an argument in the CONNECT statement. Then you specify the hints in the CONNECTION TO component's ORACLE SQL query. The hints are entered as comments in the SQL query and are passed to and processed
by ORACLE.

PATH=<'>ORACLE-database-specification<'>
specifies the ORACLE driver, node, and database. Aliases are required if you are using SQL*Net Version 2.0 or later. In some operating environments, you can enter the information that is required by the PATH= statement before
invoking the SAS System.
SAS/ACCESS uses the same ORACLE path designation that you use to connect to ORACLE directly. See your database administrator to determine the path designations that have been set up in your operating environment, and to determine
the default value if you do not specify a path designation. On UNIX systems, the TWO_TASK environment variable is used, if set. If neither PATH= nor TWO_TASK have been set, the default value is the local driver.

 

Pass-Through Examples
The following example uses the alias DBCON for the DBMS connection (the connection alias is optional):

proc sql;
connect to oracle as dbcon
(user=scott password=tiger buffsize=100
path='myorapath');
quit;


The following example connects to ORACLE and sends it two EXECUTE statements to process.

proc sql;
connect to oracle (user=scott
password=tiger);

execute (create view whotookorders as
select ordernum, takenby,
firstname, lastname, phone
from orders, employees
where orders.takenby=employees.empid)
by oracle;
execute (grant select on whotookorders
to testuser) by oracle;

disconnect from oracle;
quit;


The following example performs a query, shown in underlined text, on the ORACLE table CUSTOMERS:

proc sql;
connect to oracle (user=scott
password=tiger);
select *
from connection to oracle
(select * from customers
where customer like '1%');
disconnect from oracle;
quit;


In this example, the PRESERVE_COMMENTS argument is specified after the USER= and PASSWORD= arguments. The ORACLE SQL query is enclosed in required parentheses. The SQL INDX command identifies the index for the ORACLE query optimizer
to use in processing the query. Note that multiple hints are separated with blanks.

proc sql;
connect to oracle as mycon(user=scott
password=tiger preserve_comments);
select *
from connection to mycon
(select /* +indx(empid) all_rows */
count(*) from employees);
quit;


 

     这里说的访问数据库不是把数据库作为一个 lib 来访问,而是通过 connection 来访问,为什用sas/access 的这种办法来访问 DBMS呢,是因为要处理大量数据的时候,SAS 要在本机生成一些文件(临时文件之类),把 sql 语句直接提交给 DBMS,由 DMBS 执行,SAS 就不会需要中间这些步骤了。
     
简单来说,就是把 sql 语句交给 DBMS engine 来执行,这种方式在 SAS 里叫做 Pass-Through Facility。

下面是一个完整的 pass-through 方式执行 sql 的语句:
  
proc sql;
  connect to oracle as mydb (Path='ConnectionString' user='dbuser' password='passwd');
  %put &sqlxmsg;
    select count(*) from connection to mydb
     (select * from scott);   
%put &sqlxmsg;
disconnect from mydb;
quit;

1. connect to 语句是连接到数据库,然后给 sas 一个别名,叫 mydb
2. select count(*) from connection to mydb 这里是指从 DBMS 返回的结果从 select 数据,而真正运行在 dbms 端的语句则是括号中的这句   (select * from suspect_duplicates_2);   
3. 当然是 断开连接了 disconnect from mydb;
ps.
%put &sqlxmsg; 是 sas 的宏,用来输出 dbms 的错误信息

以上的示例是用来 select 有结果集的,对于没有结果集的 sql 语句,要用到 EXECUTE,见下例:

 proc sql;
  connect to oracle as mydb (Path='ConnectionString' user='dbuser' password='passwd');
  %put &sqlxmsg;
    execute
     (create table .......) by mydb;
   
%put &sqlxmsg;
disconnect from mydb;
quit;

括号里的 sql 语句可以是 create, update, 等等...

二. SAS访问数据库

sas可以用odbc连接数据库

也可以用db connect

随便你用什么方法

如果odbc配置好了

在sas里面写

proc sql;

  connect to odbc (database= uid= pwd=);

   disconnect from odbc;

quit;

如果直接连接数据库,对各个数据库是不同的

例如对db2

proc sql;

connect to db2(database= user= pwd=);

    execute() by db2;

  disconnect from db2;

quit;

或者

proc sql;

connect to db2 as aa(database= user= pwd=);

  create table bb as select * 

   from connection to aa(select * from cc);

disconnect from db2;

quit;

还可以用sas的libname,具体方法类似,sas有自己的online doc里面有具体的方法,你可以参考!!

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息