为什么从关系数据库中不支持存储过程中进行选择?

tbo*_*one 9 sql database sql-server oracle stored-procedures

众所周知,您无法SELECT在Oracle或SQL Server(可能是大多数其他主流RDBMS产品)中执行存储过程.

一般来说,从存储过程中选择有几个明显的"问题",只有两个想到:

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是否可以做到这一点的问题,答案也是否定的: PostgreSQL可以在两个SQL Server存储过程之间执行连接吗?

Luk*_*der 16

TL; DR:您可以从(表值)函数中选择,也可以从PostgreSQL中的任何函数中选择.但不是来自存储过程.

这是一个"直观的",有点数据库无关的解释,因为我认为SQL及其许多方言对于有机成长的语言/概念来说太过分了,因此对此有一个基本的,"科学的"解释.

历史上的程序与功能

我并没有真正看到从存储过程中选择的重点,但我有多年的经验和接受现状的偏见,我当然看到程序功能之间的区别如何令人困惑以及人们希望他们如何更多才多艺,更强大.特别是在SQL Server,Sybase或MySQL中,过程可以返回任意数量的结果集/更新计数,尽管这与返回定义良好的类型的函数不同.

将程序视为必要的例程(具有副作用),将函数视为没有副作用的纯例程.一个SELECT说法本身也是"纯"无副作用(除了潜在的锁定效应),因此是很有意义想到的功能作为唯一类型的例程,可以被用在SELECT声明.

实际上,将函数视为对行为具有强约束的例程,而允许过程执行任意程序.

4GL与3GL语言

另一种看待这种情况的方法是从SQL角度看第四代编程语言(4GL).4GL只有在它可以做的事情受到严重限制时才能合理地工作.公用表表达式使得SQL turing-complete,是的,但SQL的声明性本质仍然阻止它从实用的日常角度来看是一种通用语言.

存储过程是规避此限制的一种方法.有时,你想要完整实用.因此,存储过程必须采取必要措施,具有副作用,具有交易性等.

存储函数是一种聪明的方式,可以将一些 3GL /过程语言特性引入到更纯净的4GL世界中,代价是禁止它们内部的副作用(除非你想打开潘多拉的盒子并且有完全不可预测的SELECT语句).

某些数据库允许其存储过程返回任意数量的结果集/游标的事实是它们允许任意行为(包括副作用)的特征.原则上,我所说的任何内容都不会在存储的函数中阻止这种特殊行为,但如果允许它们在SQL(4GL语言)的上下文中这样做,那将是非常不实用和难以管理的.

从而:

  • 程序可以调用程序,任何函数和SQL
  • "Pure"函数可以调用"纯"函数和SQL
  • SQL可以调用"纯"函数和SQL

但:

  • 调用程序的"纯"函数变成"不纯"函数(如程序)

和:

  • SQL无法调用程序
  • 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;
/
Run Code Online (Sandbox Code Playgroud)

然后:

SELECT * FROM TABLE (my_function(1, 2))
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

然后

SELECT * FROM my_function(1, 2)
Run Code Online (Sandbox Code Playgroud)

PostgreSQL的

让我谈谈PostgreSQL.

PostgreSQL非常棒,因此也是一个例外.它也很奇怪,其中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;
Run Code Online (Sandbox Code Playgroud)

副作用:

  • 创建一个表
  • 插入记录

然而:

SELECT * FROM wow();
Run Code Online (Sandbox Code Playgroud)

产量

wow
---
1
Run Code Online (Sandbox Code Playgroud)

  • 对于它的价值,那就是从表值函数中进行选择,而不是从存储过程本身中严格选择. (2认同)