当前位置: 首页 > 面试题库 >

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

养枫涟
2023-03-14
问题内容

众所周知,您无法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)。


问题答案:

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

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

历史上的程序与功能

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

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

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

4GL与3GL语言

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

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

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

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

因此:

  • 程序可以调用程序,任何函数和SQL
  • “pure”函数可以调用“pure”函数和SQL
  • SQL可以调用“pure”函数和SQL

但:

  • “纯”函数调用过程变为“impure”函数(如过程)

和:

  • SQL无法调用过程
  • SQL无法调用“impure”函数

“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


 类似资料:
  • 问题内容: 我想将分层的二维科学数据集存储在关系数据库(MySQL或SQLite)中。每个数据集都包含一个数值数据表,其中包含任意数量的列。另外,每个数据集可以具有一个或多个与其表的给定行关联的相同类型的子级。每个数据集通常具有1至100列和1至1.000.000行。数据库应该能够处理许多数据集(> 1000),并且数据的读/写应该相当快。 存储此类数据的最佳数据库模式将是什么?是否有一个“主”表

  • 问题内容: 因此,问题的根源在于将XML数据存储在关系数据库中是否合适?通常有没有更好的方法来实现相同的目标?哪些数据库引擎为XML数据类型(例如SQL Server)提供了良好的支持,以及围绕“ XML索引”的问题是什么? 问题答案: 数据库用于存储数据。XML是数据。因此,在适当的情况下,将XML存储在数据库中是完全有效的。这是否是最有效的方法,取决于许多可能无法概括的因素。 例如,如果您有一

  • 我在PostgreSQL中有一个存储过程,我想在表中进行插入。我从这个过程中得到了一些参数,并使用它们尝试在其他表上选择其他属性。 这是我的存储过程: 当我试图执行时,它抛出一个错误,说:“错误:列“customer_code”不存在”,“提示:表“sales_invoice_header”中有一个名为“customer_code”的列,但不能从查询的这一部分引用它。” 表客户是存在的,有一个名为

  • 所以我有表注释和作者。我想用许多可选参数构建复杂的搜索栏。我想用可选的作者名字/姓氏和一些标志来过滤评论,比如人气(基于评论评级)。 由于我不知道如何使用spring数据jpa存储库编写它,我一直在考虑使用@query注释将其编写为本机查询,像这样的smth应该可以工作 是否有使用Spring data jpa编写它的选项? 例如,将来我计划添加更多参数和分页。使用Spring就像使用sql查询1

  • 问题内容: 我有一个ac#实体框架应用程序。我正在尝试从代码运行存储过程(没有问题)。它长期运行,大约30分钟。随着过程的进行,我将每个事务的日志写入SQL表。我希望从该应用程序启动该过程,但随后在屏幕上显示登录的最后10条记录,可能每10秒重新查询一次。这将显示进度。 我更改了代码以简化。线程在dispatcherTime_Tick进程上阻塞。看起来存储过程很好。 这就是所谓的服务。 我一直在执

  • 问题内容: 编辑:虽然此问题中的某些答案可能会帮助其他人解决不同的问题,但该解决方案实际上与数据库连接上的自动提交功能中的某些错误有关! 执行查询后强制执行提交会使数据库反映更改,因此下面显示的代码是调用此类型存储过程的正确方法 我正在尝试在oracle数据库中调用一个简单的存储过程。 该过程如下所示: 我遇到麻烦的Java代码如下所示 我根本没有收到任何错误,但是没有反映出数据库更改。当我在SQ