【问题标题】:How Can I Filter SQL Results Based On Row With Last Timestamp?如何根据具有最后时间戳的行过滤 SQL 结果?
【发布时间】:2021-01-10 01:05:40
【问题描述】:

我对 SQL 还很陌生;请原谅这个问题的幼稚。

假设您有一个表,其中每一行都有以下条目,所有这些条目都是 varchar(50):DocumentName、DocumentNumber、Status、PreviousUser、NextUser、Timestamp。时间戳是这样的,字母排序也是按时间顺序排列的。虽然每一行都是唯一的,但不能保证每行都有唯一的 DocumentName 和 DocumentNumber 条目。

我想做一个查询,返回 unique DocumentName、DocumentNumber 和 Status 的所有文档,其中该 DocumentName 和 DocumentNumber 的 last NextUser 条目(由Timestamp) 匹配我拥有的字符串。我将如何将其格式化为查询?

这是一个包含示例返回的示例表,可能有助于澄清我的要求。

+================+================+============+==============+==========+============+
| DocumentName   | DocumentNumber | Status     | PreviousUser | NextUser | Timestamp  |
+================+================+============+==============+==========+============+
| Change Request | 1              | PROCESSING | SSMITH       | MJONES   | 2020 02 01 |
+----------------+----------------+------------+--------------+----------+------------+
| Change Request | 1              | DRAFT      | JDOE         | SSMITH   | 2020 01 01 |
+----------------+----------------+------------+--------------+----------+------------+
| Change Request | 1              | COMPLETE   | SSMITH       | NULL     | 2020 02 22 |
+----------------+----------------+------------+--------------+----------+------------+
| Change Request | 1              | APPROVAL   | MJONES       | SSMITH   | 2020 02 21 |
+----------------+----------------+------------+--------------+----------+------------+
| Change Request | 3              | PROCESSING | JDOE         | SSMITH   | 2020 04 17 |
+----------------+----------------+------------+--------------+----------+------------+
| User Request   | 1              | APPROVAL   | SSMITH       | MJONES   | 2020 01 01 |
+----------------+----------------+------------+--------------+----------+------------+
| User Request   | 1              | REWORK     | MJONES       | SSMITH   | 2020 03 03 |
+----------------+----------------+------------+--------------+----------+------------+
| User Request   | 1              | APPROVAL   | SSMITH       | MJONES   | 2020 03 07 |
+----------------+----------------+------------+--------------+----------+------------+
| User Request   | 7              | DRAFT      | JDOE         | SSMITH   | 2020 03 17 |
+----------------+----------------+------------+--------------+----------+------------+
| User Request   | 7              | APPROVAL   | SSMITH       | MJONES   | 2020 03 19 |
+----------------+----------------+------------+--------------+----------+------------+
| Problem Report | 1              | PROCESSING | JDOE         | SSMITH   | 2020 05 03 |
+----------------+----------------+------------+--------------+----------+------------+
| Problem Report | 1              | DRAFT      | JDOE         | JDOE     | 2020 05 02 |
+----------------+----------------+------------+--------------+----------+------------+
| Problem Report | 9              | COMPLETE   | JDOE         | NULL     | 2020 06 24 |
+----------------+----------------+------------+--------------+----------+------------+
| Problem Report | 13             | DRAFT      | JDOE         | SSMITH   | 2020 07 04 |
+----------------+----------------+------------+--------------+----------+------------+
| Problem Report | 13             | REWORK     | SSMITH       | JDOE     | 2020 07 17 |
+----------------+----------------+------------+--------------+----------+------------+

如果我想匹配 JDOE,我应该返回一行:('Problem Report', 13)。

如果我想匹配 SSMITH,我应该返回两行:('Change Request', 3) 和 ('Problem Report', 1)。

如果我想匹配 MJONES,我应该返回两行:('User Request', 1) 和 ('User Request', 7)。

如果我留下了模棱两可的东西,请告诉我。

【问题讨论】:

  • 向我们展示一些示例表数据和预期结果 - 全部为格式化文本(无图像)。 minimal reproducible example.
  • 我已将其添加到原始帖子中。谢谢。
  • 不相关,但是:在varchar 列中存储时间戳(实际上是日期)是一个非常非常糟糕的主意。你有机会修复损坏的数据模型吗?
  • 我使用 NextUser 列来确定用户。我将来可能有机会修复时间戳,但不会很快。我正在使用 MSSQL Server Server 2008 R2。
  • 能否提供插入语句格式的样本数据?例如,('Change Request', '1', 'PROCESSING', 'SSMITH', 'MJONES', '2020-02-01')

标签: sql sql-server sql-server-2008


【解决方案1】:

您可以做的是使用一个窗口函数,该函数将根据 docName、docNumber 和 status 对条目进行排名,如下所示:

  SELECT
    docName,
    docNumber,
    status,
    prevU,
    nextU,
    ts,
    RANK() OVER (
      PARTITION BY
        docName,
        docNumber,
        status
      ORDER BY
        ts desc
    ) rnk
 FROM docs

基本上,它会针对每个 docName、docNumber 和状态返回一个基于最近日期的排名。例如,根据您的示例数据,您有 docNumber 为“1”的“更改请求”四次不同的时间,每次都有不同的状态。由于这 4 个整体的状态是唯一的,因此它们排名为 1。对于“用户请求”文档编号“1”和状态“批准”两次出现,您将看到日期“2020-03-07”排名为 1因为那是最新的。

样本结果可在此dbfiddle 中找到。您可以对其进行修改以包含所有示例数据,以更好地了解排名的运作方式。

获得完整结果后,您可以查询以下过滤条件:

 where rnk = 1 and nextU = 'name'

上述过滤器将返回该特定用户的最新条目。 Example

另外,请注意,我刚刚更改了示例中的列名,以便于我。

另外,我不完全确定您需要如何对其进行分区,因此您可以根据自己的要求进行修改。

如果它只需要基于 docName 和 docNumber 则只需从 partition by 子句中删除 status 列。这个scenario的结果

【讨论】:

    【解决方案2】:

    在您提供表名后尝试此操作:

    SELECT *
    FROM Abc123 AS a
    WHERE NextUser = @MyUser
    AND 
    EXISTS 
    (
       SELECT 1
       FROM abc123 AS i
       WHERE a.DocumentName = i.DocumentName
       AND a.DocumentNumber = i.DocumentNumber
       GROUP BY i.DocumentName,
           i.DocumentNumber
       HAVING MAX(i.Timestamp) = a.Timestamp
    )
    

    这应该从表中返回最后一个下一个用户接触记录的记录与@MyUser匹配。

    内部查询标识每个文档名称和文档编号的最大时间戳。然后通过名称、编号和时间戳关联外部查询。最后,根据您的参数过滤外部查询结果。

    这应该是可搜索的,并且也可以与表上的任何相关索引一起使用。

    【讨论】:

    • 这似乎真的很好用!谢谢!
    • 很高兴听到它,如果解决了您的问题,请标记答案。
    • 你打赌。再次感谢。
    【解决方案3】:

    这有帮助吗?

    Select DISTINCT DocumentName, DocumentNumber, Status
    from table_name
    WHERE nextuser = 'your string'
      AND timestamp = (Select MAX(timestamp) from table_name)
    

    【讨论】:

    • 不完全是。如果我理解正确,那只会在时间戳与表中的最后一个时间戳匹配时返回一些东西。我只对特定 (DocumentName, DocumentNumber) 对的最后一个时间戳感兴趣。不过,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2021-10-14
    • 2022-01-26
    • 1970-01-01
    • 2019-09-27
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    相关资源
    最近更新 更多