Das Kern Missverständnis: eine record
Variable enthält eine einzelne Zeile (oder ist NULL), keine Tabelle (0-n-Zeilen eines bekannten Typs). Es gibt keine "Tabellenvariablen" in Postgres oder PL/pgSQL. Je nach Aufgabenstellung gibt es verschiedene Alternativen:
Dementsprechend können Sie nicht mehrere Zeilen zu einem record
Typ Variablen zuweisen. In dieser Erklärung:
EXECUTE format('SELECT id, tags FROM %s', _tbl) INTO t;
... Postgres ordnet nur die erste Zeile und verwirft den Rest. Da "der erste" in Ihrer Abfrage nicht gut definiert ist, erhalten Sie eine willkürliche Auswahl. Offensichtlich aufgrund des eingangs erwähnten Missverständnisses. Eine record
Variable kann auch nicht anstelle von Tabellen in SQL-Abfragen verwendet werden. Das ist die Hauptursache für den Fehler, den Sie erhalten:
Beziehung „t“ existiert nicht
Es sollte nun klar sein, dass count(*)
keinen Sinn zu beginnen machen würde, da t
ist nur ein einziger Datensatz/Reihe - abgesehen davon, dass es sowieso unmöglich ist.
Schließlich (auch wenn der Rest funktionieren würde), scheint der Rückgabetyp falsch zu sein:
(t TEXT[], e TEXT[])
. Da Sie id, tags
in t
auswählen, möchten Sie etwas wie (id int, e TEXT[])
zurückgeben.
Was Sie versuchen, zu tun würde dieses wie arbeiten:
CREATE OR REPLACE FUNCTION func(_tbl regclass)
RETURNS TABLE (id int, e text[]) AS
$func$
DECLARE
_ct int;
BEGIN
EXECUTE format(
'CREATE TEMP TABLE tmp ON COMMIT DROP AS
SELECT id, tags FROM %s'
, _tbl);
GET DIAGNOSTICS _ct = ROW_COUNT; -- cheaper than another count(*)
-- ANALYZE tmp; -- if you are going to run multiple queries
RAISE NOTICE '% results', _ct;
RETURN QUERY TABLE tmp;
END
$func$ LANGUAGE plpgsql;
Anruf (beachten Sie die Syntax!):
SELECT * FROM func('test');
Verwandte:
nur ein Proof of Concept. Während Sie die gesamte Tabelle auswählen, verwenden Sie stattdessen nur die zugrunde liegende Tabelle. In Wirklichkeit werden Sie einige WHERE
Klausel in der Abfrage haben ...
Sorgfältige des Ungleichgewichts Lauern Typ, count()
kehrt bigint
, Sie konnte sie nicht zuordnen zu einer integer
Variable. Brauche eine Besetzung: count(*)::int
.
Aber ich ersetzt, dass vollständig, es ist billiger, dieses Recht nach EXECUTE
auszuführen:
GET DIAGNOSTICS _ct = ROW_COUNT;
Details in the manual.
Warum ANALYZE
?
Abgesehen: CTEs im Klar SQL kann oft die Arbeit machen:
Danke so viel, Erwin, für Art und detaillierte Antwort. Jetzt ist der Grund für mich sehr klar. Ich werde CTE für den Zweck verwenden. –