Sql server T-SQL根据座位位置、ID和时间使用以前的值(不一定是之前的值)更新空值
我在win7机器上使用MSMS2008R 我对SQL非常陌生,仍在努力掌握基本原理,它与我过去使用的非常不同 我在获取一些数据时遇到了一些问题。这是我狼吞虎咽之后的样子这只是一个小场景 我需要在MediaId列中搜索空值,这很简单 一旦我找到了这些值,我需要及时搜索在空值的时间戳之前发生的相同位置和logID,并用正确的mediaID替换该空值 我对这个问题有很好的理解,也知道如何用大多数语言来解决这个问题,但是SQL很奇怪,给我带来了很多问题。。。我花了很长时间才把我的数据拿到这个阶段,但我不知道从这里走到哪里。我已经研究了CTE和游标,但仍然不确定如何应用这些方法Sql server T-SQL根据座位位置、ID和时间使用以前的值(不一定是之前的值)更新空值,sql-server,tsql,null,cursor,common-table-expression,Sql Server,Tsql,Null,Cursor,Common Table Expression,我在win7机器上使用MSMS2008R 我对SQL非常陌生,仍在努力掌握基本原理,它与我过去使用的非常不同 我在获取一些数据时遇到了一些问题。这是我狼吞虎咽之后的样子这只是一个小场景 我需要在MediaId列中搜索空值,这很简单 一旦我找到了这些值,我需要及时搜索在空值的时间戳之前发生的相同位置和logID,并用正确的mediaID替换该空值 我对这个问题有很好的理解,也知道如何用大多数语言来解决这个问题,但是SQL很奇怪,给我带来了很多问题。。。我花了很长时间才把我的数据拿到这个阶段,但我不
顺便说一句,很抱歉,由于我的工作性质,我无法发布我的任何代码,我认为这足够让您思考。如果您没有连续的空值并且正在使用SQL Server 2012+,那么您可以使用lag: 如果一行中最多有两个空值,则可以使用简单的修改:
select time, location, logid,
coalesce(mediaid,
lag(mediaid) over (partition by location, logid, time),
lag(mediaid, 2) over (partition by location, logid, time)
) as mediaid
from t;
除此之外,您还希望SQL Server在lag上实现IGNORE NULLS选项。除此之外,或在SQL Server的早期版本中,您可以执行以下操作:
select t.time, t.location, t.logid, tprev.mediaid
from t outer apply
(select top 1 t2.mediaid
from t t2
where t2.location = t.location and t2.logid = t.logid and
t2.time <= t.time and t2.mediaid is not null
order by t2.time desc
) tprev
您可以使用交叉应用和顶部:
另一种方法是:
SELECT A.locationid,
A.logid,
A.time,
COALESCE(A.mediaid, B.mediaid) AS MediaID
FROM tbl A
JOIN (SELECT locationid,logid,time,mediaid
FROM (SELECT Row_number()
OVER(partition BY locationid, logid ORDER BY time DESC) AS rn,*
FROM tbl
WHERE mediaid IS NOT NULL)t
WHERE t.rn = 1)B
ON A.locationid = B.locationid
AND A.logid = B.logid
一个完整的例子:
-- delete test table
drop table mediaTable
go
-- create test table
create table mediaTable (
[Time] DateTime not null,
Location varchar(15) not null,
logId int not null,
mediaId int null
)
go
-- add some test data
insert into mediaTable values
(getdate(), '12K', 234499, 2018334),
(dateadd(day,1,getdate()), '12K', 234499, 100),
(dateadd(day,1,getdate()), '58', 234499, -1),
(dateadd(day,2,getdate()), '12K', 234499, null ),
(dateadd(day,3,getdate()), 'ht66', 2001, 10 ),
(dateadd(day,4,getdate()), 'ht66', 2001, 20 ),
(dateadd(day,5,getdate()), 'ht66', 2001, 30 ),
(dateadd(day,6,getdate()), 'ht66', 2001, null )
go
-- show data before update
select * from mediaTable;
-- update data
With cte ( [Time], Location, logId, mediaId ) As (
Select [Time], Location, logId, mediaId From mediaTable Where ( mediaId Is Null )
)
Update mediaTable Set
mediaId = b.mediaId
From
mediaTable As a
Inner Join cte As c On ( a.Location = c.Location ) And ( a.logId = c.logId )
Cross Apply (
Select Top 1 mediaId From mediaTable Where ( Location = c.Location ) And ( logId = c.logId ) And ( MediaId Is Not Null ) Order By [Time] Desc
) As b
Where
( a.mediaId Is Null )
-- show data after update
select * from mediaTable;
编辑
这似乎更快:
Update a Set
a.mediaId = b.mediaId
From
#mediaTable As a
Cross Apply (
Select Top 1 mediaId
From #mediaTable
Where
( Location = a.Location )
And ( logId = a.logId )
And ( a.mediaId Is Null )
And ( mediaId Is Not Null )
Order By [Time] Desc
) As b
您可以使用子查询,使用以下代码使用以前的值更新列:
UPDATE t
SET t.mediaId = (
SELECT TOP 1
mediaId
FROM
YourTable s
WHERE
s.LogId = t.LogId
AND s.Location = t.Location
AND s.Time < t.Time
ORDER BY
[Time] DESC)
FROM
YourTable t
WHERE
t.mediaId IS NULL
这些答案对你有用吗?如果是的话,你可以请一位。这将帮助那些跟随你的人。是的,我接受了它,尽管我仍然很好奇尝试其他的技巧。非常感谢您抽出时间。嘿,戈登,谢谢您的快速回复。不幸的是,我使用的是2008 R,它不包含滞后函数。非常优雅的方法knkarthick24,但它没有给我正确的值,它正在向mediaId添加一个值。。。。我会把它弄得乱七八糟,看看它是否管用。谢谢迪,非常感谢你。这很好,正是我所需要的。。。不管您如何评论其中的一些步骤,sql对我来说仍然非常陌生。
Update a Set
a.mediaId = b.mediaId
From
#mediaTable As a
Cross Apply (
Select Top 1 mediaId
From #mediaTable
Where
( Location = a.Location )
And ( logId = a.logId )
And ( a.mediaId Is Null )
And ( mediaId Is Not Null )
Order By [Time] Desc
) As b
UPDATE t
SET t.mediaId = (
SELECT TOP 1
mediaId
FROM
YourTable s
WHERE
s.LogId = t.LogId
AND s.Location = t.Location
AND s.Time < t.Time
ORDER BY
[Time] DESC)
FROM
YourTable t
WHERE
t.mediaId IS NULL