2009-11-11 159 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