Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Warum wird die Auswahl aus gespeicherter Prozedur in relationalen Datenbanken nicht unterstützt?

TL;DR :Sie können Wählen Sie aus (Tabellenwert-)Funktionen oder aus jeder Art von Funktion in PostgreSQL aus. Aber nicht von gespeicherten Prozeduren.

Hier ist eine "intuitive", etwas Datenbank-agnostische Erklärung, denn ich glaube, dass SQL und seine vielen Dialekte zu sehr eine organisch gewachsene Sprache / ein organisch gewachsenes Konzept sind, als dass es dafür eine grundlegende, "wissenschaftliche" Erklärung geben könnte.

Prozeduren vs. Funktionen, historisch

Ich sehe nicht wirklich den Sinn darin, aus gespeicherten Prozeduren auszuwählen, aber ich bin durch jahrelange Erfahrung voreingenommen und akzeptiere den Status quo, und ich sehe auf jeden Fall, wie der Unterschied zwischen Prozeduren ist und Funktionen verwirrend sein können und wie man sich wünschen würde, dass sie vielseitiger und leistungsfähiger sind. Insbesondere in SQL Server, Sybase oder MySQL können Prozeduren eine beliebige Anzahl von Ergebnismengen / Aktualisierungszählern zurückgeben, obwohl dies nicht dasselbe ist wie eine Funktion, die einen wohldefinierten Typ zurückgibt.

Stellen Sie sich Prozeduren als zwingende Routinen vor (mit Nebenwirkungen) und von Funktionen als reine Routinen ohne Nebenwirkungen. Ein SELECT -Anweisung selbst ist auch "rein" ohne Nebenwirkungen (abgesehen von potenziellen Sperreffekten), daher ist es sinnvoll, sich Funktionen als die einzigen Arten von Routinen vorzustellen, die in einem SELECT verwendet werden können Aussage.

Stellen Sie sich Funktionen als Routinen mit starken Verhaltensbeschränkungen vor, während Prozeduren beliebige Programme ausführen dürfen.

4GL vs. 3GL-Sprachen

Man kann dies auch aus der Perspektive betrachten, dass SQL eine Programmiersprache der vierten Generation (4GL) ist. . Eine 4GL kann nur dann vernünftig arbeiten, wenn sie in ihren Möglichkeiten stark eingeschränkt ist. Allgemeine Tabellenausdrücke haben SQL turing-complete gemacht , ja, aber die deklarative Natur von SQL verhindert immer noch, dass es aus praktischer, alltäglicher Sicht eine Allzwecksprache ist.

Gespeicherte Prozeduren sind eine Möglichkeit, diese Einschränkung zu umgehen. Manchmal möchten Sie vollständig zu sein und praktisch. Gespeicherte Prozeduren greifen also darauf zurück, zwingend erforderlich zu sein, Nebenwirkungen zu haben, transaktional zu sein usw.

Gespeicherte Funktionen sind eine clevere Art, einige einzuführen 3GL / prozedurale Sprachfeatures in die reinere 4GL-Welt um den Preis, Nebenwirkungen in ihnen zu verbieten (es sei denn, Sie möchten die Büchse der Pandora öffnen und haben völlig unvorhersehbare SELECT Aussagen).

Die Tatsache, dass einige Datenbanken zulassen, dass ihre gespeicherten Prozeduren eine beliebige Anzahl von Ergebnismengen / Cursors zurückgeben, ist eine Eigenschaft ihres willkürlichen Verhaltens, einschließlich Nebenwirkungen. Im Prinzip würde nichts, was ich gesagt habe, dieses spezielle Verhalten auch in gespeicherten Funktionen verhindern, aber es wäre sehr unpraktisch und schwer zu handhaben, wenn sie dies im Kontext von SQL, der 4GL-Sprache, tun dürften.

Also:

  • Prozeduren können Prozeduren, beliebige Funktionen und SQL aufrufen
  • „Reine“ Funktionen können „reine“ Funktionen und SQL aufrufen
  • SQL kann "reine" Funktionen und SQL aufrufen

Aber:

  • „Reine“ Funktionen, die Prozeduren aufrufen, werden zu „unreinen“ Funktionen (wie Prozeduren)

Und:

  • SQL kann keine Prozeduren aufrufen
  • SQL kann keine "unreinen" Funktionen aufrufen

Beispiele für "reine" Tabellenwertfunktionen:

Hier sind einige Beispiele für die Verwendung von "reinen" Tabellenwertfunktionen:

Orakel

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;
/

Und dann:

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

Und dann

SELECT * FROM my_function(1, 2)

PostgreSQL

Lassen Sie mich etwas zu PostgreSQL sagen.

PostgreSQL ist genial und damit eine Ausnahme. Es ist auch seltsam und wahrscheinlich sollten 50 % seiner Funktionen nicht in der Produktion verwendet werden. Es unterstützt nur "Funktionen", keine "Prozeduren", aber diese Funktionen können als alles Mögliche fungieren. Sehen Sie sich Folgendes an:

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;

Nebenwirkungen:

  • Eine Tabelle wird erstellt
  • Ein Datensatz wird eingefügt

Dennoch:

SELECT * FROM wow();

Erträge

wow
---
1