SQL 获取每行最后一次出现的字段

SQL Get Last Occurrence of Field Against Each Row

如何像这样添加 LastDocumentID 列:

+------------+-----------+----------------+
| DocumentID | Reference | LastDocumentID |
+------------+-----------+----------------+
|          1 | A         | NULL           |
|          2 | A         | 1              |
|          3 | A         | 2              |
|          4 | B         | NULL           |
|          5 | B         | 4              |
|          6 | C         | NULL           |
|          7 | C         | 6              |
|          8 | C         | 7              |
|          9 | C         | 8              |
+------------+-----------+----------------+

table 可能是随机顺序,但在最后一个文档 ID 中,我基本上希望它获得小于该行引用的该行文档 ID 的最大文档 ID。

在 SQL Server 2012+ 中,您可以使用 lag()。在 SQL Server 2008 中,您可以使用关联子查询或外部应用。这是一种方法:

select documentid, reference,
       (select top 1 documentid
        from table t2
        where t2.reference = t.reference and
              t2.documentid < t.documentid
        order by documentid desc
       ) as LastDocumentId
from table t;

我被要求取消删除,但有以下警告...对于 SQL 大于 2008 的服务器版本:

您可以使用 Window 函数完成此操作

SELECT
    DocumentID,
    Reference,
    MAX(DocumentID) OVER (PARTITION BY Reference ORDER BY DocumentID ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS LastDocumentID
FROM
    <table>

那条较长的行是 window 函数将从由您的引用字段分区的行组中获取 max(documentid),并受该引用的所有先前文档 ID 的限制,不包括当前文档。

您可以通过这种方式从 "last document" 中获取任何值:

SELECT
   D.DocumentID,
   D.Reference,
   LastDocumentID = R.DocumentID
FROM
   dbo.Documents D
   OUTER APPLY (
      SELECT TOP 1 *
      FROM dbo.Documents R
      WHERE
         D.Reference = R.Reference
         AND R.DocumentID < D.DocumentID
      ORDER BY R.DocumentID DESC
   ) R
;

See this working in a SQL Fiddle

虽然与在 WHERE 子句中仅计算子查询中的列值的类似方法具有相同的逻辑,但这允许您从以前的文档中提取多个列,并演示 OUTER APPLY。如果您想要等效的 INNER 联接(不包括没有先前的行),请更改为 CROSS APPLY

作为参考,这是执行此操作的单值方法。你基本上把OUTER APPLY中包含的查询放到括号里,而且只有select一列:

SELECT
   D.DocumentID,
   D.Reference,
   LastDocumentID = (
      SELECT TOP 1 R.DocumentID
      FROM dbo.Documents R
      WHERE
         D.Reference = R.Reference
         AND R.DocumentID < D.DocumentID
      ORDER BY R.DocumentID DESC
   )
FROM
   dbo.Documents D
;

或者,您可以只使用 Max:

SELECT
   D.DocumentID,
   D.Reference,
   LastDocumentID = (
      SELECT Max(R.DocumentID)
      FROM dbo.Documents R
      WHERE
         D.Reference = R.Reference
         AND R.DocumentID < D.DocumentID
   )
FROM
   dbo.Documents D
;

如果您使用的是 SQL Server 2012 及更高版本,您可以使用其可用于窗口函数的更高级语法以这种方式执行此操作:

SELECT
    D.DocumentID,
    D.Reference,
    LastDocumentID = Max(D.DocumentID) OVER (
       PARTITION BY D.Reference
       ORDER BY D.DocumentID ASC
       ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
    )
FROM
    dbo.Documents D
;
如果可以的话,

LAG 可能会更有效率。但是当 MAX 效果很好时,没有特别的理由使用 TOP

select
    documentid, reference,
    (
        select max(documentid) from table as t2
        where t2.reference = t1.reference and t2.documentid < t1.documentid
    )
from table as t1;