2016-07-13 6 views
1

Ich möchte programmgesteuert eine SQL in Postgres ausführen, ohne eine Funktion zu erstellen.Wie Sie plpgsql ausführen, ohne eine Funktion zu erstellen?

Grund: um sicherzustellen, dass meine plpgsql funktioniert im Voraus UND "zu analysieren" die Abfrage vor der Übergabe an eine Funktion.

Ich bin neu in Postgres und ich dachte, das wäre einfach. Ich konnte kein Beispiel finden. Vielleicht ist es nicht möglich? Wie kann der folgende Code funktionieren?

DO 
$body$ 
DECLARE 
    v_name_short VARCHAR; 
BEGIN 

v_name_short := 'test Account 1'; 

    RETURN QUERY 
     SELECT 
      a.name_short, 
      a.name_long 
     FROM enterprise.account a 
     WHERE 
      CASE WHEN v_name_short IS NOT NULL THEN 
       LOWER(a.name_short) = LOWER(v_name_short) 
      ELSE 
       1 = 1 
      END; 
END; 
$body$ 
LANGUAGE 'plpgsql'; 

Auch hier ist das Ziel hier meine SQL testet, wie in diesem Fall habe ich sicher noch meine CASE Aussage machen will, um einen Index mit I erstellt (LOWER (name_short)). Wie auch immer, ich bekomme diese Fehlermeldung:

ERROR: cannot use RETURN QUERY in a non-SETOF function

Ist das, was ich bin gefragt möglich in Postgres? Wenn nicht, gibt es eine Möglichkeit, Pläne in einer Funktion zu analysieren?

+0

Warum verwenden Sie einen 'do' Block ein' explain' zu laufen? Warum kannst du nicht einfach 'explain select ... 'ausführen? –

Antwort

2

Ein anonymer Codeblock kehrt leer. Sie können jedoch einen Trick mit einer temporären Tabelle verwenden, z.

CREATE TEMP TABLE IF NOT EXISTS trace (name_short text, name_long text); 

DO 
$body$ 
DECLARE 
    v_name_short VARCHAR; 
BEGIN 

    v_name_short := 'test Account 1'; 

    INSERT INTO trace 
     SELECT 
      a.name_short, 
      a.name_long 
     FROM enterprise.account a 
     WHERE 
      CASE WHEN v_name_short IS NOT NULL THEN 
       LOWER(a.name_short) = LOWER(v_name_short) 
      ELSE 
       1 = 1 
      END; 
END; 
$body$ 
LANGUAGE 'plpgsql'; 

SELECT * FROM trace; 
-- DROP TABLE trace; 

Mit EXPLAIN ANALYSE können Sie nur eine einzige Ebene SQL-Abfrage, keine Funktion ist, ein do-Block noch ein Skript analysieren. So können Sie versuchen:

EXPLAIN ANALYSE 
    SELECT 
     a.name_short, 
     a.name_long 
    FROM enterprise.account a 
    WHERE 
     CASE WHEN 'test Account 1' IS NOT NULL THEN 
      LOWER(a.name_short) = LOWER('test Account 1') 
     ELSE 
      1 = 1 
     END; 

Beachten Sie, dass in diesem Fall, dass Sie die Variable nicht verwenden können beacuse es nicht durch den Planer erkannt werden, anstatt die wörtliche verwenden.

+0

Klin, danke für deine Antwort. Ich bin nur überrascht, dass ich das in Postgres nicht sauber führen kann. Obwohl Ihre Lösung ausgeführt wird, kann ich von pgAdmin aus keine "explain analyze" ausführen, da sie direkt in der CREATE-Anweisung bombardiert wird (die nicht analysiert werden kann). Ich denke, ich muss einen Weg finden, um einen Abfrageplan innerhalb einer Funktion zu analysieren ... – arnold

+1

Sie können nur eine einzige einfache SQL-Abfrage analysieren, keine Funktion, einen Do-Block oder ein Skript. Versuchen Sie 'explain analyze select ...', aber Sie können die Variable nicht verwenden. Setze stattdessen das wörtliche "test Account 1" ein. – klin

+0

Klin, ein Gefallen: Würde es Ihnen etwas ausmachen, Ihre Antwort mit dem gerade geposteten Kommentar zu aktualisieren? Dann wird die Antwort vervollständigt und ich kann es als akzeptiert markieren. Nochmals vielen Dank für Ihre Hilfe! – arnold

0

A do anonymer Code-Block gibt immer void:

The code block is treated as though it were the body of a function with no parameters, returning void

Zur Ausführung von Abfragen in einer do Block Verwendung perform

do $$ 
    begin 
    perform * from t; 
    end 
$$; 

https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT

+0

Danke, aber gibt es eine Möglichkeit, den obigen Code mit einer alternativen Syntax auszuführen? – arnold

+0

@arnold Aktualisiert –

+0

Wir sind einen Schritt näher, aber jetzt bekomme ich das: "Abfrage erfolgreich zurückgegeben ohne Ergebnis in 28 ms". Nun, es gibt ein Ergebnis ... aber wie du sagtest, "DO" kommt immer leer zurück. Gibt es eine Möglichkeit, die Abfrage ohne DO auszuführen? Danke nochmal für deine Hilfe! – arnold

1

eine dritte (undokumentiert) ist Option zwischen einer normalen PL/pgSQL-Funktion und einer DO Anweisung: a temporäre Funktion:

Und du eigentlich kann detaillierte Abfragepläne für jedes SQL erhalten Anweisung innerhalb plpgsql funktioniert mit dem zusätzlichen Modul auto-explain. Details:

Aber Sie werden Ihre Funktion mit Werten für jeden Zweig in Ihrem CASE Ausdruck sicherzustellen, dass alles abdecken, um zu testen. Postgres führt nur oberflächliche Syntaxprüfungen unter CREATE FUNCTION durch.

Prepared statements kann eine andere Option sein, mit zu arbeiten. PL/pgSQL behandelt SQL-Anweisungen wie vorbereitete Anweisungen intern:

Verwandte Themen