【问题标题】:Update row to specific column将行更新到特定列
【发布时间】:2026-02-19 17:55:01
【问题描述】:

我有一个 CTE_product 如下:

Customer ProductName Quantity Price
A Apple 2 2.00
A Banana 3 1.00

还有一张表总计:

CustomerName Apple Banana
A 4.00 3.00

我想要的是计算CTE中每个产品的总价格并将其值更新到表Total中的相应列

这是我尝试过的查询:

UPDATE t
SET t.Apple = CASE WHEN ProductName = 'Apple' THEN cte.Quantity * cte.Price ELSE 0 END,
    t.Banana = CASE WHEN ProductName = 'Banana' THEN cte.Quantity * cte.Price ELSE 0 END
FROM Total t
INNER JOIN CTE_product cte ON cte.CustomerName = t.CustomerName

使用此查询,只有 Apple 列具有值。

【问题讨论】:

  • 总表的某些内容似乎不正确......每个水果真的是一个单独的列吗?
  • 是的,当然。由于一些隐私,我必须修复我的数据列的名称。但是结构是正确的

标签: sql sql-server


【解决方案1】:

这是因为更新基本上是逐行完成的,因为在JOINed 数据中,苹果和香蕉位于不同的行。

您需要像这样“跳过”不是更新主题的列的更新:

UPDATE t
SET
  t.Apple =  CASE
               WHEN ProductName = 'Apple'
               THEN cte.Quantity * cte.Price
               ELSE t.Apple
             END,
  t.Banana = CASE
               WHEN ProductName = 'Banana'
               THEN cte.Quantity * cte.Price
               ELSE t.Banana
             END
FROM Total t
INNER JOIN CTE_product cte ON cte.CustomerName = t.CustomerName

或在更新前转置您的数据:

with cte_pivoted as (
  select
    CustomerName,
    [Apple] as Apple,
    [Banana] as Banana
  from CTE_product
  pivot(
    sum(Quantity*Price) for ProductName in ([Apple], [Banana])
  ) as p
)

UPDATE t
  SET t.Apple = coalesce(cte.apple, 0), t.Banana = coalesce(cte.Banana, 0)
FROM Total t
INNER JOIN cte_pivoted cte
  ON cte.CustomerName = t.CustomerName

当然,这两个语句都希望您只有一行用于单个产品和客户。

【讨论】:

  • 感谢您的回答,但第一个解决方案不起作用。 Banana 列仅返回 null
  • @NekoMi 看起来您的 CTE 在 quantityprice 列中有空值。你可以检查这个db<>fiddle
  • 是的。但是在您的小提琴中,Banana 列没有更改或计算。它显示默认值
  • @NekoMi 是的,但是您的要求是什么?如果没有 'Banana' 行,它应该是 0 吗?然后您需要确定是否存在Banana 行,这可通过PIVOT 查询和空处理获得。我已将其更新为设置 0 而不是 null,以防某些产品没有行。
【解决方案2】:

最简单的方法可能是两个连接:

UPDATE t
    SET t.Apple = COALESCE(a.Quantity * a.Price, t.Apple),
        t.Banana = COALESCE(b.Quantity * b.Price, t.Banana)
FROM Total t LEFT JOIN
     CTE_product a
     ON a.CustomerName = t.CustomerName AND
        a.ProductName = 'Apple' LEFT JOIN
     CTE_product b
     ON b.CustomerName = t.CustomerName AND
        b.ProductName = 'Banana'
WHERE a.CustomerName IS NOT NULL OR b.CustomerName IS NOT NULL;

注意:这假设 CTE 每个客户和产品只有一行。

【讨论】:

    【解决方案3】:

    您可以使用FROM 子句中的子查询(条件聚合)来计算香蕉和苹果的总值,如下所示:

    UPDATE t
    SET t.Apple = cte.apple,
        t.Banana = cte.banana
    FROM Total t
    INNER JOIN 
      (select customername,
              sum(CASE WHEN ProductName = 'Apple' THEN cte.Quantity * cte.Price ELSE 0 END) as apple,
              sum(CASE WHEN ProductName = 'Banana' THEN cte.Quantity * cte.Price ELSE 0 END) as banana
        from CTE_product) cte ON cte.CustomerName = t.CustomerName
    

    【讨论】:

      【解决方案4】:

      您还可以转置 CTE 中的数据并从那里更新:

      
      WITH cte_Product AS
      (...)
      , cte_Total AS
      (
          SELECT      [Customer], [ProductName]
                      , [Quantity] * [Price] AS [TotalSalePrice]
          FROM        cte_Product
      )
      , cte_Pivot AS
      (
          SELECT          [Customer], [Apple], [Banana]
          FROM            cte_Total
          PIVOT           ( SUM ( [TotalSalePrice] )
              FOR         [ProductName] IN ( [Apple], [Banana] ) ) AS pvt
      )
      UPDATE          t
      SET             [Apple]     = p.[Apple]
                      , [Banana]  = p.[Banana]
      FROM            cte_Pivot AS p
          INNER JOIN  Total AS t
              ON      p.[Customer] = t.[CustomerName] ;
      GO
      

      【讨论】: