【问题标题】:How to union two tables to override empty values and order by timestamp?如何合并两个表以覆盖空值并按时间戳排序?
【发布时间】:2018-11-10 18:12:48
【问题描述】:

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

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 项目中,并使用 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

【问题讨论】:

  • 我不明白为什么您的预期输出中缺少第一个表中时间为 2018-02-21 01:06:01.000 的行。你能解释一下吗?
  • @Larnu 你什么意思?这是最后的记录。

标签: sql sql-server database linq


【解决方案1】:

老实说,一个完整的猜测,但也许......

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;

【讨论】:

    【解决方案2】:

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

    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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-04
      • 1970-01-01
      • 2020-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-26
      • 2015-09-17
      相关资源
      最近更新 更多