在多个子查询中使用WITH查询的结果

时间:2013-12-06 13:42:11

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

我想到MSSQL数据库进行一次往返,以检索多个表。每个表都以某种方式依赖于相同的昂贵查找,这将获取一堆ID并处理分页和非常基本的过滤。所以我试图将昂贵的部分移出,所以它只发生一次,然后重复使用它的结果集。

下面是我正在努力做的一个非常简化的版本。 “主要查询”是昂贵的查找,它对于它下面的下一个其他查询很常见。 “第一个结果集”应该按照您的预期返回我想要的内容,但“第二个结果集”会因为主查询超出范围而失败。

-- Primary query
WITH t(ItemId, Row) AS (
    SELECT ItemId, ROW_NUMBER() OVER(ORDER BY DateCreated DESC) AS Row
    FROM Items
)

-- First result set
SELECT * 
FROM Items
INNER JOIN t ON Items.ItemId = t.ItemId
WHERE t.Row < 10

-- Second result set
SELECT *
FROM Photos
INNER JOIN ItemPhotos ON Photos.PhotoId = ItemPhotos.PhotoId
INNER JOIN t ON ItemPhotos.ItemId = t.ItemId
WHERE t.Row < 10

有没有办法做到这一点,以便第二个结果集有效?

我想避免创建临时表,因为根据我的经验,我几乎总是有一个更便宜的替代品,我还没有学到。在这种情况下,我不确定是否有替代方案,但我希望有人知道解决方法。 (我当然会对它们进行测试。)

我知道在上面的示例中,您可以通过对整个事情执行INNER JOIN来返回单个结果集,但在我的情况下,它不是一个可行的解决方案,因为结果集会很大。

3 个答案:

答案 0 :(得分:3)

不,没有办法做到这一点。

答案 1 :(得分:0)

如果您不想使用临时表,可以使用如下变量表:(由于Aaron感谢错误而更改)

宣布@mytable(......)

答案 2 :(得分:0)

正如我的评论中所述,即使该语法有效,它也无法达到单次访问数据库的目的,因为CTE只是语法。

鉴于t.Row&gt; 1740 AND t.Row&lt; = 1760我会把#temp放在临时表上 我喜欢临时表的简单性,但它不能很好地查询优化

这假设ItemID是PK

如果要创建#temp,则在其中放置一些结构,以使连接尽可能高效。

插入中的顺序将最小化(或消除)PK上的碎片

连接中的#temp.rn而不是where使查询优化器有机会在连接之前进行过滤

IF OBJECT_ID(N'tempdb..#temp', N'U') IS NOT NULL   DROP TABLE #temp;
CREATE TABLE #temp (ItemId INT PRIMARY KEY CLUSTERED, rn INT);  

insert into #temp 
SELECT sID, ROW_NUMBER() OVER(ORDER BY addDate DESC) AS Row
  FROM docSVsys 
 where sID < 10000
 ORDER by sID;

select count(*) from #temp;

CREATE UNIQUE NONCLUSTERED INDEX [IX] ON #temp ([rn] ASC);

select docSVtext.value
  from docSVtext 
  join #temp 
    on docSVtext.sID = #temp.ItemID 
   and #temp.rn >= 100
   and #temp.rn  < 200;

select docSVdate.value
  from docSVdate 
  join #temp 
    on docSVdate.sID = #temp.ItemID 
   and #temp.rn >= 100
   and #temp.rn  < 200; 

IF OBJECT_ID(N'tempdb..#temp', N'U') IS NOT NULL   DROP TABLE #temp;

另一个选项是#temp2,您可以为单个条件连接插入行。