sql >> Database teknologi >  >> RDS >> Oracle

Hvorfor understøttes valg fra lagret procedure ikke i relationelle databaser?

TL;DR :du kan vælg fra (tabel-værdi) funktioner, eller fra enhver form for funktion i PostgreSQL. Men ikke fra lagrede procedurer.

Her er en "intuitiv", noget databaseagnostisk forklaring, for jeg mener, at SQL og dets mange dialekter er for meget et organisk dyrket sprog/begreb til, at der kan være en grundlæggende, "videnskabelig" forklaring på dette.

Procedurer vs. funktioner, historisk

Jeg kan ikke rigtig se meningen med at vælge fra lagrede procedurer, men jeg er forudindtaget af mange års erfaring og accepterer status quo, og jeg kan bestemt se, hvordan skelnen mellem procedurer og funktioner kan være forvirrende, og hvordan man ville ønske, at de var mere alsidige og kraftfulde. Specifikt i SQL Server, Sybase eller MySQL kan procedurer returnere et vilkårligt antal resultatsæt/opdateringsantal, selvom dette ikke er det samme som en funktion, der returnerer en veldefineret type.

Tænk på procedurer som imperative rutiner (med bivirkninger) og fungerer som rene rutiner uden bivirkninger. En SELECT selve erklæringen er også "ren" uden bivirkninger (bortset fra potentielle låseeffekter), så det giver mening at tænke på funktioner som de eneste typer rutiner, der kan bruges i en SELECT erklæring.

Tænk faktisk på funktioner som værende rutiner med stærke begrænsninger på adfærd, hvorimod procedurer tillades at udføre vilkårlige programmer.

4GL vs. 3GL sprog

En anden måde at se dette på er fra perspektivet, at SQL er et 4. generations programmeringssprog (4GL) . En 4GL kan kun fungere rimeligt, hvis den er stærkt begrænset i, hvad den kan. Almindelige tabeludtryk gjort SQL turing-komplet , ja, men den deklarative karakter af SQL forhindrer stadig, at det er et sprog til generelle formål fra et praktisk, dagligdags perspektiv.

Lagrede procedurer er en måde at omgå denne begrænsning på. Nogle gange vil du at være turing komplet og praktisk. Så lagrede procedurer tyer til at være tvingende, have bivirkninger, være transaktionelle osv.

Lagrede funktioner er en smart måde at introducere nogle på 3GL / proceduremæssige sprogfunktioner ind i den renere 4GL-verden til prisen for at forbyde bivirkninger inde i dem (medmindre du vil åbne pandoras æske og have fuldstændig uforudsigelig SELECT udsagn).

Det faktum, at nogle databaser tillader, at deres lagrede procedurer returnerer vilkårlige antal resultatsæt/markører, er et træk ved, at de tillader vilkårlig adfærd, inklusive bivirkninger. I princippet ville intet, jeg sagde, forhindre denne særlige adfærd også i lagrede funktioner, men det ville være meget upraktisk og svært at administrere, hvis de fik lov til at gøre det inden for konteksten af ​​SQL, 4GL-sproget.

Således:

  • Procedurer kan kalde procedurer, enhver funktion og SQL
  • "Rene" funktioner kan kalde "rene" funktioner og SQL
  • SQL kan kalde "rene" funktioner og SQL

Men:

  • "Rene" funktioner kalder procedurer bliver "urene" funktioner (som procedurer)

Og:

  • SQL kan ikke kalde procedurer
  • SQL kan ikke kalde "urene" funktioner

Eksempler på "rene" tabelværdierede funktioner:

Her er nogle eksempler på brug af tabelværdier, "rene" 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;
/

Og så:

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

Og så

SELECT * FROM my_function(1, 2)

PostgreSQL

Lad mig få et ord om PostgreSQL.

PostgreSQL er fantastisk og dermed en undtagelse. Det er også mærkeligt, og sandsynligvis bør 50% af dets funktioner ikke bruges i produktionen. Det understøtter kun "funktioner", ikke "procedurer", men disse funktioner kan fungere som hvad som helst. Tjek følgende:

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;

Bivirkninger:

  • Der oprettes en tabel
  • En post er indsat

Alligevel:

SELECT * FROM wow();

Udbytte

wow
---
1


  1. InnoDB-ydelsesjusteringer

  2. Sådan øges intervaldatoen på Mysql

  3. Hvordan vælger man 200 poster for hver 'for loop' iteration i oracle?

  4. Context manager for Pythons MySQLdb