TL;DR :u kunt selecteer uit (tabelwaarde) functies, of uit elke soort functie in PostgreSQL. Maar niet van opgeslagen procedures.
Hier is een "intuïtieve", enigszins database-agnostische verklaring, want ik geloof dat SQL en zijn vele dialecten te veel een organisch gegroeide taal / concept zijn om hier een fundamentele, "wetenschappelijke" verklaring voor te hebben.
Procedures versus functies, historisch gezien
Ik zie niet echt het nut in van het selecteren van opgeslagen procedures, maar ik ben bevooroordeeld door jarenlange ervaring en het accepteren van de status-quo, en ik zie zeker hoe het onderscheid tussen procedures en functies verwarrend kunnen zijn en hoe men zou willen dat ze veelzijdiger en krachtiger zouden zijn. Specifiek in SQL Server, Sybase of MySQL kunnen procedures een willekeurig aantal resultaatsets/updatetellingen retourneren, hoewel dit niet hetzelfde is als een functie die een goed gedefinieerd type retourneert.
Zie procedures als noodzakelijke routines (met bijwerkingen) en van functies als pure routines zonder bijwerkingen. Een SELECT
statement zelf is ook "puur" zonder bijwerkingen (afgezien van mogelijke vergrendelingseffecten), dus is het logisch om functies te beschouwen als de enige soorten routines die kunnen worden gebruikt in een SELECT
verklaring.
Beschouw functies in feite als routines met sterke gedragsbeperkingen, terwijl procedures willekeurige programma's mogen uitvoeren.
4GL versus 3GL-talen
Een andere manier om dit te bekijken is vanuit het perspectief van SQL als een 4e generatie programmeertaal (4GL) . Een 4GL kan alleen redelijk werken als het zwaar wordt beperkt in wat het kan doen. Gemeenschappelijke tabelexpressies maakten SQL turing-compleet , ja, maar het declaratieve karakter van SQL verhindert nog steeds dat het een taal voor algemene doeleinden is vanuit een praktisch, alledaags perspectief.
Opgeslagen procedures zijn een manier om deze beperking te omzeilen. Soms wil je om compleet te zijn en praktisch. Opgeslagen procedures zijn dus dwingend, hebben bijwerkingen, zijn transactioneel, enz.
Opgeslagen functies zijn een slimme manier om sommige . te introduceren 3GL / procedurele taalfuncties in de zuiverdere 4GL-wereld tegen de prijs van het verbieden van bijwerkingen erin (tenzij je de doos van Pandora wilt openen en volledig onvoorspelbare SELECT
hebt verklaringen).
Het feit dat sommige databases toestaan dat hun opgeslagen procedures een willekeurig aantal resultatensets / cursors retourneren, is een kenmerk van hun toestaan van willekeurig gedrag, inclusief bijwerkingen. In principe zou niets van wat ik zei dit specifieke gedrag ook in opgeslagen functies voorkomen, maar het zou erg onpraktisch en moeilijk te beheren zijn als ze dit zouden mogen doen binnen de context van SQL, de 4GL-taal.
Dus:
- Procedures kunnen procedures, elke functie en SQL aanroepen
- "Pure" functies kunnen "pure" functies en SQL aanroepen
- SQL kan "pure" functies en SQL aanroepen
Maar:
- "Pure" functies die procedures aanroepen, worden "onzuivere" functies (zoals procedures)
En:
- SQL kan geen procedures aanroepen
- SQL kan geen "onzuivere" functies aanroepen
Voorbeelden van "pure" tabelwaardefuncties:
Hier zijn enkele voorbeelden van het gebruik van tabelwaardige, "pure" functies:
Oracle
CREATE TYPE numbers AS TABLE OF number(10);
/
CREATE OR REPLACE FUNCTION my_function (a number, b number)
RETURN numbers
IS
BEGIN
return numbers(a, b);
END my_function;
/
En dan:
SELECT * FROM TABLE (my_function(1, 2))
SQL-server
CREATE FUNCTION my_function(@v1 INTEGER, @v2 INTEGER)
RETURNS @out_table TABLE (
column_value INTEGER
)
AS
BEGIN
INSERT @out_table
VALUES (@v1), (@v2)
RETURN
END
En dan
SELECT * FROM my_function(1, 2)
PostgreSQL
Ik wil iets zeggen over PostgreSQL.
PostgreSQL is geweldig en dus een uitzondering. Het is ook raar en waarschijnlijk zou 50% van de functies niet in productie moeten worden gebruikt. Het ondersteunt alleen "functies", niet "procedures", maar die functies kunnen als alles fungeren. Bekijk het volgende:
CREATE OR REPLACE FUNCTION wow ()
RETURNS SETOF INT
AS $$
BEGIN
CREATE TABLE boom (i INT);
RETURN QUERY
INSERT INTO boom VALUES (1)
RETURNING *;
END;
$$ LANGUAGE plpgsql;
Bijwerkingen:
- Er is een tabel gemaakt
- Er is een record ingevoegd
Toch:
SELECT * FROM wow();
Opbrengsten
wow
---
1