2

私が見つけることができるPL/SQLの使用例はすべて、次のようになります(この例はウィキペディアから抜粋したものです)。

FOR RecordIndex IN (SELECT person_code FROM people_table)
LOOP
  DBMS_OUTPUT.PUT_LINE(RecordIndex.person_code);
END LOOP;

言い換えれば、それらすべてに共通することが1つあります。実際にデータをどこかに出力するときは、データを貼り付けDBMS_OUTPUTます。これは、アプリケーションがデータを処理するのに非常に役に立たない場所のようです。

PL / SQL機能を使用してOracleデータベースからデータを取得したい場合、このデータがプレーンSQLクエリの結果であるかのようにするにはどうすればよいですか。たとえば、DELETE ... RETURNING ... INTOSQLステートメントによって削除された行を、 SELECT ... FROM ...?の結果を処理するのと同じ方法で処理したい場合です。

データベースのスキーマを変更したり、ストアドプロシージャを作成したりしたくありません。やりたいだけですcursor.execute("begin; ... something; end"); results = cursor.fetchall()

特に、そのAPIはデータベース実装間で移植できないため、変数を作成したくありません。cursor.var()(もちろん、SQLも移植可能ではありませんが、さまざまなデータベースバックエンド用にカスタムSQL文字列を生成する必要があることは一般的に受け入れられています。)

4

6 に答える 6

1

Oracle 12c では、一時的な PL/SQL 関数を定義て、SELECT ステートメントで使用できます。

WITH FUNCTION x(param)
  <body>
END x;
SELECT x(p) FROM t

これは1 つのSQL ステートメントであり、通常の方法で行をフェッチできる select です。残念ながら、Oracle 12c はまだリリースされていません...

于 2013-04-18T23:28:20.503 に答える
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 呼び出しごとに 1 つのレコードを生成します!

于 2013-04-19T17:59:39.100 に答える
0

あなたの要件は次のとおりです。

  • データベースのスキーマを変更したくない
  • またはストアドプロシージャを作成します...特に、cursor.var()で変数を作成したくありません (残念ながら、ストアドプロシージャは通常の方法です)

また、コメントで、トランザクションの最後に破棄される一時テーブルを作成する方法を尋ねました。例を挙げます(これが要件を満たす唯一の方法だと思うため) .

[エラーを処理しないことや防弾であることについては、通常の警告がありますが、本当にこの方法で進めたい場合は、これで始められるはずです]

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グローバル一時テーブルのドキュメントはこちら。

于 2013-04-19T00:52:57.827 に答える
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を確認してください。

于 2016-05-18T12:44:07.787 に答える
-1

2つの方法でそれを行うことができます:1。移植性がない-グローバルコンテキストに書き込みます。2.ポータブル-一時テーブルに書き込みます。

于 2011-12-15T09:52:18.540 に答える