SQL:根据条件填充前一行值的空单元格?
请将此视为高优先级请求。需要帮助
请求高代表用户链接(http://i.imgur.com/P4UOiMz.jpg)
我需要制作专栏" OXY_ID_NEW"在下表中使用SQL。这在SQL 2008R2或SQL 2012或Amazon REDSHIFT中是否可行?
SQL TABLE图像(http://i.imgur.com/P4UOiMz.jpg)
基本上,我想把空填充#34; OXY_ID"具有该ID的最后已知Oxy_id的单元格,如' OXY_ID_NEW'列。
答案 0 :(得分:2)
可能像
coalesce(lag(oxy_id) over (partition by id order by number), oxy_id)
..假设id,number cols实际上增加..在截图中看起来它们重复,在这种情况下你需要提供整个表定义。
答案 1 :(得分:0)
只要你拥有它,gordy给出的LAG示例是最简单的。请注意,您无法直接使用它来更新表格。窗口函数只能出现在SELECT或ORDER BY子句中,因此您需要一个临时表。
对于旧版本,您需要一个游标。类似的东西:
declare @demo table
(
id varchar (10),
number int,
oxy_id varchar(2)
)
INSERT INTO @demo VALUES ('308_2123', 36, 'ZY')
INSERT INTO @demo VALUES ('308_2123', 36, NULL)
INSERT INTO @demo VALUES ('308_2123', 37, NULL)
INSERT INTO @demo VALUES ('308_2123', 37, NULL)
INSERT INTO @demo VALUES ('308_2123', 38, 'WY')
INSERT INTO @demo VALUES ('308_2123', 38, 'WY')
INSERT INTO @demo VALUES ('308_2123', 38, NULL)
INSERT INTO @demo VALUES ('308_2123', 39, NULL)
INSERT INTO @demo VALUES ('309_5647', 30, 'AB')
INSERT INTO @demo VALUES ('309_5647', 30, NULL)
INSERT INTO @demo VALUES ('309_5647', 31, NULL)
INSERT INTO @demo VALUES ('309_5647', 32, 'BC')
INSERT INTO @demo VALUES ('310_8897', 20, 'CD')
INSERT INTO @demo VALUES ('310_8897', 21, 'DC')
INSERT INTO @demo VALUES ('310_8897', 22, NULL)
INSERT INTO @demo VALUES ('310_8897', 23, NULL)
INSERT INTO @demo VALUES ('310_8897', 23, NULL)
INSERT INTO @demo VALUES ('311_6789', 1, NULL)
INSERT INTO @demo VALUES ('311_6789', 1, NULL)
INSERT INTO @demo VALUES ('311_6789', 2, 'EF')
INSERT INTO @demo VALUES ('311_6789', 3, 'GH')
INSERT INTO @demo VALUES ('311_6789', 3, NULL)
INSERT INTO @demo VALUES ('312_9874', 1, 'HK')
INSERT INTO @demo VALUES ('312_9874', 1, 'KY')
INSERT INTO @demo VALUES ('312_9874', 1, NULL)
INSERT INTO @demo VALUES ('312_9874', 1, 'YY')
DECLARE @id varchar(10)
DECLARE @oxy_ID varchar(2)
declare @prevOxyID varchar(10) = NULL
declare @number int
DECLARE @previd varchar(10) = NULL
DECLARE cur CURSOR FOR
(SELECT d.id, d.number, d.oxy_id FROM @demo d)
OPEN cur
FETCH NEXT FROM cur into
@id, @number, @oxy_id
WHILE @@FETCH_STATUS = 0
BEGIN
IF @oxy_id IS NULL
BEGIN
if @prevOxyID IS NOT NULL
BEGIN
IF @id = @previd
BEGIN
UPDATE @demo SET oxy_id = @prevOxyID
WHERE id = @id AND number = @number AND oxy_id IS NULL
END
ELSE
BEGIN
SET @prevOxyID = NULL
END
END
SET @previd = @id
END
ELSE
BEGIN
SET @previd = @id
SET @prevOxyID = @oxy_ID
END
FETCH NEXT FROM cur into
@id, @number, @oxy_id
END
close cur
deallocate cur
SELECT * FROM @demo
请注意,您无法在光标中使用order by。数据必须已按照图像上显示的顺序排列。如果表中的数据不按此顺序再次,则需要使用临时表,其中记录以正确的顺序插入,然后在临时表上执行游标,最后从临时表更新原始表之一。
修改
确定没有游标版本。正如gordy所提到的,LAG的问题是重复的数字。同样的问题限制了UPDATE的使用,因为没有行的唯一标识符。相反,我必须将结果插入临时表,删除原件,然后从temp重新插入。如果你确实有一个唯一的密钥,那么请替换此删除并插入UPDATE。下面的解决方案,虽然有点啰嗦,但确实解决了问题,根据我的研究应该可以使用Amazon Redshift,但我无法进行测试。我不会重复插入,请从上面复制。
declare @demo table
(
id varchar (10),
number int,
oxy_id varchar(2)
)
create table allrownums
(
id varchar (10),
number int,
oxy_id varchar(2),
rownum int
)
INSERT INTO allrownums
SELECT id, number, oxy_id, ROW_NUMBER() OVER (ORDER BY id, number) AS rownum
FROM @demo;
create table allnotnullrows
(
id varchar (10),
number int,
oxy_id varchar(2),
rownum int
)
INSERT INTO allnotnullrows
SELECT * FROM allrownums
WHERE oxy_id IS NOT NULL
create table maxrownums
(
id varchar (10),
rownum int,
maxrownum int
)
INSERT INTO maxrownums
SELECT a.id, a.rownum, Max(n.rownum)
FROM allrownums a INNER JOIN allnotnullrows n
ON n.id = a.id WHERE a.rownum >= n.rownum
GROUP BY a.id, a.rownum
create table tempresults
(
id varchar (10),
number int,
oxy_id varchar(2)
)
INSERT INTO tempresults
SELECT a.id, a.number, coalesce(a.oxy_id, n.oxy_id) as oxy_id
FROM allrownums a
LEFT JOIN maxrownums m
ON m.rownum = a.rownum
LEFT JOIN allnotnullrows n
ON a.id = n.id
and n.rownum = m.maxrownum
DELETE FROM @demo;
INSERT INTO @demo SELECT * FROM tempresults;
DROP TABLE tempresults;
DROP TABLE allrownums;
DROP TABLE allnotnullrows;
DROP TABLE maxrownums;
SELECT * FROM @demo;
答案 2 :(得分:0)
应该在SQL 2008中工作(我无法测试,但CROSS APPLY在SQL 2008中有效)
CREATE TABLE #table1( ID INT, Number INT, OXY_ID VARCHAR( 2 ))
INSERT INTO #table1
VALUES
( 1, 23, 'AD' ),
( 2, 23, 'XY' ),
( 3, 23, '' ),
( 4, 23, '' ),
( 5, 23, 'MY' ),
( 6, 23, '' ),
( 7, 23, 'ZY' )
CREATE INDEX IX_table1__ID ON #table1( ID, OXY_ID )
SELECT a.*, c.OXY_ID AS OXY_ID_New
FROM #table1 AS a
CROSS APPLY
( SELECT TOP 1 ID, OXY_ID
FROM #table1 AS b
WHERE OXY_ID <> '' AND a.ID >= b.ID
ORDER BY ID DESC ) AS c
评论:
应该比光标快很多。
与此相比, LAG
解决方案更加优雅。