使用PL / SQL的所有示例我都可以找到这样的结果(this example taken from Wikipedia):
FOR RecordIndex IN (SELECT person_code FROM people_table)
LOOP
DBMS_OUTPUT.PUT_LINE(RecordIndex.person_code);
END LOOP;
换句话说,它们都有一个共同点:当需要在某处实际输出数据时,它们会将其粘贴在DBMS_OUTPUT
中,这对于应用程序处理它来说似乎是一个相当无用的地方
如果我想使用PL / SQL功能从Oracle数据库中检索数据,就好像这些数据是纯SQL查询的结果一样,我该怎么做?例如,如果我想处理DELETE ... RETURNING ... INTO
SQL语句删除的行,就像我处理SELECT ... FROM ...
的结果一样?
我不想修改数据库的架构或创建任何存储过程;我只想做cursor.execute("begin; ... something; end"); results = cursor.fetchall()
。
特别是,我不想要使用cursor.var()
创建变量,因为该API在数据库实现之间不可移植。 (显然,SQL也不可移植,但无论如何都需要为不同的数据库后端生成自定义SQL字符串,这是一个普遍接受的事实。)
答案 0 :(得分:1)
使用Oracle 12c,您将能够在SELECT语句中定义临时PL / SQL函数和使用它:
WITH FUNCTION x(param)
<body>
END x;
SELECT x(p) FROM t
这是一个 SQL语句,您可以通过常规方式从中获取行。 不幸的是,Oracle 12c还没有发布......
答案 1 :(得分:1)
Oracle中的“临时表”想法很糟糕。它们与SQL * Server或Sybase中的临时表不同。在Oracle中,表是PERMANENT;只有内容是暂时的。 所以你不应该编写一个需要动态创建/删除表的应用程序 - 在这种方法之后你会遇到各种各样的问题。
答案 2 :(得分:1)
使用OCI,您只能检索简单类型的表,而不能检索记录表
使用cx_Oracle(Python):
cx = cx_Oracle.connect(dsn)
cu = cx.cursor()
dates = cu.var(cx_Oracle.DATE, 100)
cu.execute("""
DECLARE
TYPE date_tab_typ IS TABLE OF DATE INDEX BY PLS_INTEGER;
v_dates date_tab_typ;
BEGIN
SELECT SYSDATE-ROWNUM BULK COLLECT INTO v_dates
FROM user_objects
WHERE ROWNUM < 100;
:1 := v_dates;
END;
""", [dates])
dates = [dates.getvalue(i+1) for i in xrange(100)]
我编写了一个库,它围绕存储的函数/过程生成这样的匿名PL / SQL块,以便能够使用记录类型的数组(你需要在记录中每列创建一个数组) - 工作,但不是很好
或者如果你不能使用游标作为返回类型(因为你不能将记录作为选择产生),那么你可以编写PIPELINED存储函数:它们像Python生成器一样工作,每个PIPE调用产生一条记录!
答案 3 :(得分:0)
您的要求是:
你还在评论中询问你是如何创建一个在交易结束时将被销毁的临时表,我会给你一个例子(因为我认为这是唯一能满足它的方法)你的要求)。
[关于此问题的一般注意事项是不处理错误或防弹,但如果你真的想以这种方式进行,这应该可以帮助你开始]
import cx_Oracle
def main():
block = """
BEGIN
-- you could put your PL/SQL in here,
-- to insert values into this table
INSERT INTO some_table (col1, col2) VALUES ('test', 'this');
END;
"""
conn = cx_Oracle.connect("User/password@somewhere")
curs = conn.cursor()
conn.begin()
curs.execute("""CREATE GLOBAL TEMPORARY TABLE some_table (
col1 VARCHAR2(10),
col2 VARCHAR2(10)
) ON COMMIT PRESERVE ROWS""")
curs.execute(block)
curs.execute('SELECT * FROM some_table')
print(curs.fetchall())
curs.execute('TRUNCATE TABLE some_table')
curs.execute('DROP TABLE some_table')
conn.commit()
if __name__ == '__main__':
main()
返回: [('test','this')]
Oracle Global Temporary Table Docs此处。
答案 4 :(得分:0)
您可以在匿名块中使用DBMS_SQL包来描述您的查询
q="""DECLARE
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
v_sql dbms_sql.varchar2a;
v_sql_1 varchar2(32767);
v_sql_2 varchar2(32767);
v_sql_3 varchar2(32767);
v_sql_4 varchar2(32767);
v_type VARCHAR2(32):='';
PROCEDURE print_rec(rec in DBMS_SQL.DESC_REC) IS
BEGIN
v_type:=CASE rec.col_type
WHEN 1 THEN 'VARCHAR2'
WHEN 12 THEN 'DATE'
WHEN 2 THEN 'NUMBER'
ELSE ''||rec.col_type
END;
DBMS_OUTPUT.PUT_LINE(rec.col_name||':'||rec.col_max_len||':'||v_type);
END;
BEGIN
v_sql(1):='%s';
v_sql(2):='%s';
v_sql(3):='%s';
v_sql(4):='%s';
v_sql(5):='%s';
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c, v_sql,1,5,False, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
/*
* Following loop could simply be for j in 1..col_cnt loop.
* Here we are simply illustrating some of the PL/SQL table
* features.
*/
col_num := rec_tab.first;
IF (col_num IS NOT NULL) THEN
LOOP
print_rec(rec_tab(col_num));
col_num := rec_tab.next(col_num);
EXIT WHEN (col_num IS NULL);
END LOOP;
END IF;
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
""" % (qry[0:32000].replace("'","''"),qry[32000:64000].replace("'","''"),qry[64000:96000].replace("'","''"),qry[96000:128000].replace("'","''"),qry[128000:160000].replace("'","''"))
regexp=re.compile(r'([\w\_\:\(\)\d]+)')
在此步骤之后,您可以创建SQL语句并使用SQL * Plus
运行提取查看extractor.py了解更多详情。
答案 5 :(得分:-1)
你可以通过两种方式实现: 1.不便携 - 写入全球背景。 2.便携式 - 写入临时表。