Sql-Server

加入導致其他列數據發生變化?

  • June 22, 2017

我首先要說我對數據庫和 SQL 比較陌生,我正在嘗試對以前同事創建的aView進行補充。SQL Server

我正在嘗試加入Customer_Snacks表格,以便我可以獲得Snack Quantity每個客戶的訂單。我遇到的問題是LEFT OUTER JOIN,據我所知,當我執行某個操作時,其他一些列數據會發生巨大變化。

通過使用子查詢,我設法讓它以我希望的方式工作,但它非常慢。查詢需要一分鐘多的時間才能執行,作為回報,呼叫該視圖的應用程序會超時。

這是我目前擁有的作品(我知道,這很混亂):

SELECT
   cl.CustomerID,
   cl.FirstName + ' ' + c.LastName as CustomerDisplay,
   cl.InvoiceID,
   cl.MealPlanID,
   mp.DeliveryDate1 as DeliveryDate,
   SUM(CASE WHEN cll.Name = 'Meal' THEN cll.Quantity ELSE 0 END) as RegularQuantity,
   SUM(CASE WHEN cll.Name = 'Meal' THEN cll.Quantity * Amount ELSE 0 END) as RegularTotal,
   SUM(CASE WHEN cll.Name = 'EXTRAPROTEINMEAL' THEN cll.Quantity ELSE 0 END) as ProteinQuantity,
   SUM(CASE WHEN cll.Name = 'EXTRAPROTEINMEAL' THEN cll.Quantity * Amount ELSE 0 END) as ProteinTotal,
   SUM(CASE WHEN cll.Name = 'TAX' THEN Amount ELSE 0 END) as TotalTax,
   SUM(CASE WHEN cll.Name = 'SNACKS' THEN Amount ELSE 0 END) AS SnackTotal,
   -- Here is my subquery that I would like to integrate into this view with a join so that it's much faster
   (SELECT SUM(cs.Quantity) FROM Fustomer_Snacks as cs WHERE cs.CustomerID = cl.CustomerID and cs.DeliveryDate = mp.DeliveryDate1) as SnackQuantity,
   ------------------------------------------------------------------
   CAST(SUM((CASE WHEN cll.Name = 'home' or cll.Name = 'work' THEN 1 ELSE 0 END)) as bit) as IsDelivery,
   SUM(CASE WHEN (cll.Name = 'home' or cll.Name = 'work' or cll.Name = 'pickup') and cll.Quantity > 0 THEN cll.Quantity * Amount else 0 END) as DeliveryCharge,
   cl.Balance as PrePromoTotal,
   ISNULL(cl.Balance * (pc.Discount * .01), 0) * -1 as PromoDiscount,
   cl.FinalBalance - ISNULL((cl.FinalBalance * (pc.Discount * .01)),0) Total
FROM
   Customer_Ledger as cl
INNER JOIN
   Customer_Ledger_LineItems as cll
       on cl.ID = cll.LedgerID
INNER JOIN
   MealPlan as mp
       on cl.MealPlanID = mp.ID
INNER JOIN
   Customer as c
       on cl.CustomerId = c.Id
LEFT OUTER JOIN
   PromoCode as pc
       on cl.BalancePromoId = pc.Id
GROUP BY
   cl.CustomerID,
   c.FirstName,
   c.LastName,
   MealPlanID,
   InvoiceID,
   mp.DeliveryDate1,
   cl.Balance,
   cl.FinalBalance,
   pc.Discount

就像我說的,我目前擁有它的方式,它可以工作,但它太慢了。一旦我嘗試LEFT OUTER JOIN它,它就會快得多,但其他列就像RegularQuantity其他數字一樣被誇大了(我不確定這是怎麼發生的)。

如果有人能引導我朝著正確的方向前進,那就太好了!

GROUP BY很可能你的問題是,當你添加零食時,你有不止一張表為你的語句中的列返回不止一行- 可能Customer_SnacksCustomer_Ledger_LineItems

當數據庫引擎執行連接時,它會匹配第一個表中的許多行與值ABC,但第二個表中的許多行具有相同的值ABC(外部連接的工作方式略有不同,但我們暫時忽略它) .

我猜對於給定的Customer_Ledger行,您將綁定到Customer一行、MealPlan一行、一(或零)PromoCode row, and multiple個 Customer_Ledger_LineItems 行。

我也在猜測Customer_Ledger一行及其相關MealPlan行,您可以帶回多Customer_Snacks行。

因此,當我們將所有行放在一起時,假設我們有:

  • 1Customer
  • 1Customer_Ledger
  • 1MealPlan
  • 1PromoCode
  • 3Customer_Ledger_LineItems

將所有這些匹配在一起,你得到1 * 1 * 1 * 1 * 3= 3 行。

現在,添加 2Customer_Snacks行。這些與我們已經擁有的所有行匹配,所以我們得到1 * 1 * 1 * 1 * 3 * 2= 6 行。

當我們去取我們的總和時,我們將從Customer_Ledger_LineItems行中得到雙倍的總和,因為現在每行顯示兩次。而且,我們將從 中得到三倍的總和Customer_Snacks,因為這些行現在每行都顯示了 3 次。基本上,您在CROSS JOIN相關Customer_Ledger_LineItems行和Customer_Snacks行之間得到一個。

有兩種方法可以避免這種情況。您已經使用了第一個選項 - 使用子查詢從一個表中獲取總和,該表將多行返回到我們的分組值。

另一個選項非常相似:建構一個包含您需要的所有相關值的臨時表(或 CTE),這樣當您加入數據時,您將只有一行包含所需的總和。在您的情況下,這看起來像:

;WITH SnackSums AS
     (SELECT cs.CustomerID
            ,cs.DeliveryDate
            ,SUM(cs.Quantity) as SnackQuantity
        FROM Customer_Snacks cs
       GROUP BY cs.CustomerID, cs.DeliveryDate
     )

並且會在SELECT您的查詢之前進行。然後,您只需將ss.SnackQuantity子查詢放在哪裡,然後添加:

LEFT OUTER JOIN
 SnackSums ss
   ON (cl.CustomerId = ss.CustomerId AND ss.DeliveryDate = mp.DeliveryDate1)

就在你的GROUP BY. 最後,您還需要添加ss.SnackQuantityGROUP BY因為在您的主查詢的上下文中,這是一個獨立的非聚合值。

現在,我不保證這會比子查詢更快。然而,它應該是準確的——如果它不准確的話,那也不要緊。

引用自:https://dba.stackexchange.com/questions/177050