2009-11-11 114 views
1

我有以下疑问:合并这两个查询到一个查询

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] 

正如你可以看到他们是非常相似的 - 只是关于查询是否是用于DLDataDelivery是不同的线路。其中一个返还总额,另一个返还总额。

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

我在想,合并它们会给我一个体面的加速 - 尤其是当这个查询将被称为很多。

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

SO'ers有什么建议吗?

回答

0

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

+0

不,因为这个想法是将这些简化为单个查询。唯一的相关领域是SUM。其余的是与已知结果进行比较。 – 2009-11-11 13:58:01

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] 

我做了左加入,但内部联接可能会因您的数据。我还会检查以确保所有这些外键字段都已编入索引。

+0

这就是我尝试过的(使用各种连接) - 随着行数由于连接本身而改变,数字将返回偏斜。 – 2009-11-11 14:00:54

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) 

希望这可以帮助。

史蒂夫

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 
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可能是内部联接。

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

+0

这与我和其他尝试过的人遇到同样的问题:当添加DLData或Delivery时,总和值会改变。 – 2009-11-16 10:29:37