加入是否导致其他列数据发生变化?

Qui*_*ver 3 join sql-server subquery

我会说,我是比较新的数据库和SQL,我试图做的除了率先ViewSQL 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
Run Code Online (Sandbox Code Playgroud)

就像我说的,我目前拥有它的方式,它有效,但它太慢了。一旦我尝试LEFT OUTER JOIN它,它就会快得多,但其他列就像RegularQuantity其他数字一样膨胀(我不确定这是怎么发生的)。

如果有人能指导我朝着正确的方向前进,那就太好了!

RDF*_*ozz 8

您的问题很可能是,当您添加零食时,您有多个表为您的GROUP BY语句中的列返回不止一行- 可能是Customer_SnacksCustomer_Ledger_LineItems

当数据库引擎执行连接时,它会匹配第一个表中具有值ABC 的多行与第二个表中具有相同值ABC 的多行(外部连接的工作方式略有不同,但我们暂时忽略它) .

我猜对于给定的Customer_Ledger行,您绑定到Customer一行、MealPlan一行、一个(或零)个PromoCode row, and multipleCustomer_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,因为这些行现在每行出现三倍。基本上,您在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
      )
Run Code Online (Sandbox Code Playgroud)

并且会在SELECT您的查询之前进行。然后,您只需放置ss.SnackQuantity子查询所在的位置,然后添加:

LEFT OUTER JOIN
  SnackSums ss
    ON (cl.CustomerId = ss.CustomerId AND ss.DeliveryDate = mp.DeliveryDate1)
Run Code Online (Sandbox Code Playgroud)

就在您的GROUP BY. 最后,您还需要添加ss.SnackQuantityGROUP BY,因为在主查询的上下文中,这是一个独立的、非聚合的值。

现在,我不保证这会比子查询更快。但是,它应该是准确的 - 如果它不准确,那么速度很快就没关系。