2017-05-09 4 views
1

Dies ist eine zweite Iteration auf eine Frage zuvor, fragte ich. Ich erstelle die folgende Funktion.PostgreSQL wählen in OUT Variablen

CREATE FUNCTION public.getpogstats(IN symbol character varying, IN pogtypeid integer, OUT closehi numeric, OUT closelo numeric, OUT dayhi numeric, OUT daylo numeric, OUT s7dhi numeric, OUT s7dlo numeric, OUT t13hi numeric, OUT t13lo numeric, OUT close numeric, OUT firstdate timestamp without time zone) 
    RETURNS record 
    LANGUAGE 'sql' 

AS $function$ 
SELECT ROUND(MAX(closeprice), 2), ROUND(MIN(closeprice), 2), ROUND(MAX(dayhigh), 2), ROUND(MIN(daylow), 2), ROUND(MAX(sevendaydp), 2), ROUND(MIN(sevendaydp), 2), 
    ROUND(MAX(thirteendaydp), 2), ROUND(MIN(thirteendaydp), 2), MIN(datadate) 
    INTO closehi, closelo, dayhi, daylo, s7dhi, s7dlo, t13hi, t13lo, firstdate 
FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
WHERE symbol.symbol = symbol; 

SELECT ROUND(closeprice, 2) INTO close FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid 
WHERE datadate = (SELECT MAX(datadate) 
        FROM pogdata JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
        WHERE symbol.symbol = symbol) 
AND symbol.symbol = symbol; 

$function$; 

ALTER FUNCTION public.getpogstats(character varying, integer) 
    OWNER TO postgres; 

Wenn ich ausführen um diese Funktion zu erstellen, erhalte ich die folgende Meldung:

ERROR: syntax error at or near "," 
LINE 8:  INTO closehi, closelo, dayhi, daylo, s7dhi, s7dlo, t13hi... 
         ^
********** Error ********** 

ERROR: syntax error at or near "," 
SQL state: 42601 
Character: 620 

Ich versuche, die Dokumentation zu PostgreSQL zu folgen, wo es heißt

... where target kann eine Datensatzvariable, eine Zeilenvariable oder eine durch Kommas getrennte Liste von einfachen Variablen und Datensatz-/Zeilenfeldern sein.

zählen die OUT-Parameter als "einfache Variablen"?

+1

'select ... in' kann nur mit PL/pgSQL verwendet werden, nicht SQL (auch - nicht verwandt - der Name der Sprache ist ein Bezeichner sollte nicht in einfache Anführungszeichen gesetzt werden, also' same sql' oder 'Sprache plpgsql') –

+0

Danke für die Rückmeldung. Ich habe die Sprache auf "plpgsql" geändert, aber jetzt ist der Fehler: Syntaxfehler bei oder in der Nähe von "SELECT". LINE 6: WÄHLEN SIE RUNDE (MAX (closeprice), 2), RUNDE (MIN (closeprice), 2), ... – KFayal

+1

Sie müssen auch den Rumpf der Funktion ändern, um den Syntaxregeln von PL/pgSQL zu entsprechen: https : //www.postgresql.org/docs/current/static/plpgsql.html –

Antwort

1

Die OUT Parameter sind Variablen, die Sie in einer SELECT ... INTO Anweisung verwenden können.

Sie sind jedoch SQL-Funktionen Mischen und PL/pgSQL-Funktionen.

Die Art und Weise Sie die Funktion erklärt (LANGUAGE 'sql') gelten die folgenden:

  • Es nur reguläre SQL-Anweisungen enthalten können (zum Beispiel keine SELECT ... INTO), und das Ergebnis der letzten Anweisung ist das Ergebnis der Funktionen (siehe the documentation).

  • Output parameters Geben Sie nur Namen für die Ergebnisspalten der letzten SELECT-Anweisung an.

Was Sie brauchen, ist ein PL/pgSQL-Funktion (LANGUAGE 'plpgsql').

Dann können Sie SELECT ... INTO verwenden, aber Sie müssen Ihren Code in PL/pgSQL Blöcke ordnen:

[DECLARE 
    <variable> <type>; 
    ...] 
BEGIN 
    <statement>; 
    ... 
[EXCEPTION 
    WHEN <exception> THEN 
     <statement>; 
     ... 
    ...] 
END; 
0

Ich hatte gerade die Sprache zu ändern und den BEGIN und END-Wrapper auf die folgende und alles klappte hinzufügen. Nun, es funktionierte bis zu dem Punkt, wo ich die Prozedur ausführen konnte. Danke für die Hilfe.

CREATE FUNCTION public.getpogstats(IN symbol character varying, IN pogtypeid integer, OUT closehi numeric, OUT closelo numeric, OUT dayhi numeric, OUT daylo numeric, OUT s7dhi numeric, OUT s7dlo numeric, OUT t13hi numeric, OUT t13lo numeric, OUT close numeric, OUT firstdate timestamp without time zone) 
    RETURNS record 
    LANGUAGE 'plpgsql' 

AS $function$ 
BEGIN 
SELECT ROUND(MAX(closeprice), 2), ROUND(MIN(closeprice), 2), ROUND(MAX(dayhigh), 2), ROUND(MIN(daylow), 2), ROUND(MAX(sevendaydp), 2), ROUND(MIN(sevendaydp), 2), 
    ROUND(MAX(thirteendaydp), 2), ROUND(MIN(thirteendaydp), 2), MIN(datadate) 
    INTO closehi, closelo, dayhi, daylo, s7dhi, s7dlo, t13hi, t13lo, firstdate 
FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
WHERE symbol.symbol = symbol; 

SELECT ROUND(closeprice, 2) INTO close FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid 
WHERE datadate = (SELECT MAX(datadate) 
        FROM pogdata JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
        WHERE symbol.symbol = symbol) 
