sql >> Databasteknik >  >> RDS >> Oracle

Varför stöds inte val från lagrad procedur i relationsdatabaser?

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


  1. MySQL Visa användare

  2. Underfråga med ogiltigt identifierarfel i sql

  3. Ta bort-knappen fungerar inte i CodeIgniter

  4. SQL Server Temp-tabell vs Tabellvariabel