sql >> Database teknologi >  >> RDS >> PostgreSQL

Vil du gemme almindelig forespørgsel som kolonne?

Er der en måde at gemme det undervalg som en pseudo-kolonne i tabellen?

En VIEW som er blevet anbefalet er en helt gyldig løsning. Gå til det.

Men der er en anden måde, der passer endnu tættere på dit spørgsmål. Du kan skrive en funktion, der tager tabeltypen som parameter for at emulere et "beregnet felt" eller "genereret kolonne" .

Overvej denne testcase, afledt af din beskrivelse:

CREATE TABLE tbl_a (a_id int, col1 int, col2 int);
INSERT INTO tbl_a VALUES (1,1,1), (2,2,2), (3,3,3), (4,4,4);

CREATE TABLE tbl_b (b_id int, a_id int, colx int);
INSERT INTO tbl_b VALUES
  (1,1,5),  (2,1,5),  (3,1,1)
, (4,2,8),  (5,2,8),  (6,2,6)
, (7,3,11), (8,3,11), (9,3,11);

Opret funktion, der emulerer col3 :

CREATE FUNCTION col3(tbl_a)
  RETURNS int8
  LANGUAGE sql STABLE AS
$func$
SELECT sum(colx)
FROM   tbl_b b
WHERE  b.a_id = $1.a_id
$func$;

Nu kan du forespørge:

SELECT a_id, col1, col2, tbl_a.col3
FROM   tbl_a;

Eller endda:

SELECT *, a.col3 FROM tbl_a a;

Bemærk, hvordan jeg skrev tbl_a.col3 / a.col3 , ikke kun col3 . Dette er væsentligt .

I modsætning til en "virtuel kolonne" i Oracle er den ikke inkluderet automatisk i en SELECT * FROM tbl_a . Du kan bruge en VIEW for det.

Hvorfor virker dette?

Den almindelige måde at referere til en tabelkolonne på er med attributnotation :

SELECT tbl_a.col1 FROM tbl_a;

Den almindelige måde at kalde en funktion på er med funktionel notation :

SELECT col3(tbl_a);

Generelt er det bedst at holde sig til disse kanoniske måder , som stemmer overens med SQL-standarden.

Men Postgres tillader også attributnotation. Disse virker også:

SELECT col1(tbl_a) FROM tbl_a;
SELECT tbl_a.col3;

Mere om det i manualen.
Du ved sikkert nu, hvor det går hen. Dette udseende ligesom du ville tilføje en ekstra kolonne i tabellen tbl_a mens col3() er faktisk en funktion, der tager den aktuelle række af tbl_a (eller dets alias) som rækketypeargument og beregner en værdi.

SELECT *, a.col3
FROM   tbl_a AS a;

Hvis der er en faktisk kolonne col3 det har prioritet, og systemet leder ikke efter en funktion af det navn, der tager rækken tbl_a som parameter.

"Skønheden" ved det:du kan tilføje eller slippe kolonner fra tbl_a og den sidste forespørgsel vil dynamisk returnere alle aktuelle kolonner, hvor en visning kun ville returnere sådanne kolonner, der eksisterede på oprettelsestidspunktet (tidlig binding vs. sen binding af * ).
Selvfølgelig skal du droppe den afhængige funktion, før du kan droppe bordet nu. Og du skal passe på ikke at ugyldiggøre funktionen, når du foretager ændringer i tabellen.

Jeg ville stadig ikke bruge det. Det er for overraskende for den uskyldige læser.



  1. Alternativ til mysql_real_escape_string uden at oprette forbindelse til DB

  2. Træk dage fra en dato i SQLite

  3. ROUND(dato) Funktion i Oracle

  4. Dataintegritet og præstationsovervejelser i MySQL semisynkron replikering