Sql server T-SQL根据座位位置、ID和时间使用以前的值(不一定是之前的值)更新空值

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很奇怪,给我带来了很多问题。。。我花了很长时间才把我的数据拿到这个阶段,但我不

我在win7机器上使用MSMS2008R

我对SQL非常陌生,仍在努力掌握基本原理,它与我过去使用的非常不同

我在获取一些数据时遇到了一些问题。这是我狼吞虎咽之后的样子这只是一个小场景

我需要在MediaId列中搜索空值,这很简单

一旦我找到了这些值,我需要及时搜索在空值的时间戳之前发生的相同位置和logID,并用正确的mediaID替换该空值

我对这个问题有很好的理解,也知道如何用大多数语言来解决这个问题,但是SQL很奇怪,给我带来了很多问题。。。我花了很长时间才把我的数据拿到这个阶段,但我不知道从这里走到哪里。我已经研究了CTE和游标,但仍然不确定如何应用这些方法


顺便说一句,很抱歉,由于我的工作性质,我无法发布我的任何代码,我认为这足够让您思考。

如果您没有连续的空值并且正在使用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