TL;DR :kamu bisa pilih dari fungsi (bernilai tabel), atau dari fungsi apa pun di PostgreSQL. Tapi tidak dari prosedur tersimpan.
Inilah penjelasan "intuitif", agak agnostik basis data, karena saya percaya bahwa SQL dan banyak dialeknya terlalu banyak merupakan bahasa/konsep yang tumbuh secara organik sehingga tidak ada penjelasan "ilmiah" yang mendasar untuk ini.
Prosedur vs. Fungsi, secara historis
Saya tidak benar-benar melihat gunanya memilih dari prosedur tersimpan, tetapi saya bias oleh pengalaman bertahun-tahun dan menerima status quo, dan saya tentu melihat bagaimana perbedaan antara prosedur dan fungsi dapat membingungkan dan bagaimana orang ingin mereka menjadi lebih fleksibel dan kuat. Khususnya di SQL Server, Sybase atau MySQL, prosedur dapat mengembalikan jumlah set hasil / jumlah pembaruan yang berubah-ubah, meskipun ini tidak sama dengan fungsi yang mengembalikan tipe yang terdefinisi dengan baik.
Pikirkan prosedur sebagai rutinitas penting (dengan efek samping) dan berfungsi sebagai rutinitas murni tanpa efek samping. Sebuah SELECT
pernyataan itu sendiri juga "murni" tanpa efek samping (terlepas dari efek penguncian potensial), jadi masuk akal untuk menganggap fungsi sebagai satu-satunya jenis rutinitas yang dapat digunakan dalam SELECT
pernyataan.
Faktanya, anggap fungsi sebagai rutinitas dengan batasan kuat pada perilaku, sedangkan prosedur diizinkan untuk mengeksekusi program sewenang-wenang.
Bahasa 4GL vs. 3GL
Cara lain untuk melihat ini adalah dari perspektif SQL sebagai bahasa pemrograman generasi ke-4 (4GL) . Sebuah 4GL hanya dapat bekerja secara wajar jika sangat dibatasi dalam apa yang dapat dilakukannya. Ekspresi Tabel Umum membuat SQL turing-complete , ya, tetapi sifat deklaratif SQL masih mencegahnya menjadi bahasa tujuan umum dari perspektif praktis sehari-hari.
Prosedur tersimpan adalah cara untuk menghindari batasan ini. Terkadang, Anda ingin menjadi turing lengkap dan praktis. Jadi, prosedur tersimpan menjadi keharusan, memiliki efek samping, bersifat transaksional, dll.
Fungsi tersimpan adalah cara cerdas untuk memperkenalkan beberapa 3GL / fitur bahasa prosedural ke dunia 4GL yang lebih murni dengan harga melarang efek samping di dalamnya (kecuali jika Anda ingin membuka kotak pandora dan memiliki SELECT
yang sama sekali tidak terduga pernyataan).
Fakta bahwa beberapa basis data mengizinkan prosedur tersimpannya untuk mengembalikan jumlah set/kursor hasil yang berubah-ubah adalah ciri dari perilaku sewenang-wenang yang diizinkan, termasuk efek samping. Pada prinsipnya, tidak ada yang saya katakan akan mencegah perilaku khusus ini juga dalam fungsi yang tersimpan, tetapi akan sangat tidak praktis dan sulit untuk dikelola jika diizinkan untuk melakukannya dalam konteks SQL, bahasa 4GL.
Jadi:
- Prosedur dapat memanggil prosedur, fungsi apa pun, dan SQL
- Fungsi "Murni" dapat memanggil fungsi "murni" dan SQL
- SQL dapat memanggil fungsi "murni" dan SQL
Tapi:
- Fungsi "murni" memanggil prosedur menjadi fungsi "tidak murni" (seperti prosedur)
Dan:
- SQL tidak dapat memanggil prosedur
- SQL tidak dapat memanggil fungsi "tidak murni"
Contoh fungsi bernilai tabel "murni":
Berikut adalah beberapa contoh penggunaan fungsi "murni" bernilai tabel:
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;
/
Dan kemudian:
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
Dan kemudian
SELECT * FROM my_function(1, 2)
PostgreSQL
Biarkan saya berbicara tentang PostgreSQL.
PostgreSQL luar biasa dan karenanya merupakan pengecualian. Ini juga aneh dan mungkin 50% fiturnya tidak boleh digunakan dalam produksi. Itu hanya mendukung "fungsi", bukan "prosedur", tetapi fungsi-fungsi itu dapat bertindak sebagai apa saja. Simak berikut ini:
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;
Efek samping:
- Sebuah tabel telah dibuat
- Sebuah catatan dimasukkan
Namun:
SELECT * FROM wow();
Hasil
wow
---
1