Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server T-SQL动态SQL和临时表_Sql Server_Tsql_Stored Procedures_Dynamic Sql_Temp Tables - Fatal编程技术网

Sql server T-SQL动态SQL和临时表

Sql server T-SQL动态SQL和临时表,sql-server,tsql,stored-procedures,dynamic-sql,temp-tables,Sql Server,Tsql,Stored Procedures,Dynamic Sql,Temp Tables,看起来,通过executestring方法使用动态SQL创建的表具有不同的作用域,不能由同一存储过程中的固定SQL引用。 但是,我可以在子序列动态SQL中引用由动态SQL语句创建的临时表,但存储过程似乎不会将查询结果返回给调用客户机,除非SQL已修复 一个简单的2表场景: 我有两张桌子。让我们称之为订单和物品。Order的主键为OrderId,Items的主键为ItemId。Items.OrderId是标识父订单的外键。订单可以有1到n个项目 我希望能够为用户提供一个非常灵活的查询生成器类型界面

看起来,通过executestring方法使用动态SQL创建的表具有不同的作用域,不能由同一存储过程中的固定SQL引用。 但是,我可以在子序列动态SQL中引用由动态SQL语句创建的临时表,但存储过程似乎不会将查询结果返回给调用客户机,除非SQL已修复

一个简单的2表场景: 我有两张桌子。让我们称之为订单和物品。Order的主键为OrderId,Items的主键为ItemId。Items.OrderId是标识父订单的外键。订单可以有1到n个项目

我希望能够为用户提供一个非常灵活的查询生成器类型界面,允许用户选择他想要查看的项目。筛选条件可以基于Items表和/或parent Order表中的字段。如果某个项目满足筛选条件,包括父订单上的条件(如果存在),则应在查询中返回该项目以及父订单

通常,我认为,大多数人都会在Item表和父Order表之间构造联接。我想执行两个单独的查询。一个返回所有符合条件的项目,另一个返回所有不同的父订单。原因是双重的,你可能同意也可能不同意

第一个原因是,我需要查询父Order表中的所有列,如果我执行一次查询以将Orders表连接到Items表,那么我将多次报告订单信息。由于每个订单通常有大量的项目,我希望避免这种情况,因为这将导致更多的数据被传输到胖客户机。相反,如前所述,我希望在一个数据集中分别返回这两个表,并使用其中的两个表填充自定义订单和子项客户端对象。我对LINQ或实体框架的了解还不够。我手工制作我的物品。我希望返回两个表而不是一个表的第二个原因是,我已经有了另一个过程,该过程将返回给定OrderId的所有项目以及父订单,并且我希望使用相同的2表方法,以便可以重用客户机代码来填充来自2个数据表的自定义订单和客户机对象返回

我希望做的是:

在客户端上构造一个动态SQL字符串,该字符串将orders表连接到Items表,并根据Winform fat客户端应用程序上创建的自定义筛选器的指定,对每个表进行适当的筛选。客户端上的SQL构建应该如下所示:

TempSQL = "

    INSERT INTO #ItemsToQuery
       OrderId, ItemsId
    FROM
       Orders, Items 
    WHERE
       Orders.OrderID = Items.OrderId AND
       /* Some unpredictable Order filters go here */
      AND
       /* Some unpredictable Items filters go here */
    "
SELECT Items.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter)
SELECT Orders.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter)
然后,我会调用一个存储过程

CREATE PROCEDURE GetItemsAndOrders(@tempSql as text)
   Execute (@tempSQL) --to create the #ItemsToQuery table

SELECT * FROM Items WHERE Items.ItemId IN (SELECT ItemId FROM #ItemsToQuery)

SELECT * FROM Orders WHERE Orders.OrderId IN (SELECT DISTINCT OrderId FROM #ItemsToQuery)
这种方法的问题是ItemsToQuery表(因为它是由动态SQL创建的)无法从以下两个静态SQL访问,如果我将静态SQL更改为动态,则不会将任何结果传递回胖客户机

我想到了3个,但我正在寻找一个更好的:

1第一个SQL可以通过从客户端执行动态构造的SQL来执行。然后,可以将结果作为表传递给上述存储过程的修改版本。我熟悉以XML形式传递表数据。如果我这样做了,那么存储的proc就可以使用静态SQL将数据插入到临时表中,因为静态SQL是由动态SQL创建的,所以可以毫无问题地查询该表。我还可以研究传递新的表类型param而不是XML。但是,我希望避免将可能较大的列表传递给存储过程

2我可以执行客户端的所有查询

第一种是这样的:

TempSQL = "

    INSERT INTO #ItemsToQuery
       OrderId, ItemsId
    FROM
       Orders, Items 
    WHERE
       Orders.OrderID = Items.OrderId AND
       /* Some unpredictable Order filters go here */
      AND
       /* Some unpredictable Items filters go here */
    "
SELECT Items.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter)
SELECT Orders.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter)
这仍然使我能够重用客户端对象填充代码,因为订单和项目继续在两个不同的表中返回

