这是我的挑战: 我有一个日志表,每次更改记录时都会添加一条新记录,但会为每条记录中的每个未更改值设置一个NULL值。换句话说,仅设置更改的值,每行中其余未更改的字段仅具有NULL值。 现在我想用上面的值替换每个NULL值,这些值不是NULL值,如下所示:
源表:Task_log
ID Owner Status Flag
1 Bob Registrar T
2 Sue NULL NULL
3 NULL NULL F
4 Frank Admission T
5 NULL NULL F
6 NULL NULL T
所需的输出表:Task_log
ID Owner Status Flag
1 Bob Registrar T
2 Sue Registrar T
3 Sue Registrar F
4 Frank Admission T
5 Frank Admission F
6 Frank Admission T
如何编写将生成所需输出表的查询?
答案 0 :(得分:2)
一个SQLServer 2012的新窗口函数是FIRST_VALUE
,它有一个非常直接的名称,它可以通过OVER
子句进行分区,在使用它之前必须划分数据块中的每一列,当找到值时,列的块开始。
With Block As (
Select ID
, Owner
, OBlockID = SUM(Case When Owner Is Null Then 0 Else 1 End)
OVER (ORDER BY ID)
, Status
, SBlockID = SUM(Case When Status Is Null Then 0 Else 1 End)
OVER (ORDER BY ID)
, Flag
, FBlockID = SUM(Case When Flag Is Null Then 0 Else 1 End)
OVER (ORDER BY ID)
From Task_log
)
Select ID
, Owner = FIRST_VALUE(Owner) OVER (PARTITION BY OBlockID ORDER BY ID)
, Status = FIRST_VALUE(Status) OVER (PARTITION BY SBlockID ORDER BY ID)
, Flag = FIRST_VALUE(Flag) OVER (PARTITION BY FBlockID ORDER BY ID)
FROM Block
UPDATE
查询很容易导出
答案 1 :(得分:0)
正如我在评论中提到的,我会尝试修复创建记录而不是修复垃圾数据的过程。如果这不是一个选项,下面的代码应该指向正确的方向。
UPDATE t1
set t1.owner = COALESCE(t1.owner, t2.owner),
t1.Status = COALESCE(t1.status, t2.status),
t1.Flag = COALESCE(t1.flag, t2.flag)
FROM Task_log as t1
INNER JOIN Task_log as t2
ON t1.id = (t1.id + 1)
where t1.owner is null
OR t1.status is null
OR t1.flag is null
答案 2 :(得分:0)
我可以想到几种方法。
您可以将COALESCE与数组聚合函数结合使用。不幸的是,它看起来并不像SQL Server本身支持array_agg(尽管有些nice people have developed some workarounds)。
您还可以为每列使用子选择。
SELECT id,
(SELECT TOP 1 FROM (SELECT owner FROM ... WHERE id = outer_id AND owner IS NOT NULL order by ID desc )) AS owner,
-- other columns
您也可以使用窗口函数执行某些操作。
答案 3 :(得分:0)
香草解决方案将是:
select id
, owner
, coalesce(owner, ( select owner from t t2
where id = (select max(id) from t t3
where id < t1.id and owner is not null))
) as new_owner
, flag
, coalesce(flag, ( select flag from t t2
where id = (select max(id) from t t3
where id < t1.id and flag is not null))
) as new_flag
from t t1
相当低效,但应该适用于大多数DBMS