众所周知,您无法在Oracle或SQL Server(可能是大多数其他主流RDBMS产品)中的存储过程中执行SELECT
。
一般来说,从存储过程中进行选择有几个明显的“问题”,只有两个是:
a)由存储过程产生的列是不确定的(直到运行时才知道)
b)由于存储过程的不确定性,因此在建立数据库统计信息和制定有效的查询计划时会出现问题
由于用户经常需要此功能,因此随着时间的推移,已开发出许多解决方法:
http://www.club-oracle.com/threads/select-from-stored-procedure-results.3147/
http://www.sommarskog.se/share_data.html
特别是SQL Server,它具有OPENROWSET
函数,可让您加入几乎所有内容或从中进行选择:https://msdn.microsoft.com/en-us/library/ms190312.aspx
....但是,出于安全原因,DBA往往不太愿意启用此功能。
因此,我的问题是:尽管允许加入存储过程或从存储过程中进行选择涉及一些明显的问题或性能方面的考虑,但是否有一些根本的根本技术原因导致RDBMS平台不支持此功能?
编辑:
初始反馈还需要更多说明。。是的,您可以从存储过程返回结果集,是的,如果要加入(或选择),可以使用(表值)函数而不是存储过程来自结果集-但是,这与JoiningTo/SelectingFrom存储过程不同。如果您在完全控制的数据库中工作,则可以选择使用TVF。但是,发现自己在第三方数据库中工作并被迫调用预先存在的存储过程是非常普遍的。或者,通常,您希望加入系统存储过程,例如:sp_execute_external_script(https://msdn.microsoft.com/en-us/library/mt604368.aspx)。
编辑2:
关于PostgreSQL是否可以做到这一点,答案是否定的:Can PostgreSQL perform a join between two SQL Server stored procedures?
最佳答案
TL; DR :可以从(表值)函数中选择,也可以从PostgreSQL中的任何函数中选择。但不是来自存储过程。
这是一个“直观”的,有点与数据库无关的解释,因为我认为SQL及其许多方言过于有机地增长了语言/概念,因此对此没有一个根本的“科学”解释。
历史上的程序与功能
我没有真正看到从存储过程中进行选择的要点,但是我因多年的经验和接受现状而有偏见,我当然也看到了过程和函数之间的区别如何造成混淆,以及人们希望他们如何做。更通用,更强大。特别是在SQL Server,Sybase或MySQL中,过程可以返回任意数量的结果集/更新计数,尽管这与返回定义明确的类型的函数不同。
将过程视为命令性例程(具有副作用),将功能视为无副作用的纯例程。 SELECT
语句本身也是“纯”的,没有副作用(除了潜在的锁定效果),因此将函数视为可以在SELECT
语句中使用的唯一例程类型是有道理的。
实际上,可以将函数视为对行为有严格约束的例程,而过程则可以执行任意程序。
4GL与3GL语言
从SQL的角度来看,这是另一种方法,它是4th generation programming language (4GL)。 4GL仅在其功能上受到严格限制时才能合理地工作。 Common Table Expressions made SQL turing-complete是的,但是从日常实用的角度来看,SQL的声明性仍然阻止其成为通用语言。
存储过程是规避此限制的一种方法。有时,您想完整而实用。因此,存储过程必须执行命令,具有副作用,进行事务处理等。
存储函数是将某些3GL/过程语言功能引入纯净4GL世界的一种聪明方法,其代价是禁止它们内部出现副作用(除非您想打开pandora的包装盒并拥有完全不可预测的SELECT
语句)。
一些数据库允许其存储过程返回任意数量的结果集/游标的事实是其允许任意行为(包括副作用)的一个特征。原则上,我说过的话也不会阻止存储函数中的这种特定行为,但是如果允许它们在4GL语言SQL的上下文中这样做将是非常不切实际且难以管理的。
因此:
但:
和:
“纯”表值函数的示例:
以下是一些使用表值“纯”函数的示例:
甲骨文
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;
/
然后:
SELECT * FROM TABLE (my_function(1, 2))
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
然后
SELECT * FROM my_function(1, 2)
PostgreSQL的
我想谈谈PostgreSQL。
PostgreSQL很棒,因此是个异常(exception)。它也很奇怪,可能不应该在生产中使用其50%的功能。它仅支持“功能”,不支持“过程”,但是那些功能可以充当任何东西。查看以下内容:
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;
副作用:
然而:
SELECT * FROM wow();
产量
wow
---
1
关于sql - 为什么在关系数据库中不支持从存储过程中进行选择?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33833265/