我有一种感觉,在我存储的proc中,我可能有一些使用表数据类型的选项,但这对我来说也是新的,我希望能在这一点上多加注意


如果您在我写的文章中浏览了这么远,我会感到惊讶,但如果是这样,我会详细介绍您对如何最好地完成此任务的想法。

您首先需要创建表,然后它将在动态SQL中可用

这项工作:

CREATE TABLE #temp3 (id INT)
EXEC ('insert #temp3 values(1)')

SELECT *
FROM #temp3
这是行不通的:

EXEC (
        'create table #temp2 (id int)
         insert #temp2 values(1)'
        )

SELECT *
FROM #temp2
换言之:

创建临时表 执行程序 从临时表中选择 以下是完整的示例:

CREATE PROC prTest2 @var VARCHAR(100)
AS
EXEC (@var)
GO

CREATE TABLE #temp (id INT)

EXEC prTest2 'insert #temp values(1)'

SELECT *
FROM #temp

来自动态SQL的结果集将返回给客户端。我已经做了很多了

关于通过临时表和变量共享数据以及在SQL和它生成的动态SQL之间共享数据的问题,您是对的

我认为,在尝试使临时表正常工作时,您可能会感到困惑,因为您肯定可以从执行动态SQL的SP获取数据:

USE SandBox
GO

CREATE PROCEDURE usp_DynTest(@table_type AS VARCHAR(255))
AS 
BEGIN
    DECLARE @sql AS VARCHAR(MAX) = 'SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''' + @table_type + ''''
    EXEC (@sql)
END
GO

EXEC usp_DynTest 'BASE TABLE'
GO

EXEC usp_DynTest 'VIEW'
GO

DROP PROCEDURE usp_DynTest
GO
此外:
我强烈建议你通读一遍


就我个人而言,我喜欢传递逗号分隔的文本列表,然后使用文本到表函数解析它并连接到它。如果先在连接中创建临时表,则临时表方法可以工作。但感觉有点乱

1st方法-在同一个动态SQL调用中包含多个语句:

DECLARE @DynamicQuery NVARCHAR(MAX)

SET @DynamicQuery = 'Select * into #temp from (select * from tablename) alias 
select * from #temp
drop table #temp'

EXEC sp_executesql @DynamicQuery
第二种方法-使用全局临时表: 注意,您需要特别注意全局变量

完成temp2对象后,不要忘记手动删除它:

IF (OBJECT_ID('tempdb..##temp2') IS NOT NULL)
BEGIN
     DROP Table ##temp2
END

注意:如果您不知道数据库的完整结构,请不要使用此方法2。

我遇到了@Muflix提到的相同问题。当您不知道返回的列或动态生成的列时,我所做的是创建一个具有唯一id的全局表,然后在处理完后将其删除,如下所示:

DECLARE @DynamicSQL NVARCHAR(MAX)
DECLARE @DynamicTable VARCHAR(255) = 'DynamicTempTable_' + CONVERT(VARCHAR(36), NEWID())
DECLARE @DynamicColumns NVARCHAR(MAX)

--Get "@DynamicColumns", example: SET @DynamicColumns = '[Column1], [Column2]'

SET @DynamicSQL = 'SELECT ' + @DynamicColumns + ' INTO [##' + @DynamicTable + ']' + 
     ' FROM [dbo].[TableXYZ]'

EXEC sp_executesql @DynamicSQL

SET @DynamicSQL = 'IF OBJECT_ID(''tempdb..##' + @DynamicTable + ''' , ''U'') IS NOT NULL ' + 
    ' BEGIN DROP TABLE [##' + @DynamicTable + '] END'

EXEC sp_executesql @DynamicSQL

当然不是最好的解决方案,但这似乎对我很有效。

TLDR:您完全可以将动态sql的结果返回给调用应用程序。这里的大多数答案都涉及到您提出的其他要点。如果您在进程中创建临时表,它将不起作用,您需要先创建临时表,然后才能在进程中填充它。另请参阅我的example@SQLMenace-我明白你在说什么。我的观点是,您可以从动态SQL返回集合,它们可以使用自己的临时表并从中返回。我将添加第二个示例。我认为这也有效:插入到诱惑执行器'select??从;问题是,当我们不知道列的定义时,怎么样?假设您知道该表存在,将目标表中的top 1放入someTable。然后截断某个表。这又快又脏。免责声明:例如,varchars的列大小可能不代表整个集合中的最大大小。如果您担心这个问题,请从sys.tables和sys.columns构建临时表。你应该只需要做一次。如果您对动态SQLI的了解比CSV更快地传递XML,那么它也可以动态完成。虽然更加详细,但它允许灵活地修改和传递其他列。SQL已经知道如何解析XML了。但我看到了将客户机数据集传递到服务器端表变量的示例。非常干净。尽管如此,它还是不如temp表IMHO理想,因为它是一种不太可能扩展的方法。SQL Server 2008+或2005?支持在ADO.NET数据集中定义好后可通过客户端提供的表值,例如SQL Server 2016+支持JSON。