2017-12-07 4 views
0

사용자 입력을 기반으로 3 개의 테이블에서 데이터를 준비하고 COPY TO을 사용하여 데이터를 내 보내야하는 plpgsql 함수가 있습니다. 데이터는 도로 교통 사고이므로 3 테이블은 accident, casualtyvehicle이며 각 사고는 세 테이블 모두에있는 accidentid 열을 통해 차량 및 사상자 테이블의 0 개 이상의 레코드에 연결됩니다. severitylocal_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 년대를 사용하는 가장 효율적인 방법을 찾고 있어요.

-- 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 블록을 사용할 수있을 거라고 생각 예

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 개 테이블에서 관련 데이터를 얻을 수 있습니다 당신은, 당신은 문자열이 0에 의해 실행되는

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

어느 전체 쿼리와 같은 동적 쿼리를 필요로 문자열 변수에 저장되는 쿼리 (부분)을 실행하려면이거나 전체 쿼리가 정적 SQL입니다. 그것들을 혼합 할 수는 없습니다.

CTE가 필요합니까? 조인으로 조회를 표현할 수있는 경우, 옵티마이 저는 더 많은 옵션을 갖습니다. 이것은 내가 CTE없이해야 할 일을하지하지만 난 accident 테이블에 동일한 쿼리를 수행하는 데 3 시간이 있기 때문에 나는 이것을 해결이되는 가장 효율적인 방법을 볼 수 없습니다

+0

을 문자열로 전체 쿼리가 의미가, 나는 그 문제가 될 수 있다고 생각했다. 3 개의 별도의 내보내기 파일이 필요하기 때문에 조인을 통해이 작업을 수행 할 수 있다고 생각하지 마십시오. 그렇지 않은 경우이 – Alex

+0

의 반대쪽에서 전체 가져 오기 루틴을 다시 작성해야합니다. 실제로 위의 제안은 ' 'copy' 문에 대한 파일 이름과 경로가 변수에 저장되어 있다면, 거의 중첩 된'execute'복사본이 필요할 것입니다. (select '최초의'execute' 문자열 내에서 모든 인용문이 실용적이지 않은 것처럼 보입니다 – Alex

+0

'COPY (WITH ... SELECT ...) TO ... '와 같은 것을 작성하는 데있어서의 문제점은 무엇입니까? –

0

: 가진

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;