2017-03-23 2 views
0

Ich arbeite in PostgreSQL vergangenen Jahren, aber ich hatte keine Ahnung über Array-Konzept und wie Array in PostgreSQL zu behandeln. Ich brauche eine dynamische Abfrage für die Auswahl von Spalten in mehreren Tabellen und das Ergebnis wird im Cursor sein, Spaltennamen sollten sich dynamisch ändern.Umgehen String Array als Parameter und dynamische Abfrage in PostgreSQL

für zB (in mehreren Tabellen insgesamt 30 Spalten wird Wenn Benutzer col1 benötigen, COL5, Col6, col25), so select-Anweisung Abfrage dynamisch werden wird sich ändern, wie:

select col1, col5,col6,col25 from table .... 

ein anderer Benutzer benötigen col2 , COL5, COL7, col29, col26 wird SELECT-Anweisung dynamisch als

select col2,col5,col7,col29,col26 from table .... and so on. 

gespeicherten Prozedur übergeben Parameter Array wird

create or replace function func_my_method(check_in character varying, sel character varying[])... 
ändern

dieser sel [] enthält wie

  sel[0]:='col1_name' 
      sel[1]:='col5_name' 
      sel[2]:='col6_name' 
      sel[3]:='col25_name' 

so müssen wir zuerst aufgespalten werden die Array-Werte in separaten Variable und diese Variable in select-Anweisung angenommen werden wollen

'select'||col1, col5,col6,col25||'from......' 

schließlich sagen, Kurz muss ich ein Array in Parametern übergeben und muss eine Array-Werte trennen und es wird separate Variablen zuweisen. Diese Variable wird verwendet, um eine Anweisung dynamisch auszuwählen

+0

so erstellen Sie Ihre dynamische Anweisung. was machst du damit? .. zurück was? Satz von? Tabelle? Anzahl der Reihen? –

+0

@VaoTsun ich erstelle keine Aussage oder Verfahren für diese ich erwähnte nur zu Ihrer Referenz. Ich benötige eine Prozedur für dieses obige Kriterium und werde als Cursor zurückkehren. Bitte hilf mir diesbezüglich. –

+1

Also, Sie brauchen etwas wie ein ['Refcursor'] (https://www.postgresql.org/docs/current/static/plpgsql-cursors.html)? http://rexttester.com/FMCUW60860 - Vergessen Sie bitte nicht, Spaltennamen mit 'format()' oder 'quote_ident()' anzugeben, um die Möglichkeit der SQL-Injektion zu minimieren. – pozs

Antwort

1

Ein bare refcursor kann eine beliebige Anzahl von Spalten enthalten. Auch wenn Sie eine besondere Erklärung von ihm zu lesen brauchen werden: FETCH ...

CREATE OR REPLACE FUNCTION func_my_method(check_in text, sel text[], ref refcursor) 
    RETURNS refcursor 
    LANGUAGE plpgsql 
AS $func$ 
BEGIN 
    OPEN ref FOR EXECUTE 'SELECT ' || (SELECT string_agg(quote_ident(c), ', ') 
            FROM unnest(sel) c) || ' FROM ...'; 
    RETURN ref; 
END; 
$func$; 

SELECT func_my_method('check_in', ARRAY['col1', 'col2'], 'sample_name'); 
FETCH ALL IN sample_name; 

http://rextester.com/ZCZT84224

Hinweis: Sie könnte lassen Sie die refcursor Parameter & DECLARE in Ihrer Funktion Körper. Auf diese Weise generiert PostgreSQL einen (nicht konfliktbehafteten) Namen für den Refcursor, der beim Aufruf von SELECT func_my_method(...) zurückgegeben wird. Sie werden diesen Namen in der FETCH ...-Anweisung benötigen.

aktualisieren: Wenn Sie vollständig qualifizieren wollen (einige) Spalten (dh Schreibtabellenname & Spalte auch), müssen Sie entweder:

CREATE OR REPLACE FUNCTION func_my_method2(check_in text, sel text[], ref refcursor) 
    RETURNS refcursor 
    LANGUAGE plpgsql 
AS $func$ 
BEGIN 
    OPEN ref FOR EXECUTE 'SELECT ' || (SELECT string_agg((SELECT string_agg(quote_ident(c), '.') 
                 FROM unnest(string_to_array(fq, '.')) c), ', ') 
            FROM unnest(sel) fq) || ' FROM ...'; 
    RETURN ref; 
END; 
$func$; 

SELECT func_my_method2('check_in', ARRAY['col1', 'check_in.col2'], 'sample_name2'); 
FETCH ALL IN sample_name2; 

(dies den sel Parameter aufgeteilt werden in " Teile“die vollständig qualifizierten Namen auf . - haben aber einen Nachteil:

: die Tabelle & Spaltennamen nicht .)

Oder enthalten

CREATE OR REPLACE FUNCTION func_my_method3(check_in text, sel text[][], ref refcursor) 
    RETURNS refcursor 
    LANGUAGE plpgsql 
AS $func$ 
BEGIN 
    OPEN ref FOR EXECUTE 'SELECT ' || (SELECT string_agg((SELECT string_agg(quote_ident(sel[i][j]), '.') 
                 FROM generate_subscripts(sel, 2) j), ', ') 
            FROM generate_subscripts(sel, 1) i) || ' FROM ...'; 
    RETURN ref; 
END; 
$func$; 

SELECT func_my_method3('check_in', ARRAY[ARRAY['check_in', 'col1'], ARRAY['check_in', 'col2']], 'sample_name3'); 
FETCH ALL IN sample_name3; 

(aber das hat eine unangenehme Konsequenz: Da Arrays rechteckig sein müssen, müssen alle Spalten-Sub-Arrays die gleichen exakten Dimensionen haben; Daher müssen Sie den Tabellennamen für alle Spalten oder für keines von beiden angeben.)

http://rextester.com/JNI24740

+0

gerade fertig forkin Ihren Code http://rextester.com/IFNLM12119 –

+0

@dineshdanny ja, voll qualifizierte Namen können nicht direkt mit 'format()' oder 'quote_ident()' verwendet werden. Wenn Sie nur eine Tabelle auswählen möchten, lassen Sie sie einfach in den Parametern aus und verwenden Sie "SELECT mm_items". || (SELECT string_agg (quote_ident (c), ', mm_items.') ... '... – pozs

+0

@dineshdanny ... Wenn Sie mehrere Tabellen verwenden möchten, dann verwenden Sie entweder kein Zitat in Ihrer Funktion (aber dann * * Immer ** rufe diese Funktion von einer vertrauenswürdigen Quelle auf, vielleicht 'REVOKE' einige Privilegien, um das zu erreichen - oder du musst den' sel' Parameter parsen (zB Split auf '.')) – pozs

Verwandte Themen