2017-12-07 26 views
0

ユーザー入力に基づいて3つのテーブルからデータを準備し、COPY TOを使用してデータをエクスポートする必要があるplpgsql関数があります。データは交通事故であるため、3つのテーブルはaccident,casualtyおよびvehicleであり、それぞれの事故は、3つのテーブルすべてに存在するaccidentid列を介して車両および死傷者テーブルのゼロ以上のレコードにリンクしています。 severityおよびlocal_authoritiesは入力パラメータ(両方ともtext [])です。動的SQLクエリでWITHブロックを使用する方法

sql_query = 'SELECT COUNT(*) FROM accident WHERE severity = ANY(' || quote_literal(severity) 
|| ') AND local_auth = ANY (' || quote_literal(local_authorities) || ')'; 

EXECUTE sql_query INTO result_count; 

IF result_count > 0 THEN 
    -- replace Select Count(*) With Select * 
    sql_query = Overlay(sql_query placing '*' from 8 for 8); 

    -- copy the accident data first 
    EXECUTE 'COPY (' || sql_query || ') TO ' || quote_literal(file_path || file_name_a) || 
    ' CSV'; 

この最初のビットは、関連する事故を取得しますので、私は今、関連の車両や損害データをダウンロードするために最初のクエリからaccidentid年代を使用するための最も効率的な方法を探しています。

私は、私はこのようなWITHブロックを使用することができるだろうと思った:

-- replace * with accidentid 
sql_query = Overlay(sql_query placing 'accidentid' from 8 for 1); 

WITH acc_ids AS (sql_query) 
    EXECUTE 'COPY (SELECT * FROM vehicle WHERE accidentid IN (SELECT accidentid FROM 
    acc_ids)) TO ' || out_path_and_vfilename || ' CSV'; 
    EXECUTE 'COPY (SELECT * FROM casualty WHERE accidentid IN (SELECT accidentid FROM 
    acc_ids)) TO ' || out_path_and_cfilename || ' CSV'; 

が、エラーが出ます:

ERROR: syntax error at or near "$1"

LINE 1: WITH acc_ids AS ($1) EXECUTE 'COPY (SELECT * FROM accident....

私は非動的テストケースで上記を試してみました例えば

WITH acc_ids AS (
    SELECT accidentid FROM accident 
    WHERE severity = ANY ('{3,2}') 
    AND local_auth = ANY ('{E09000001,E09000002}') 
    ) 
    SELECT * FROM vehicle 
    WHERE accidentid IN (
    SELECT accidentid FROM acc_ids); 

残念ながら、サーバはまだPostgres 8.4を実行していますので、当分はformat()を使用することはできません。

これはおそらくWITHブロックでは不可能ですが、私が達成しようとしていることを少なくとも示してくれることを願っています。

編集/更新

主な目標は、理想的には場合accidentテーブルの上に3回

答えて

2

を選択を実行しなくても、3つの別々のcsvのファイルに3つのテーブルから関連データを取得することですあなたは、文字列変数に格納されたクエリ(一部を)実行したいあなたは

EXECUTE 'WITH acc_ids AS (' || sql_query || ')' 
    'SELECT ... '; 

のような動的なクエリを必要とするいずれかの全体のクエリは0で実行される文字列です。、またはクエリ全体が静的SQLです。それらを混在させることはできません。

CTEが必要ですか?ジョインとしてクエリを表現できる場合、オプティマイザにはさらに多くのオプションがあります。

+0

ました文字列としてのクエリ全体が意味をなさないので、私はそれが問題かもしれないと考えていました。私は3つの別々のエクスポートファイルが必要なので、私は結合でこれを行うことができるとは思わない、そうでなければ、この – Alex

+0

の反対側でインポートルーチン全体を書き直さなければならない。実際には、 'copy'ステートメントのファイル名とパスも変数に保持されているとすれば、ほとんどの場合は 'execute'コピーをネストする必要があります(select '最初の' execute'文字列の中で、すべての引用が実用的でないと考えている – Alex

+0

'COPY(WITH ... SELECT ...)TO ...'のようなものを書くときに何が問題になるのですか? –

0

これは私がCTEせずに何をする必要があるかないが、私はaccidentテーブルの上に3回同じクエリを実行する必要があるため、私は、これは、これを解決する最も効率的な方法であることを見ることができない。

sql_query = sql_query || which_tab || ' WHERE severity = ANY ('|| 
    quote_literal(severity) ||') AND ' || date_start || ' AND ' || 
    date_end || ' AND local_auth = ANY (' || 
    quote_literal(local_authorities) || ')'; 

-- replace * with COUNT(*) 
sql_query = Overlay(sql_query placing 'COUNT(*)' from 8 for 1); 
EXECUTE sql_query INTO result_count; 

IF result_count > 0 THEN 

    -- replace COUNT(*) with * 
    sql_query = Overlay(sql_query placing '*' from 8 for 8); 
    -- copy the accident data first 
    EXECUTE 'COPY (' || sql_query || ') TO ' || quote_literal(file_path || 
     file_name_a) || ' CSV'; 

    sql_query = Overlay(sql_query placing 'accidentid' from 8 for 1); 
    -- vehicles 
    EXECUTE 'COPY (SELECT * FROM vehicle WHERE accidentid IN (
    SELECT accidentid FROM accident 
    WHERE severity = ANY (' || quote_literal(severity) || ') 
    AND local_auth = ANY (' || quote_literal(local_authorities) ||'))) 
    TO ' || quote_literal(file_path || file_name_v) || ' CSV'; 
    -- casualties 
    EXECUTE 'COPY (SELECT * FROM casualty WHERE accidentid IN (
    SELECT accidentid FROM accident 
    WHERE severity = ANY (' || quote_literal(severity) || ') 
    AND local_auth = ANY (' || quote_literal(local_authorities) ||'))) 
    TO ' || quote_literal(file_path || file_name_c) || ' CSV'; 
END IF; 
関連する問題