Deklaration von Variablen

Hallo an alle,

ich möchte gern eine Deklaration von Variablen erreichen mit den ich dann “spielen” kann. Aus der Praxis kenne ich das auf MS-SQL Server dort kann ich Variablen deklarieren und mir diese auch wieder ausgeben lassen.
Geht das auch mit Postgresql?

Laut der Doku https://www.postgresql.org/docs/9.1/static/plpgsql-declarations.html

müsste ich eigentlich nur das machen

day int = 5;
year integer;
month integer;

Aber da wird schon bei der Namensvergebung gemeckert. Also hatte ich auch testweise einen Namen gewählt der nicht vorkommen könnte. War aber der gleiche Effekt. Dann schrieb ich Declare davor. Aber das scheint Funktionen vorbehalten zu sein.

Was mach ich falsch? Kann ich mir den Inhalt der Variablen auch wieder ausgeben lassen? gibt es so was wie print auch in Postgresql?

Variablen sind Dinge von Programmiersprachen, SQL selber hat keine. Du wirst also eine Funktion in z.B. pl/pgsql erstellen, dazu mußt du auch die passende Syntax einhalten, wie z.B. die Funktion definieren. Erst dann kannst Du innerhalb dieser Funktion mit Variablen spielen.

Ausgeben kannst Du Inhalte von Variablen z.B. via Raise.

Btw.: Du verweist auf Doku zur Version 9.1, diese ist mittlerweile nicht mehr supported.

Danke! Schade das dies so nicht geht wie bei MS.

Ich nutze gleich mal hier den Thread um eine weitere Frage loszuwerden.
Wie kann ich denn Abfragen in Funktionen mit Parametern beeinflussen?
Ziel ist es eine Funktion zu haben die 2 Parameter erhält und an einer Stelle (in dem Beispiel dem Zeitstempel) mit den 2 Parametern zu manipulieren.
Ich bin mal so an die Sache herangegangen klappt aber nicht. Auch finde ich stets nur Beispiele, wo leider nicht eine Zeichenkette so manipuliert wird, wie ich das gerne hätte.

CREATE OR REPLACE FUNCTION neu_para3( IN month_start int, IN year_start int)
	RETURNS SETOF"Zeiten" AS 
$BODY$

	SELECT "Wert","Timestamp_Messung","wert2","Wert3","Wert4","Zahl" FROM "Zeiten" 

	where "Timestamp_Messung" = $2 + '-' + $1 + '-03 08:59:28.966' 

$BODY$
	LANGUAGE sql VOLATILE;



[\Code]

Zuerstmal: der Operator um Strings zu verknüpfen ist || in SQL, nicht +

Du musst Jahr/Monat so umwandeln, dass das dann auch einen korrekten Timestamp ergibt, das kann man mit to_timestamp() machen:

CREATE OR REPLACE FUNCTION neu_para3( IN month_start int, IN year_start int)
	RETURNS SETOF "Zeiten" AS 
$BODY$

  SELECT "Wert","Timestamp_Messung","wert2","Wert3","Wert4","Zahl" 
  FROM "Zeiten" 
  where "Timestamp_Messung" = to_timestamp(to_char(year_start, '0000')||'-'||to_char(month_start, '00') || '-03 08:59:28.966', 'yyyy-mm-dd hh24:mi:ss.ms') 

$BODY$
	LANGUAGE sql VOLATILE;

Alternativ, etwas übersichtlicher mit make_timestamp():

CREATE OR REPLACE FUNCTION neu_para3( IN month_start int, IN year_start int)
	RETURNS SETOF "Zeiten" AS 
$BODY$

  SELECT "Wert","Timestamp_Messung","wert2","Wert3","Wert4","Zahl" 
  FROM "Zeiten" 
  where "Timestamp_Messung" = select make_timestamp(year_start, month_start, 3, 8, 59, 28.966);

$BODY$
	LANGUAGE sql VOLATILE;

Ausserdem: vermeide die unsäglichen doppelten Anführungszeichen. Man muss nicht nur wesentlich mehr tippen, sondern das führt langfristig immer wieder zu unschönen Problemen.

@castorp

in der nächsten Testdatenbank werde ich dies berücksichtigen.
Ich hätte da noch ein Frage. Wie kann man denn mehr Spalten zurückgeben als vorher vorhanden waren. Es soll mir also einfach noch ein weitere Spalte zurückgegeben werden obwohl diese “eigentlich” vorher nicht vorhanden waren. Es soll also einfach möglich alles zurück zu geben was der SQL auch zurückgeben würde.


CREATE OR REPLACE FUNCTION neu_para3( IN month_start int, IN year_start int)
	RETURNS SETOF"Zeiten" AS 
$BODY$

	SELECT "Wert","Timestamp_Messung","wert2","Wert3","Wert4","Zahl",to_char(year_start, '0000')||'-'||to_char(month_start, '00') || '-01 23:58'  FROM "Zeiten"

	  where "Timestamp_Messung" = to_timestamp(to_char(year_start, '0000')||'-'||to_char(month_start, '00') || '-03 08:59:28.966', 'yyyy-mm-dd hh24:mi:ss.ms') 

$BODY$
	LANGUAGE sql VOLATILE;

[\Code]

So weiter geht’s mit der Deklaration von Variablen.

Ich möchte gern folgende Abfrage parametrisieren:

SELECT date_part('year', t) as year, date_part('month', t) as month
FROM generate_series('2016-01-01'::timestamp, '2016-12-01'::timestamp, '1 month') as t;

Ihr ahnt es schon es sollen die Zeitpunkte manipuliert werden.

Dazu habe ich mir eine Abfrage überlegt

