TL;DR :du kan välj från (tabellvärderade) funktioner, eller från någon form av funktion i PostgreSQL. Men inte från lagrade procedurer.
Här är en "intuitiv", något databasagnostisk förklaring, för jag tror att SQL och dess många dialekter är för mycket av ett organiskt odlat språk/begrepp för att det ska finnas en grundläggande, "vetenskaplig" förklaring till detta.
Procedurer kontra funktioner, historiskt
Jag ser inte riktigt poängen med att välja från lagrade procedurer, men jag är partisk av många års erfarenhet och accepterar status quo, och jag ser verkligen skillnaden mellan procedurer och funktioner kan vara förvirrande och hur man skulle önska att de skulle vara mer mångsidiga och kraftfulla. Specifikt i SQL Server, Sybase eller MySQL kan procedurer returnera ett godtyckligt antal resultatuppsättningar/uppdateringsantal, även om detta inte är detsamma som en funktion som returnerar en väldefinierad typ.
Se procedurer som obligatoriska rutiner (med biverkningar) och fungerar som rena rutiner utan biverkningar. En SELECT
uttalandet i sig är också "rent" utan biverkningar (förutom potentiella låsningseffekter), så det är vettigt att tänka på funktioner som de enda typerna av rutiner som kan användas i en SELECT
uttalande.
Tänk faktiskt på funktioner som rutiner med starka beteendebegränsningar, medan procedurer är tillåtna för att exekvera godtyckliga program.
4GL vs. 3GL-språk
Ett annat sätt att se på detta är ur perspektivet att SQL är ett 4:e generationens programmeringsspråk (4GL) . En 4GL kan bara fungera rimligt om den är kraftigt begränsad i vad den kan göra. Vanliga tabelluttryck som gjorts SQL turing-kompletta , ja, men SQLs deklarativa karaktär hindrar fortfarande att det är ett allmänt bruksspråk ur ett praktiskt vardagsperspektiv.
Lagrade procedurer är ett sätt att kringgå denna begränsning. Ibland vill du att vara turing komplett och praktisk. Så, lagrade procedurer tillgriper att vara absolut nödvändiga, ha biverkningar, vara transaktionella, etc.
Lagrade funktioner är ett smart sätt att introducera en del 3GL / procedurspråk presenterar den renare 4GL-världen till priset av att förbjuda biverkningar inuti dem (såvida du inte vill öppna pandoras låda och har helt oförutsägbar SELECT
uttalanden).
Det faktum att vissa databaser tillåter att deras lagrade procedurer returnerar godtyckliga antal resultatuppsättningar/markörer är ett drag av att de tillåter godtyckligt beteende, inklusive biverkningar. I princip skulle inget jag sa förhindra just detta beteende även i lagrade funktioner, men det skulle vara väldigt opraktiskt och svårt att hantera om de fick göra det inom ramen för SQL, 4GL-språket.
Alltså:
- Procedurer kan anropa procedurer, vilken funktion som helst och SQL
- "Rena" funktioner kan anropa "rena" funktioner och SQL
- SQL kan anropa "rena" funktioner och SQL
Men:
- Anropsprocedurer för "rena" funktioner blir "orena" funktioner (som procedurer)
Och:
- SQL kan inte anropa procedurer
- SQL kan inte anropa "orena" funktioner
Exempel på "rena" tabellvärdade funktioner:
Här är några exempel på användning av tabellvärdade, "rena" funktioner:
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;
/
Och sedan:
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
Och sedan
SELECT * FROM my_function(1, 2)
PostgreSQL
Låt mig säga ett ord om PostgreSQL.
PostgreSQL är fantastiskt och därmed ett undantag. Det är också konstigt och förmodligen bör 50% av dess funktioner inte användas i produktionen. Den stöder bara "funktioner", inte "procedurer", men dessa funktioner kan fungera som vad som helst. Kolla in följande:
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;
Biverkningar:
- En tabell skapas
- En post har infogats
Ändå:
SELECT * FROM wow();
Avkastning
wow
---
1