【问题标题】:How to EXEC a query generated in a CTE如何执行在 CTE 中生成的查询
【发布时间】:2012-07-24 13:49:07
【问题描述】:

我有一个 CTE,其中生成了 SELECT 语句,但 SQL Server (2012) 不允许在其上调用 EXEC。这是查询:

DECLARE @guidToFind uniqueidentifier = 'E4069560-091A-4026-B519-104F1C7693B3';

WITH GuidCols (TableName, ColName, Query) As
(
    SELECT  
        C.TABLE_NAME, 
        C.COLUMN_NAME, 
        'SELECT ' + 
             QUOTENAME(C.TABLE_NAME) + '.' + 
             QUOTENAME(C.COLUMN_NAME) + ' 
        FROM ' + 
             QUOTENAME(C.TABLE_NAME) + ' 
        WHERE ' + 
           QUOTENAME(C.COLUMN_NAME) + ' = ''' + cast(@guidToFind AS VARCHAR(50))+
           ''''
    FROM 
        INFORMATION_SCHEMA.COLUMNS C 
        INNER JOIN INFORMATION_SCHEMA.TABLES T 
        ON C.TABLE_NAME = T.TABLE_NAME AND 
           T.TABLE_TYPE = 'BASE TABLE'
    WHERE 
        C.DATA_TYPE = 'uniqueidentifier'
)
-- SELECT * FROM
EXEC( GuidCols.Query )

如果我在 CTE 之后取消注释 SELECT 语句,问题并没有解决。

此查询的目的是查找数据库中 GUID 的所有实例。目前我正在使用像this 这样的脚本来解决这个问题。但是,如果不使用集合操作和其他技术迭代行,我会更乐意解决这个问题。

【问题讨论】:

  • EXISTS 如果您只想知道包含该值的表和列,则可能是查找 GUID 实例的更有效方法。您可以组装一个单一的查询 UNIONs 所有结果,然后 EXECUTE 该字符串。
  • @HABO 感谢您的提示。你能解释一下我在哪里可以使用EXISTS吗?在第二部分中,您的意思是制作一串硬编码的表和列名称,例如'SELECT ''[table1]'', ''[Col5]'' UNION ALL SELECT ''[table3]'', ''[Col8]'''?
  • @HABO 我目前正在以这种方式实现这一目标:gist.github.com/3180402 但如果我可以使用集合操作而不是循环,我会更开心
  • 在您的 github 示例中,您添加了 DISTINCT,这样如果在给定的表和列中找到 GUID 一次或多次,您只会获得一行。如果列包含 GUID 的实例,select C.Table_Name, C.Column_Name from C.Table_Name where exists ( select 42 from C.Table_Name where C.Column_Name = @GuidToFind ) 将返回表名和列名。它使优化器清楚地知道,您并不关心该值被发现的频率,只要它存在即可。如果您将UNION 对每个表和列进行一系列此类查询,您将获得 GUID 所在位置的列表。

标签: sql sql-server common-table-expression


【解决方案1】:

EXEC() 函数可从 T-SQL 获得,但不能从 SQL 语句中访问。我会假设是这种情况,因为 SQL 是在几个步骤中执行的......类似于:

  1. 您的语句已解析。
  2. 生成执行计划。
  3. 针对数据库运行执行计划并返回结果。

EXEC() 函数旨在动态执行语句,因此为了执行您的要求,SQL Server 必须执行前两个步骤,然后在执行语句时,它必须返回到解析/执行动态语句的第一步。这必须对结果中的每一行重复。

我认为这种类型的“功能”不可用,因为它可能会对数据库引擎的性能和复杂性产生不利影响;所以他们让我们执行第一条语句,然后循环遍历每条记录以单独执行动态语句。

【讨论】:

    【解决方案2】:

    Exec 执行您嵌入在其括号中的 T-SQL 命令。不同之处在于 EXEC() 函数可以执行字符串或字符串变量,正如您在前面的代码中看到的那样。 EXEC() 的参数可以是文字字符串,但是当您使用变量时,EXEC() 的真正威力就会显现出来。

    它执行包含在变量中的命令,但在与调用函数的会话不同的上下文中。这很重要,因为它引入了一些严格的限制。您创建的任何表都对 EXEC() 上下文可见,但调用会话声明的变量对 EXEC() 上下文不可见,反之亦然。

    我在http://msdn.microsoft.com/en-us/library/aa175921(v=sql.80).aspx找到了一篇与此相关的有趣文章

    虽然上面是自给自足的,你也可以通过:http://blog.sqlauthority.com/2007/09/13/sql-server-difference-between-exec-and-execute-vs-exec-use-execexecute-for-sp-always/

    【讨论】:

      【解决方案3】:

      您不能将exec 用作CTE 的一部分。

      来自WITH common_table_expression (Transact-SQL)

      CTE 后面必须跟一个 SELECT、INSERT、UPDATE 或 DELETE 引用部分或全部 CTE 列的语句。

      您可以做的是将查询的结果存储在临时表中,遍历行并一次执行一条语句。

      【讨论】:

        【解决方案4】:

        您可以使用 OPENQUERY 代替 EXEC:

        SELECT * FROM OPENQUERY (OracleSvr, 'SELECT name FROM joe.titles WHERE name = ''NewTitle''');
        

        参考:https://docs.microsoft.com/en-us/sql/t-sql/functions/openquery-transact-sql?view=sql-server-2017

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-28
          • 1970-01-01
          • 2020-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多