AND symbol.symbol = symbol; 
END; 
$function$; 

ALTER FUNCTION public.getpogstats(character varying, integer) 
    OWNER TO postgres; 
+0

Eine andere Sache: Es wird dringend empfohlen, Parameter anders als Spalten in Ihren Abfragen zu benennen, um Namenskürzel zu vermeiden. Viele Menschen setzen einfach Parameternamen mit 'p_' voran. –

1

Sie, dass als SQL-Funktion halten können, wenn Sie wollen. SQL-Funktionen können mehrere Zeilen durch Ausführen mehrerer SELECT-Abfragen zurückgeben, aber sie können nur mehrere Spalten aus derselben Abfrage zurückgeben. Um also eine SQL-Funktion zu erhalten, müssen Sie eine einzelne Abfrage verwenden, die alle Spalten zurückgibt. Dies könnte mit einem gemeinsamen Tabellenausdruck erreicht werden:

CREATE FUNCTION public.getpogstats(IN p_symbol character varying, IN p_pogtypeid integer, OUT closehi numeric, OUT closelo numeric, OUT dayhi numeric, OUT daylo numeric, OUT s7dhi numeric, OUT s7dlo numeric, OUT t13hi numeric, OUT t13lo numeric, OUT close numeric, OUT firstdate timestamp without time zone) 
    RETURNS record 
    LANGUAGE sql 
AS $function$ 
    with data1 as (
    SELECT ROUND(MAX(closeprice), 2) as closehi, 
      ROUND(MIN(closeprice), 2) as closelo, 
      ROUND(MAX(dayhigh), 2) as dayhi, 
      ROUND(MIN(daylow), 2) as daylo, 
      ROUND(MAX(sevendaydp), 2) as s7dhi, 
      ROUND(MIN(sevendaydp), 2) as s7dlo, 
      ROUND(MAX(thirteendaydp), 2) as t13hi, 
      ROUND(MIN(thirteendaydp), 2) as t13lo, 
      MIN(datadate) as firstdate 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
    WHERE symbol.symbol = p_symbol 
), data2 as (
    SELECT ROUND(closeprice, 2) as close 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid 
    WHERE datadate = (SELECT MAX(datadate) 
         FROM pogdata 
         JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
         WHERE symbol.symbol = p_symbol) 
    AND symbol.symbol = p_symbol 
    LIMIT 1 -- just to be sure 
) 
    select d1.closehi, d1.closelo, d1.dayhi, d1.daylo, d1.s7dhi, d1.s7dlo, d1.t13hi, d1.t13lo, d2.close, d1.firstdate 
    from data1 as d1 
    cross join data2 as d2; 

$function$; 

(ich habe den Eindruck, die beiden Abfragen in einem kombiniert werden können, aber im Moment kann ich nicht einen Weg finden zu tun)


Beachten Sie, dass Sie, wenn Sie ein Ergebnis mit mehreren Spalten haben möchten (anstatt einer Spalte mit mehreren Feldern), diese explizit erweitern müssen.

folgende Auswahlmöglichkeiten:

select getpogstats('foo', 1); 

wird eine einzelne Zeile mit einer einzigen Spalte enthält mehrere Felder zurückkehren, so etwas wie:

getpogstats 
----------- 
(1,2,3,4,5,6,7,8,9,"2017-05-09 18:19:20") 

, weil die Funktion als "RETURNS record" deklariert wird.

Wenn Sie jedoch das Ergebnis als einzelne Spalten wollen, müssen Sie verwenden:

select (getpogstats('foo', 1)).*; 

Dann werden Sie jede Spalte separat erhalten:

closehi | closelo | dayhi | ... 
--------+---------+-------+---- 
     1 |  2 |  3 | ... 

Typischerweise Funktionen Rückkehr Mehr als eine Spalte ist einfacher zu handhaben, wenn Sie sie als returns table (...):

CREATE FUNCTION public.getpogstats(p_symbol character varying, p_pogtypeid integer) 
    returns table(closehi numeric, closelo numeric, dayhi numeric, daylo numeric, s7dhi numeric, s7dlo numeric, t13hi numeric, t13lo numeric, close numeric, firstdate timestamp without time zone) 
    LANGUAGE sql 
AS $function$ 
    with data1 as (
    SELECT ROUND(MAX(closeprice), 2) as closehi, 
      ROUND(MIN(closeprice), 2) as closelo, 
      ROUND(MAX(dayhigh), 2) as dayhi, 
      ROUND(MIN(daylow), 2) as daylo, 
      ROUND(MAX(sevendaydp), 2) as s7dhi, 
      ROUND(MIN(sevendaydp), 2) as s7dlo, 
      ROUND(MAX(thirteendaydp), 2) as t13hi, 
      ROUND(MIN(thirteendaydp), 2) as t13lo, 
      MIN(datadate) as firstdate 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
    WHERE symbol.symbol = p_symbol 
), data2 as (
    SELECT ROUND(closeprice, 2) as close 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid 
    WHERE datadate = (SELECT MAX(datadate) 
         FROM pogdata 
         JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
         WHERE symbol.symbol = p_symbol) 
    AND symbol.symbol = p_symbol 
    LIMIT 1 -- just to be sure 
) 
    select d1.closehi, d1.closelo, d1.dayhi, d1.daylo, d1.s7dhi, d1.s7dlo, d1.t13hi, d1.t13lo, d2.close, d1.firstdate 
    from data1 as d1 
    cross join data2 as d2; 

$function$; 
deklarieren

Dann können Sie verwenden:

select * 
from getpogstats('foo', 1); 

und das Ergebnis wird eine Struktur „wie Tisch“ automatisch haben.

Verwandte Themen