将行更新到特定列
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】:这是因为更新基本上是逐行完成的,因为在JOIN
ed 数据中,苹果和香蕉位于不同的行。
您需要像这样“跳过”不是更新主题的列的更新:
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 在quantity
或 price
列中有空值。你可以检查这个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
【讨论】:
以上是关于将行更新到特定列的主要内容,如果未能解决你的问题,请参考以下文章