TL;DR :możesz wybierz z funkcji (wartościami z tabeli) lub z dowolnej funkcji w PostgreSQL. Ale nie z procedur składowanych.
Oto „intuicyjne”, nieco niezależne od bazy danych wyjaśnienie, ponieważ uważam, że SQL i jego liczne dialekty są zbyt organicznie rozwiniętym językiem/koncepcją, aby można było to wyjaśnić jako fundamentalne, „naukowe”.
Procedury a funkcje, historycznie
Naprawdę nie widzę sensu wybierania spośród procedur składowanych, ale jestem uprzedzony przez lata doświadczenia i akceptuję status quo, i na pewno widzę, jak rozróżnia się procedury i funkcje może być mylące i jak chciałbyś, aby były bardziej wszechstronne i potężne. W szczególności w SQL Server, Sybase lub MySQL procedury mogą zwracać dowolną liczbę zestawów wyników/liczby aktualizacji, chociaż nie jest to to samo, co funkcja zwracająca dobrze zdefiniowany typ.
Pomyśl o procedurach jako koniecznych rutynach (ze skutkami ubocznymi) i działa jako czyste procedury bez skutków ubocznych. SELECT
samo stwierdzenie jest również "czysty" bez efektów ubocznych (oprócz potencjalnych efektów blokowania), więc sensowne jest myślenie o funkcjach jako o jedynym typie podprogramów, które mogą być użyte w SELECT
oświadczenie.
W rzeczywistości pomyśl o funkcjach jako o procedurach z silnymi ograniczeniami zachowania, podczas gdy procedury mogą wykonywać dowolne programy.
Języki 4GL kontra 3GL
Innym sposobem spojrzenia na to jest perspektywa SQL jako język programowania czwartej generacji (4GL) . 4GL może działać rozsądnie tylko wtedy, gdy jest mocno ograniczony w swoich możliwościach. Wspólne wyrażenia tabelowe uzupełnione o turystykę SQL , tak, ale deklaratywny charakter SQL nadal uniemożliwia jego bycie językiem ogólnego przeznaczenia z praktycznej, codziennej perspektywy.
Procedury składowane są sposobem na obejście tego ograniczenia. Czasami chcesz być kompletnym i praktyczny. Tak więc procedury składowane odwołują się do imperatywu, mają skutki uboczne, są transakcyjne itp.
Przechowywane funkcje to sprytny sposób na wprowadzenie niektórych Funkcje 3GL/języka proceduralnego do czystszego świata 4GL za cenę zakazywania efektów ubocznych wewnątrz nich (chyba że chcesz otworzyć puszkę pandory i mieć całkowicie nieprzewidywalne SELECT
oświadczenia).
Fakt, że niektóre bazy danych umożliwiają ich procedurom składowanym zwracanie dowolnej liczby zestawów wyników/kursorów, jest cechą dopuszczania przez nie dowolnych zachowań, w tym skutków ubocznych. W zasadzie nic, co powiedziałem, nie zapobiegłoby temu szczególnemu zachowaniu również w przechowywanych funkcjach, ale byłoby to bardzo niepraktyczne i trudne w zarządzaniu, gdyby pozwolono im to zrobić w kontekście SQL, języka 4GL.
Tak więc:
- Procedury mogą wywoływać procedury, dowolną funkcję i SQL
- „Czyste” funkcje mogą wywoływać „czyste” funkcje i SQL
- SQL może wywoływać „czyste” funkcje i SQL
Ale:
- „Czyste” funkcje wywołujące procedury stają się „nieczystymi” funkcjami (jak procedury)
Oraz:
- SQL nie może wywoływać procedur
- SQL nie może wywoływać „nieczystych” funkcji
Przykłady „czystych” funkcji z wartościami tabelarycznymi:
Oto kilka przykładów użycia „czystych” funkcji o wartościach tabelarycznych:
Wyrocznia
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;
/
A potem:
SELECT * FROM TABLE (my_function(1, 2))
Serwer SQL
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
A potem
SELECT * FROM my_function(1, 2)
PostgreSQL
Pozwól, że powiem coś na temat PostgreSQL.
PostgreSQL jest niesamowity i dlatego stanowi wyjątek. Jest to również dziwne i prawdopodobnie 50% jego funkcji nie powinno być wykorzystywane w produkcji. Obsługuje tylko „funkcje”, a nie „procedury”, ale te funkcje mogą działać jak cokolwiek. Sprawdź następujące:
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;
Skutki uboczne:
- Utworzono tabelę
- Wstawiono rekord
Jednak:
SELECT * FROM wow();
Plony
wow
---
1