SELECT MIN(zeitstempel),MAX(zeitstempel) from test_db;

Wenn ich also die 2 Timestamps herausgefunden habe möchte ich diese in eine Variable übergeben.
In der Microsoft Welt kann ich dies während der Laufzeit der Funktion schön DECLARE(deklarieren) und SET (überladen) machen.
Kann mir jemand zeigen wie ich das bei Postgresql machen kann?

with vars as (
   SELECT MIN(zeitstempel) as min_zeit, MAX(zeitstempel) as max_zeit 
   from test_table
)
SELECT date_part('year', t) as year, date_part('month', t) as month
FROM generate_series(vars.min_zeit, vars.max_zeit, '1 month') as t, vars

Danke castorp! Jetzt ist mir die Sache mit With auch wieder geläufig. Hatte ich total verdrängt das man auch diesen Weg gehen kann.

Jedoch funktioniert das ganze nicht so recht.
Ich erhalte 2 Zeitstempel. Wenn ich diese in das Selekt eingebe funktioniert die Abfrage, aber als ganzes mit with leider nicht.

 SELECT date_part('year', t) as year, date_part('month', t) as month
FROM generate_series('2016-09-16 11:11:00+02'::timestamp, '2017-01-17 07:53:00+01'::timestamp, '1 month') as t;

Kannst du mir sagen wo mein Denkfehler liegt??

naja ganz einfach gesagt so wie du es vorgeschlagen hast g

with vars as (
   SELECT MIN(zeitstempel) as min_zeit, MAX(zeitstempel) as max_zeit 
   from test_table
)
SELECT date_part('year', t) as year, date_part('month', t) as month
FROM generate_series(vars.min_zeit, vars.max_zeit, '1 month') as t, vars

Die Fehlermeldung lautet dann:

FEHLER: fehlender Eintrag in FROM-Klausel für Tabelle »vars«
LINE 7: FROM generate_series(vars.min_zeit, vars.max_zeit, ‘1 month’… ^


********** Fehler **********

FEHLER: fehlender Eintrag in FROM-Klausel für Tabelle »vars«
SQL Status:42P01
Zeichen:229


Ach schau einer an, aktuell nutze ich die Version 9.2 es funktioniert unter 9.5 es scheint also an der Version zu liegen.

Ah sorry, da stimmt die Reihenfolge nicht:

with vars as (
   SELECT MIN(zeitstempel) as min_zeit, MAX(zeitstempel) as max_zeit 
   from test_table
)
SELECT date_part('year', t) as year, date_part('month', t) as month
FROM vars, 
     generate_series(vars.min_zeit, vars.max_zeit, '1 month') as t

Oh Sorry das war jetzt mein Fehler! Die Reihenfolge hatte ich dann schon abgeändert und nun erscheint diese Fehlermeldung

FEHLER: Funktionsausdruck in FROM kann nicht auf andere Relationen auf der selben Anfrageebene verweisen
LINE 7: generate_series(vars.min_zeit, vars.max_zeit, ‘1 month’…
^

********** Fehler **********

FEHLER: Funktionsausdruck in FROM kann nicht auf andere Relationen auf der selben Anfrageebene verweisen
SQL Status:42P10
Zeichen:217

Das meinte ich mit der Version 9.2 zu 9.5

Ach so.
Das ist richtig, die schon ziemlich veraltete 9.2 unterstützt keine lateral joins.

Da wird’s dann etwas unhandlicher:

with vars as (
   SELECT MIN(zeitstempel) as min_zeit, MAX(zeitstempel) as max_zeit 
   from test_table
)
SELECT date_part('year', t) as year, date_part('month', t) as month
FROM  generate_series((select min_zeit from vars), (select max_zeit from vars), '1 month') as t

9.2 würde ich heute bei einem neuen Projekt auf keinen Fall mehr einsetzen - die wird nur noch bis September diesen Jahres (2017) unterstützt: https://www.postgresql.org/support/versioning/

Bei einem bestehenden Projekt sollte man das Thema Migration nach 9.6 sehr schnell auf die Tagesordnung setzen.

Hallo castorp, ich würde jetzt gern noch einen drauf setzen und mir eine Funktion schreiben welche mit dem Wechsel der Tabellenbezeichnung klar kommt.
Anbei das SQL Statement. Leider kommt er nicht mit TEXT klar bei _SQL_cmd
Habe ich jetzt falsch deklariert? sollte doch so richtig sein?!

CREATE OR REPLACE  FUNCTION min_max_timestamp(IN _table TEXT)
	RETURNS TABLE ( 
			--year int, month int
			year double precision, month double precision
			) AS


$BODY$
DECLARE
	_sql_cmd  TEXT;

BEGIN
	_sql_cmd = 
	
'with vars as (
   SELECT MIN(zeitstempel) as min_zeit, MAX(zeitstempel) as max_zeit 
   from '||_table||';
   )
SELECT date_part('year', t) as year, date_part('month', t) as month
FROM  generate_series((select min_zeit from vars), (select max_zeit from vars), '1 month') as t;';

RETURN QUERY EXECUTE _sql_cmd;

    
END;
$BODY$ 

	LANGUAGE sql VOLATILE;

Fehlermeldung:
FEHLER: Syntaxfehler bei »TEXT«
LINE 10: _sql_cmd TEXT;
^


********** Fehler **********

FEHLER: Syntaxfehler bei »TEXT«

Verwende plpgsql statt sql als Language, Variablen gibt es so nicht in SQL.

oh das ist Fies! Da hätte ich nicht nachgeschaut!

Danke für deine Hilfe! Klappt jetzt wunderbar.