为啥我们不能从 sql 调用过程

Posted

技术标签:

【中文标题】为啥我们不能从 sql 调用过程【英文标题】:Why can't we call procedure from sql为什么我们不能从 sql 调用过程 【发布时间】:2018-06-23 07:18:59 【问题描述】:

我知道如果函数不包含 out 参数或 DML(自治除外),我们可以从 SQL 调用该函数。但是我们不能在任何情况下从 SQL 调用过程。 原因是什么? 为什么我们不能从 SQL 调用过程?任何具体原因。

【问题讨论】:

您能详细说明一下您想到的哪种用例,从 SQL 语句中调用过程会受益吗? 我知道在现实环境中它没有用。我在万事达卡的面试中被问到这个问题, 我假设面试官想让你说类似 "select 语句应该返回查询结果,但是如果我们允许 select 语句运行 dml(update/delete/ insert) 通过调用过程,说 select 语句不修改表的整个目的将毫无意义”。现在,如果你再次问为什么你应该说“这就是设计程序语言的人在实现它时所想的,那是一个 ANSI 标准”。再往前走,它变成了一个历史问题和不是 SQL。 【参考方案1】:

原因是SQL ANSII standard指定SQL查询中只能使用函数。 ISO 委员会成员没有定义 SQL 查询中过程的使用。

【讨论】:

我不确定这是否真的回答了这个问题。【参考方案2】:

你可以:

call dbms_output.put_line('Hello')

CALL 是 SQL 语言的一部分。

或者我们可以在一个内联函数中嵌入一个过程:

with function f (p varchar2)
        return varchar2
    as
    begin
        dbms_output.put_line('Hello');
        return p;
    end f;
select f('Demo')
from   dual

如果你的意思是 SELECT 声明,我看不出你期望它如何工作。您希望这样的查询返回什么结果集?

select dbms_output.put_line('Hello')
from   dual

select dbms_stats.gather_table_stats(user, table_name)
from   user_tables

这不是某些标准委员会的任意限制。它只是在语义上没有任何意义。

【讨论】:

假设过程名称是 p1()。那么你可以从双写select p1()吗?我想不是。但我的问题是为什么? 我已经用select dbms_output.put_line('Hello') from dual 的例子介绍了这个确切的情况,我问'您希望这样的查询返回什么结果集?' select dbms_output.put_line('Hello') from dual 在 Oracle 中不起作用。我已经运行并检查了它。 我知道。那又怎样? 我亲爱的先生,你明白我在问什么。我在一次采访中被问到为什么我们不能像在函数中那样从独立的选择查询中调用过程。假设 f1() 是函数,那么我们可以写 select f1() from dual;但是如果 p1() 是过程,我们不能从对偶中选择 p1(); . oracle 如何限制从过程中调用过程。以及为什么我们做不到。【参考方案3】:

您可以在 SQL 中轻松调用或执行过程。参数化或非参数化都可以调用。

EXEC dbo.procedure_name

【讨论】:

exec 不是 Oracle SQL command 好的,我只考虑 SQL Server。 问题被标记为sql(指标准SQL)和oracle。 SQL Server 从来都不是问题的一部分 SQL Server 文档似乎模糊了 SQL 语言和 T-SQL 扩展(例如 printkill)之间的界限,所以我不确定 exec 是否是SQL Server 中的 SQL 语言。【参考方案4】:

我假设您是在询问从其他 SQL 语句中调用过程(不仅仅是单独调用一个过程,这显然是可能的)。

为什么?这是一个见仁见智的问题,您必须向 Oracle 数据库架构师询问真正的原因。

看起来,在所有可能的 SQL 语句中引入过程调用会带来语法和实现的复杂性,但不一定会带来更多的价值。通常有一些替代方案,它们并不难使用,同时允许相同的结果。

如果是查询(SELECT 语句),结果应该是一个数据集,并且不应更改数据库状态(数据或结构)。 PL/SQL 过程不返回数据集,并且可以更改数据库状态。

如果您处于需要调用过程来准备数据的情况下,您想查询,那么您可以先调用该过程,然后再查询数据库。

您还可以编写一个过程,该过程将具有游标引用的输出参数,这将有效地为您提供查询结果。 (对于临时案例,您可以使用参数化匿名 PL/SQL 块。)

您还可以编写一个表格函数,您可以在其中使用 PL/SQL 进行复杂的数据处理,并返回一个数据集。这样的函数可以在查询中使用。

如果您还询问其他类型的 SQL 语句,那么您可以随时调用 DML (INSERT / UPDATE / DELETE / MERGE)、DDL (CREATE / ALTER / @ 987654328@) 或 DCL (GRANT / REVOKE) 来自过程或匿名 PL/SQ 块,这样做并允许您混合 PL/SQL 逻辑。无需以其他方式执行此操作(引入 PL /SQL 转换为 DML / DDL / DCL)。

【讨论】:

以上是关于为啥我们不能从 sql 调用过程的主要内容,如果未能解决你的问题,请参考以下文章

为啥从应用程序调用 sql 过程返回 0 行?

为啥一个过程不能在 Oracle 中调用另一个过程

为啥有换行符时我的 PL/SQL 过程不能编译?

SQL Server:为啥要在存储过程名称的末尾添加“;1”?

为啥执行存储过程比脚本中的 SQL 查询更快?

为啥我们要编写 create/replace 来在 PL/SQL 中创建过程