Hab*_*man 3 sql-server t-sql sql-server-2008-r2
我是 SQL Server 世界的新手。在下面的示例中,我有两家公司:
每个公司只有一个条目具有列的值power1, power2, power3。
我需要更新表,以便每个公司的所有列都有一个值。换句话说,我需要更新所有空白(空)值。
使用虚构数据的示例:
Create Table #Rentarious
(
c1 varchar(200)
,yryryryr datetime
,power1 varchar(200)
,power2 varchar(200)
,power3 varchar(200)
)
Insert Into #Rentarious VALUES
('Building Blocks','2016','Red','Blue','Green')
,('Red Cement', '2012', 'Pink','Purple','Orange')
Insert Into #Rentarious(c1, yryryryr) VALUES
('Building Blocks', '2012')
,('Building Blocks', '2013')
,('Building Blocks', '2014')
,('Red Cement', '2016')
,('Red Cement', '2011')
Run Code Online (Sandbox Code Playgroud)
编写更新语句以将列的空值更新为表power1, power2, power3中已列出的值的语法是什么?
编写更新语句以
power1, power2, power3使用表中已列出的值更新字段的空值的语法是什么?
我认为这意味着每个公司的空值都应该根据从一个填充条目中获取的值进行填充,正如您在帖子的其他地方所说,每个公司都有。因此,在伪代码中,您的 UPDATE 语句需要如下所示:
UPDATE
#Rentarious
SET
power1 = power1 from the same company’s populated row,
power2 = power2 from the same company’s populated row,
power3 = power3 from the same company’s populated row
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
Run Code Online (Sandbox Code Playgroud)
实现上述模式的一种方法是使用相关子查询:
UPDATE
#Rentarious
SET
power1 = (SELECT power1 FROM #Rentarious AS src WHERE src.c1 = #Rentarious.c1 AND src.power1 IS NOT NULL),
power2 = (SELECT power2 FROM #Rentarious AS src WHERE src.c1 = #Rentarious.c1 AND src.power2 IS NOT NULL),
power3 = (SELECT power3 FROM #Rentarious AS src WHERE src.c1 = #Rentarious.c1 AND src.power3 IS NOT NULL)
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
Run Code Online (Sandbox Code Playgroud)
虽然这可行,但这样的更新可能效率不高,因为同一个表会额外接触三次以获取源值。由于您知道每家公司的非空值都存储在一行中,因此您可以使用派生表和专有的“使用连接更新”语法,在一次额外的表中获取它们:
UPDATE
#Rentarious
SET
power1 = sub.power1,
power2 = sub.power2,
power3 = sub.power3
FROM
(
SELECT
c1,
power1,
power2,
power3
FROM
#Rentarious
WHERE power1 IS NOT NULL
AND power2 IS NOT NULL
AND power3 IS NOT NULL
) AS sub
WHERE #Rentarious.c1 = sub.c1
AND #Rentarious.power1 IS NULL
AND #Rentarious.power2 IS NULL
AND #Rentarious.power3 IS NULL
;
Run Code Online (Sandbox Code Playgroud)
您还可以重写它以使用显式 JOIN 语法:
UPDATE
tgt
SET
power1 = src.power1,
power2 = src.power2,
power3 = src.power3
FROM
#Rentarious AS tgt
INNER JOIN
(
SELECT
c1,
power1,
power2,
power3
FROM
#Rentarious
WHERE power1 IS NOT NULL
AND power2 IS NOT NULL
AND power3 IS NOT NULL
) AS sub
ON tgt.c1 = sub.c1
WHERE tgt.power1 IS NULL
AND tgt.power2 IS NULL
AND tgt.power3 IS NULL
;
Run Code Online (Sandbox Code Playgroud)
如您所见,两种变体中只有一个子查询,它提供所有三个值来填充其他行。
但请注意,也可以在不进行任何额外扫描的情况下解决此问题。首先,如果这是一个 SELECT 语句,您可以使用窗口聚合函数返回每一行中填充行的值,如下所示:
SELECT
c1,
yryryryr,
power1,
power2,
power3,
populatedPower1 = MAX(power1) OVER (PARTITION BY c1),
populatedPower2 = MAX(power2) OVER (PARTITION BY c1),
populatedPower3 = MAX(power3) OVER (PARTITION BY c1)
FROM
#Rentarious
;
Run Code Online (Sandbox Code Playgroud)
该MAX功能可在这种情况下,因为它只返回跨越指定集合中的非空值中的最大值。在您的情况下,c1在这三种情况中的每一种情况下,每个分区都只有一个非空值,因此该函数将返回该值。这将是您问题中示例的查询结果:
c1 yryryryr power1 power2 power3 populatedPower1 populatedPower2 populatedPower3
--------------- ---------- ------ ------ ------ --------------- --------------- ---------------
Building Blocks 2012-01-01 NULL NULL NULL Red Blue Green
Building Blocks 2013-01-01 NULL NULL NULL Red Blue Green
Building Blocks 2014-01-01 NULL NULL NULL Red Blue Green
Building Blocks 2016-01-01 Red Blue Green Red Blue Green
Red Cement 2012-01-01 Pink Purple Orange Pink Purple Orange
Red Cement 2016-01-01 NULL NULL NULL Pink Purple Orange
Red Cement 2011-01-01 NULL NULL NULL Pink Purple Orange
Run Code Online (Sandbox Code Playgroud)
所以唯一剩下的就是
SET
power1 = populatedPower1,
power2 = populatedPower2,
power3 = populatedPower3
Run Code Online (Sandbox Code Playgroud)
而在 SQL Server 中确实可以这样做,因为上述 SELECT 查询的结果可以用作您的 UPDATE 语句的目标。您可以将其用作派生表:
UPDATE
tgt
SET
power1 = populatedPower1,
power2 = populatedPower2,
power3 = populatedPower3
FROM
(
SELECT
c1,
yryryryr,
power1,
power2,
power3,
populatedPower1 = MAX(power1) OVER (PARTITION BY c1),
populatedPower2 = MAX(power2) OVER (PARTITION BY c1),
populatedPower3 = MAX(power3) OVER (PARTITION BY c1)
FROM
#Rentarious
) AS tgt
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
Run Code Online (Sandbox Code Playgroud)
或将其实现为 CTE(Common Table Expression)并使用 CTE 的别名作为目标:
WITH tgt AS
(
SELECT
c1,
yryryryr,
power1,
power2,
power3,
populatedPower1 = MAX(power1) OVER (PARTITION BY c1),
populatedPower2 = MAX(power2) OVER (PARTITION BY c1),
populatedPower3 = MAX(power3) OVER (PARTITION BY c1)
FROM
#Rentarious
)
UPDATE
tgt
SET
power1 = populatedPower1,
power2 = populatedPower2,
power3 = populatedPower3
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
Run Code Online (Sandbox Code Playgroud)
两者都可以很好地工作,并导致所有空值都替换为相应的值,即:
c1 yryryryr power1 power2 power3
--------------- ---------- ------ ------ ------
Building Blocks 2016-01-01 Red Blue Green
Red Cement 2012-01-01 Pink Purple Orange
Building Blocks 2012-01-01 NULL NULL NULL
Building Blocks 2013-01-01 NULL NULL NULL
Building Blocks 2014-01-01 NULL NULL NULL
Red Cement 2016-01-01 NULL NULL NULL
Red Cement 2011-01-01 NULL NULL NULL
Run Code Online (Sandbox Code Playgroud)
对此:
c1 yryryryr power1 power2 power3
--------------- ---------- ------ ------ ------
Building Blocks 2016-01-01 Red Blue Green
Red Cement 2012-01-01 Pink Purple Orange
Building Blocks 2012-01-01 Red Blue Green
Building Blocks 2013-01-01 Red Blue Green
Building Blocks 2014-01-01 Red Blue Green
Red Cement 2016-01-01 Pink Purple Orange
Red Cement 2011-01-01 Pink Purple Orange
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21604 次 |
| 最近记录: |