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

发布于 2024-08-10 09:29:54 字数 2227 浏览 4 评论 0原文

我有以下查询:

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们有什么建议吗?

I have the following queries:

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]

As you can see they are very similar - only the lines regarding whether the query is for DLData or Delivery are different. One returns the total delivered the other returns the total dispensed.

Currently I am using them as two separate sub-queries in a third query. Singly they take approximately 1-2 seconds each. As two subqueries they are taking between 6 and 10 seconds (depending on load) and both return just 47 rows (though they are touching thousands of rows total).

I was thinking that combining them will give me a decent speed up - especially as this query will be called a lot.

However my attempts have failed as the number of rows change when I try to combine the two. I have tried various JOIN combinations but nothing returns the correct results.

Do the SO'ers have any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

走走停停 2024-08-17 09:29:54

您可以尝试:

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]

我做了左连接,但内部连接可能会起作用,具体取决于您的数据。我还会检查以确保所有这些外键字段都已建立索引。

you could try:

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]

I did a left join but an Inner join might work depending on your data. I'd also check to make sure that all of those foreign key fields are indexed.

西瓜 2024-08-17 09:29:54

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

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)

希望这会有所帮助。

-史蒂夫

After a quick look at your query, I can't be sure if this is correct without understanding the business rules behind the data. However, you can give this a shot if you'd like:

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]

one key to it is this part:

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

Which is heavily based on assumptions of your business rules but might make up for extra rows returned by the two left joins. You can also play with something like this if you'd like:

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

hope this helps.

-steve

夏了南城 2024-08-17 09:29:54

我对此写了一个愚蠢的答案,它让我烦恼,所以我开始更多地研究它 - 基本上你想将分组放在连接内。我没有时间编辑您的代码,但我认为这个示例应该可以帮助您:

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

I wrote a dumb answer to this and it bugged me so I started looking into it a bit more - basically you want to put the group bys inside the joins. I haven't got time to edit your code but I think this example should get you there:

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
深居我梦 2024-08-17 09:29:54

以下是将您的查询重写为单个查询:

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

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

Here's my rewrite of you queries into a single query:

   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

Depending on your data, the JOINs to DLDATA and DELIVERY could be inner joins.

It'd be good to get in the habit of using table aliases.

缱倦旧时光 2024-08-17 09:29:54

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

Without wanting to sound overly stupid, but I guess a union is not going to help (would require a small change to a returned column name...)?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文