将行更新到特定列

Posted

技术标签:

【中文标题】将行更新到特定列【英文标题】:Update row to specific column 【发布时间】:2021-02-02 08:26:47 【问题描述】:

我有一个 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 列具有值。

【问题讨论】:

总表的某些内容似乎不正确......每个水果真的是一个单独的列吗? 是的,当然。由于一些隐私,我必须修复我的数据列的名称。但是结构是正确的 【参考方案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

【讨论】:

以上是关于将行更新到特定列的主要内容,如果未能解决你的问题,请参考以下文章

根据 Id [重复] 将行从一个表更新到另一个表

如何将行数据透视到特定列 db2

更新并附加到特定列中的所有项目

将行插入数据集后的数据库更新

选择列表框选项时将行添加到 Data GridView VB.net

MySQL 工作台:如何将特定列导出为更新语句?