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

标签 sql sql-server database oracle stored-procedures

众所周知,您无法在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的上下文中这样做将是非常不切实际且难以管理的。

因此:

  • 过程可以调用过程,任何函数和SQL
  • “纯”函数可以调用“纯”函数和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;
    /
    

    然后:
    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/

    相关文章:

    android - sqlite 中的问题与 android 中的 "like"

    java - 使用java从mssql表中检索直方图

    sql - 在 sql 中按月份和年份排序并求和

    sql-server - SQL替换一个空的XML值

    MySQL 仅向具有不同值的表添加索引

    sql - 如何根据 SQL Server 表中给定的 Id 在链中查找子、父及其子和父

    c# - 强类型 DataContext 如何工作?

    SQL 语句作为列表框 VB.NET 的数据源

    sql - 如何使用 SQL 按类型获取项目的百分比

    database - PostgreSQL 9.3 中 b/w pg_basebackup 和 TAR 备份(停止/启动)备份的区别?