【发布时间】:2011-02-24 10:53:41
【问题描述】:
看起来使用动态 SQL 通过 EXECUTE 字符串方法创建的 #temptables 具有不同的范围,并且不能被同一存储过程中的“固定”SQL 引用。 但是,我可以在子序列动态 SQL 中引用由动态 SQL 语句创建的临时表,但似乎存储过程不会将查询结果返回给调用客户端,除非 SQL 已修复。
一个简单的2表场景: 我有 2 张桌子。我们称它们为订单和项目。 Order 的主键是 OrderId,Items 的主键是 ItemId。 Items.OrderId 是标识父订单的外键。一个订单可以有 1 到 n 个商品。
我希望能够为用户提供一个非常灵活的“查询构建器”类型的界面,以允许用户选择他想查看的项目。筛选条件可以基于 Items 表和/或父 Order 表中的字段。如果 Item 满足过滤条件,包括父 Order 的条件(如果存在),则应在查询中返回该 Item 以及父 Order。
通常,我想大多数人会在 Item 表和父 Order 表之间构建一个连接。我想改为执行 2 个单独的查询。一个返回所有符合条件的项目,另一个返回所有不同的父订单。原因有两个,你可能同意也可能不同意。
第一个原因是我需要查询父 Order 表中的所有列,如果我执行一个查询以将 Orders 表连接到 Items 表,我将多次重复 Order 信息。由于每个订单通常有大量商品,我想避免这种情况,因为这会导致更多数据传输到胖客户端。相反,如前所述,我想在数据集中单独返回两个表,并使用其中的两个表来填充自定义订单和子项目客户端对象。 (我对 LINQ 或实体框架还不够了解。我手动构建我的对象)。我想返回两个表而不是一个表的第二个原因是因为我已经有另一个过程返回给定 OrderId 的所有项目以及父 Order 并且我想使用相同的 2 表方法以便我可以重用客户端代码从返回的 2 个数据表中填充我的自定义 Order 和 Client 对象。
我希望做的是:
在客户端上构造一个动态 SQL 字符串,将订单表连接到 Items 表,并按照在 Winform 胖客户端应用程序上创建的自定义过滤器指定的过滤器对每个表进行适当的过滤。客户端上的 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 */
"
然后,我会调用一个存储过程,
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 创建的,因此无法从以下 2 个静态 SQL 访问,如果我将静态 SQL 更改为动态,则不会将任何结果传递回胖客户端。
我想到了 3 个,但我正在寻找一个更好的:
1) 第一个 SQL 可以通过从客户端执行动态构造的 SQL 来执行。然后可以将结果作为表传递给上述存储过程的修改版本。我熟悉将表数据作为 XML 传递。如果我这样做了,那么存储过程可以使用静态 SQL 将数据插入到临时表中,因为它是由动态 SQL 创建的,因此可以毫无问题地查询。 (我还可以研究传递新的 Table 类型参数而不是 XML。)但是,我想避免将可能很大的列表传递给存储过程。
2) 我可以执行来自客户端的所有查询。
第一个是这样的:
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)
这仍然使我能够重用我的客户端对象填充代码,因为订单和项目继续在两个不同的表中返回。
我有一种感觉,在我的存储过程中我可能有一些使用表数据类型的选项,但这对我来说也是新的,我希望能稍微用勺子喂它。
如果您对我所写的内容进行了如此深入的了解,我会感到惊讶,但如果是这样,我将不胜感激您对如何最好地完成这一点的任何想法。
【问题讨论】:
-
您绝对可以将动态 sql 的结果返回给调用应用程序。这里的大多数答案都解决了您提出的其他观点。
标签: sql-server tsql stored-procedures dynamic-sql temp-tables