将这两个查询合并为一个查询

时间:2009-11-11 13:42:31

标签: sql sql-server-2000

我有以下疑问:

SELECT Sites.EDISID, Sites.[Name], (SUM(DLData.Quantity) / 8) AS TiedDispense
FROM Sites
  JOIN UserSites 
    ON UserSites.EDISID = Sites.EDISID
  JOIN Users
    ON Users.[ID] = UserSites.UserID
 JOIN MasterDates 
  ON MasterDates.EDISID = UserSites.EDISID
 JOIN DLData
  ON DLData.DownloadID = MasterDates.[ID]
 JOIN Products 
  ON Products.[ID] = DLData.Product
 LEFT JOIN SiteProductTies 
  ON SiteProductTies.EDISID = UserSites.EDISID
  AND SiteProductTies.ProductID = Products.[ID]
 LEFT JOIN SiteProductCategoryTies 
  ON SiteProductCategoryTies.EDISID = UserSites.EDISID
  AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID
 WHERE Users.[ID] = @UserID
  AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = @Tied OR @Tied IS NULL)
  AND MasterDates.[Date] BETWEEN @From AND @To
  AND MasterDates.[Date] >= Sites.SiteOnline
 GROUP BY Sites.EDISID, Sites.[Name]

SELECT Sites.EDISID, Sites.[Name], SUM(Delivery.Quantity) AS TiedDelivered
FROM Sites
  JOIN UserSites 
    ON UserSites.EDISID = Sites.EDISID
  JOIN Users
    ON Users.[ID] = UserSites.UserID
 JOIN MasterDates 
  ON MasterDates.EDISID = UserSites.EDISID
 JOIN Delivery
  ON Delivery.DeliveryID = MasterDates.[ID]
 JOIN Products 
  ON Products.[ID] = Delivery.Product
 LEFT JOIN SiteProductTies 
  ON SiteProductTies.EDISID = UserSites.EDISID
  AND SiteProductTies.ProductID = Products.[ID]
 LEFT JOIN SiteProductCategoryTies 
  ON SiteProductCategoryTies.EDISID = UserSites.EDISID
  AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID
 WHERE Users.[ID] = @UserID
  AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = @Tied OR @Tied IS NULL)
  AND MasterDates.[Date] BETWEEN @From AND @To
  AND MasterDates.[Date] >= Sites.SiteOnline
 GROUP BY Sites.EDISID, Sites.[Name]

正如您所看到的,它们非常相似 - 只有关于查询是针对DLData还是Delivery的行不同。一个返回总交付​​的其他返回总分配。

目前我在第三个查询中将它们用作两个单独的子查询。他们单独约需1-2秒。作为两个子查询,它们需要6到10秒(取决于负载),并且两者都只返回47行(尽管它们总共触及数千行)。

我在考虑将它们组合在一起会给我一个不错的加速 - 特别是因为这个查询会被调用很多。

然而,当我尝试将两者结合起来时,我的尝试失败了,因为行数发生了变化。我尝试了各种JOIN组合,但没有任何结果返回正确的结果。

SO'ers有什么建议吗?

5 个答案:

答案 0 :(得分:1)

你可以尝试:

SELECT Sites.EDISID, 
    Sites.[Name], 
    (SUM(DLData.Quantity) / 8) AS TiedDispense, 
    SUM(Delivery.Quantity) AS TiedDelivered
FROM Sites  
JOIN UserSites     
    ON UserSites.EDISID = Sites.EDISID  
JOIN Users    
    ON Users.[ID] = UserSites.UserID 
JOIN MasterDates   
    ON MasterDates.EDISID = UserSites.EDISID 
JOIN DLData  
    ON DLData.DownloadID = MasterDates.[ID] 
JOIN Products   
    ON Products.[ID] = DLData.Product
LEFT JOIN Delivery  
    ON Delivery.DeliveryID = MasterDates.[ID] 
LEFT JOIN SiteProductTies   
    ON SiteProductTies.EDISID = UserSites.EDISID  AND SiteProductTies.ProductID = Products.[ID] 
LEFT JOIN SiteProductCategoryTies   
    ON SiteProductCategoryTies.EDISID = UserSites.EDISID  
    AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID 
WHERE Users.[ID] = @UserID  
    AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = @Tied 
        OR @Tied IS NULL)  
    AND MasterDates.[Date] BETWEEN @From AND @To  
    AND MasterDates.[Date] >= Sites.SiteOnline 
GROUP BY Sites.EDISID, Sites.[Name]

我做了一个左连接,但内连接可能会有效,具体取决于您的数据。我还要检查以确保所有这些外键字段都已编入索引。

答案 1 :(得分:1)

在快速查看您的查询后,如果不了解数据背后的业务规则,我无法确定这是否正确。但是,如果您愿意,可以试一试:

SELECT 

