如何结合两个表来覆盖空值并按时间戳排序?

时间:2018-05-31 16:52:52

标签: sql sql-server database linq

我有两个表来表示用户的状态以及状态更改的时间戳。我有这样的设置:

StatusTable

user_id          updated_status   timestamp
---------------- ---------------- -----------------------
1617             PENDING          2018-02-21 01:06:01.000
1617             DONE             2018-02-21 01:01:01.000
1617             PENDING          2018-02-06 01:06:01.000


OverrideStatusTable

user_id          updated_status                   timestamp
---------------- -------------------------------- -----------------------
1617                                              2018-02-23 08:12:40.297
1617             DONE-A                           2018-02-14 15:10:49.717
1617             DONE-B                           2018-02-14 15:10:35.850
1617                                              2018-02-14 15:09:23.973
1617             DONE-A                           2018-02-14 14:59:30.113

我尝试将两个表合并为一个按时间戳排序的结果,其中OverriddeStatusTable中的值覆盖StatusTable中的值,但OverrideStatus表中的updated_status为空时除外,其中最新状态来自而是显示StatusTable,但显示OverrideStatusTable中已清除值的时间戳。所以我希望我的查询结果看起来像这样:

user_id          updated_status   timestamp
---------------- ---------------- -----------------------
1617             PENDING          2018-02-23 08:12:40.297
1617             DONE-A           2018-02-14 15:10:49.717
1617             DONE-B           2018-02-14 15:10:35.850
1617             PENDING          2018-02-14 15:09:23.973
1617             DONE-A           2018-02-14 14:59:30.113
1617             PENDING          2018-02-06 01:06:01.000

我试图弄清楚最好的方法是什么 - 请记住,我最终会在我的.NET项目中将这两个表作为DataTables加载并使用它们查询它们LINQ。但是现在我只想确保我的逻辑正确。

现在我的查询设置如下:

select *
from StatusTable
where user_id='1617'
UNION
select *
from OverrideStatusTable
where user_id='1617' and updated_status != ''
order by update_date desc

但这并没有让我接近我想要的东西。输出结果是:

user_id          updated_status                   timestamp
---------------- -------------------------------- -----------------------
1617             PENDING                          2018-02-21 01:06:01.000
1617             DONE                             2018-02-21 01:01:01.000
1617             DONE-A                           2018-02-14 15:10:49.717
1617             DONE-B                           2018-02-14 15:10:35.850
1617             DONE-A                           2018-02-14 14:59:30.113
1617             PENDING                          2018-02-06 01:06:01.000

有人可以帮帮我吗?谢谢!

2 个答案:

答案 0 :(得分:0)

一个完整的猜测,如果我是诚实的,但也许......

USE Sandbox;
GO

CREATE TABLE StatusTable (user_id int,
                          updated_status varchar(10),
                          [timestamp] datetime2(3));
GO
CREATE TABLE OverrideStatusTable (user_id int,
                          updated_status varchar(10),
                          [timestamp] datetime2(3));
GO

INSERT INTO StatusTable
VALUES
(1617             ,'PENDING',          '2018-02-21 01:06:01.000'),
(1617             ,'DONE',             '2018-02-21 01:01:01.000'),
(1617             ,'PENDING',          '2018-02-06 01:06:01.000');

INSERT INTO OverrideStatusTable
VALUES
(1617             ,NULL,                               '2018-02-23 08:12:40.297'),
(1617             ,'DONE-A',                           '2018-02-14 15:10:49.717'),
(1617             ,'DONE-B',                           '2018-02-14 15:10:35.850'),
(1617             ,NULL,                               '2018-02-14 15:09:23.973'),
(1617             ,'DONE-A',                           '2018-02-14 14:59:30.113');
GO
SELECT *
FROM (SELECT TOP 1
             user_id,
             updated_status,
             [timestamp]
      FROM StatusTable
      WHERE user_id = 1617
      ORDER BY [Timestamp] ASC) ST
UNION
SELECT user_id,
       ISNULL(updated_status,'PENDING'),
       [timestamp]
FROM OverrideStatusTable OST
WHERE user_id = 1617
ORDER BY [timestamp] DESC;

GO
DROP TABLE StatusTable;
DROP TABLE OverrideStatusTable;

答案 1 :(得分:0)

您的结果可以通过以下方式获得:

select ost.userid, ost.status, ost.timestamp
from OverrideStatusTable ost
where status is not null
union all
select ost.userid,
       (select top 1 st.status
        from statustable st
        where st.user_id = ost.user_id and
              st.timetamp <= ost.timestamp
       ) as status,
       ost.timestamp
from OverrideStatusTable ost
where status is null
union all
select st.*
from statustable st
where timestamp > (select max(ost.timestamp) from OverrideStatusTable ost where ost.userid = st.userid);