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

问题描述

:您 可以 从(表值)函数中选择,也 可以 从Postgresql中的任何类型的函数中选择。但不是来自存储过程。

这是一个“直观”的,有点与数据库无关的解释,因为我相信sql及其许多方言过于有机地增长了语言/概念,因此对此没有一个根本的“科学”解释。

历史上的程序与功能

我并没有真正从存储过程中进行选择的意义,但是我对多年的经验和接受现状抱有偏见,并且我当然知道 过程函数间的区别可能会造成混淆,以及人们希望他们如何做。更通用,更强大。特别是在sql Server,Sybase或MysqL中,过程可以返回任意数量的结果集/更新计数,尽管这与返回定义明确的类型的函数不同。

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

实际上,可以将函数视为对行为有严格约束的例程,而过程则可以执行任意程序。

4GL与3GL语言

sql的角度来看,这是另一种方法,它是第四代编程语言(4GL)。4GL仅在其功能上受到严格限制时才能合理地工作。通用表表达式使sql turing- complete成为可能,但是从实际的日常角度来看,sql的声明性仍然阻止其成为通用语言。

存储过程是规避此限制的一种方法。有时,您 完整 实用。因此,存储过程必须执行命令,具有副作用,进行事务处理等。

存储函数是将 某些 3GL /过程语言功能引入纯净4GL世界的一种聪明方法,其代价是禁止它们内部出现副作用(除非您想打开pandora的包装盒并拥有完全不可预测的SELECT陈述)。

一些数据库允许其存储过程返回任意数量的结果集/游标的事实是其允许任意行为(包括副作用)的一个特征。原则上,我说过的话也不会阻止存储函数中的这种特定行为,但是如果允许它们在4GL语言sql的上下文中这样做是非常不切实际且难以管理的。

因此:

但:

和:

“pure”表值函数的示例:

以下是一些使用表值“pure”函数的示例:

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

接着:

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很棒,因此是个例外。它也很奇怪,可能不应该在生产中使用其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

解决方法

众所周知,您无法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/zh-
cn/library/ms190312.aspx

....但是,出于安全原因,DBA往往不太愿意启用此功能。

因此,我的问题是:尽管允许加入存储过程或从存储过程中进行选择涉及一些明显的问题或性能方面的考虑,但是否有一些 根本的根本技术原因
导致RDBMS平台不支持此功能?

编辑:
从初始反馈中 可以得到 更多的澄清。是的,您 可以 从存储过程中返回结果集,是的,如果您想加入到(, 可以
使用(表值)函数而不是存储过程。或从结果集中选择-但是,这 存储过程的JoiningTo /
SelectingFrom不同。如果您在完全控制的数据库中工作,则可以选择使用TVF。但是,发现自己在第三方数据库中工作并被迫调用预先存在的存储过程是
非常
普遍的。或者,通常,您希望加入系统存储过程,例如:sp_execute_external_script(https://msdn.microsoft.com/zh-
CN/library/mt604368.aspx)。