Sites.EDISID, Sites.[Name], 
CASE WHEN Delivery.DeliveryID IS NULL THEN 0 ELSE SUM(Delivery.Quantity) END TiedDelivered, 
CASE WHEN DLData.[ID] IS NULL THEN 0 ELSE (SUM(DLData.Quantity) / 8) END TiedDispense 

FROM Sites
  JOIN UserSites 
    ON UserSites.EDISID = Sites.EDISID
  JOIN Users
    ON Users.[ID] = UserSites.UserID
 JOIN MasterDates 
  ON MasterDates.EDISID = UserSites.EDISID
 LEFT JOIN Products 
  ON Products.[ID] = DLData.Product

 LEFT JOIN DLData
  ON DLData.DownloadID = MasterDates.[ID]
 LEFT JOIN Delivery
  ON Delivery.DeliveryID = MasterDates.[ID]

 LEFT JOIN SiteProductTies 
  ON SiteProductTies.EDISID = UserSites.EDISID
  AND SiteProductTies.ProductID = Products.[ID]
 LEFT JOIN SiteProductCategoryTies 
  ON SiteProductCategoryTies.EDISID = UserSites.EDISID
  AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID
 WHERE Users.[ID] = @UserID
  AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = @Tied OR @Tied IS NULL)
  AND MasterDates.[Date] BETWEEN @From AND @To
  AND MasterDates.[Date] >= Sites.SiteOnline
  AND (DLData.[DownloadID] IS NOT NULL OR DELIVERY.DeliveryID IS NOT NULL)
 GROUP BY Sites.EDISID, Sites.[Name]

这一部分的一个关键是:

  AND (DLData.[DownloadID] IS NOT NULL OR DELIVERY.DeliveryID IS NOT NULL)

这主要基于业务规则的假设,但可能会弥补两个左连接返回的额外行。如果你愿意,你也可以玩这样的东西:

AND ( TiedDelivered != 0 AND TiedDispense != 0)

希望这会有所帮助。

-Steve

答案 2 :(得分:1)

我给这个写了一个愚蠢的答案,它给我带来了麻烦,所以我开始更多地研究它 - 基本上你想把这些组织放在连接中。我没有时间编辑你的代码,但我认为这个例子可以帮助你:

create table #prod(
prodid int,
prodamount int)

create table #del(
delid int,
delamount int)

create table #main(
id int,
name varchar(50))

insert into #main(id,name)
select 1, 'test 1'
union select 2, 'test 2'
union select 3, 'test 3'
union select 4, 'test 4'

insert into #prod(prodid,prodamount)
select 1, 10
union select 1, 20
union select 1, 30
union select 2, 5

insert into #del(delid,delamount)
select 1, 9
union select 1, 8
union select 3, 7

/** wrong **/

select m.id, m.name, isnull(sum(p.prodamount),0), isnull(sum(d.delamount),0)
from #main m
left join #prod p on p.prodid = m.id
left join #del d on d.delid = m.id
group by m.id, m.name

/** right! **/
select id, name, isnull(myprod.prodtot,0) as prodtot, isnull(mydel.deltot,0) as deltot
from #main
left join 
    (SELECT prodid, SUM(prodamount) AS prodtot
    FROM #prod
    GROUP BY prodid) myprod on #main.id = myprod.prodid
left join 
    (SELECT delid, SUM(delamount) AS deltot
    FROM #del
    GROUP BY delid) mydel on #main.id = mydel.delid



drop table #prod
drop table #del
drop table #main

答案 3 :(得分:1)

这是我将您的查询重写为单个查询:

   SELECT t.edisid,
          t.name, 
          SUM(dd.quantity) / 8 AS TiedDispense,
          SUM(d.quantity) AS TiedDelivered
     FROM SITES t
     JOIN USERSITES us ON us.edisid = t.esisid
     JOIN USERS u ON u.id = us.userid
     JOIN MASTERDATES md ON md.edisid = us.edisid
                        AND md.date >= t.siteonline
LEFT JOIN DLDATA dd ON dd.downloadid = md.id
LEFT JOIN DELIVERY d ON d.deliveryid = md.id
     JOIN PRODUCTS p ON p.id IN (dd.product, d.product)
LEFT JOIN SITEPRODUCTTIES spt ON spt.edisid = us.edisid
                             AND spt.productid = p.id
LEFT JOIN SITEPRODUCTCATEGORYTIES spct ON spct.edisid = us.edisid
                                      AND spct.productcategoryid = p.categoryid
    WHERE u.id = @UserID
      AND (@Tied IS NULL OR COALESCE(spt.tied, spct.tied, p.tied) = @Tied)
      AND md.date BETWEEN @From AND @To      
 GROUP BY t.edisid, t.name

根据您的数据,DLDATADELIVERY的联接可能是内部联接。

养成使用表别名的习惯会很好。

答案 4 :(得分:0)

不想听起来过于愚蠢,但我想工会不会有帮助(需要对返回的列名进行少量更改......)?