获取表中的最后一项-SQL

时间:2020-03-05 18:43:46  来源:igfitidea点击:

我在SQL Server中有一个历史记录表,该表基本上可以跟踪整个过程中的项目。该项目具有一些固定字段,这些字段在整个过程中不会更改,但是还有一些其他字段,包括状态和ID,它们随着过程步骤的增加而增加。

基本上,我想检索给定批处理引用的每个项目的最后一步。所以如果我做一个

Select * from HistoryTable where BatchRef = @BatchRef

它将返回批次中所有项目的所有步骤,例如

Id      Status  BatchRef        ItemCount
1       1       Batch001        100
1       2       Batch001        110
2       1       Batch001        60
2       2       Batch001        100

但是我真正想要的是:

Id      Status  BatchRef        ItemCount
1       2       Batch001        110
2       2       Batch001        100

编辑:应用程序似乎无法使TABLE标记与Markdown一起使用,并遵循帮助的字母,并且在预览中看起来不错

解决方案

回答

假设表中有一个标识列...

select 
    top 1 <fields> 
from 
    HistoryTable 
where 
    BatchRef = @BatchRef 
order by 
    <IdentityColumn> DESC

回答

以WMD格式化数据的方式解密数据有点困难,但是我们可以利用SQL 2005上的常用表表达式来实现所需的技巧:

with LastBatches as (
    select Batch, max(Id)
    from HistoryTable
    group by Batch
)
select *
from HistoryTable h
    join LastBatches b on b.Batch = h.Batch and b.Id = h.Id

或者子查询(假设子查询中的分组依据有效,我不记得了):

select *
from HistoryTable h
    join (
        select Batch, max(Id)
        from HistoryTable
        group by Batch
    ) b on b.Batch = h.Batch and b.Id = h.Id

编辑:我假设我们要为每个批次的最后一个项目。如果我们只需要一批,那么其他答案(排在前1位和降序)是我们要走的路。

回答

正如已经建议的那样,我们可能想对查询进行重新排序,以使其在另一个方向上进行排序,因此实际上是在获取第一行。然后,我们可能想要使用类似

SELECT TOP 1 ...

如果我们使用的是MSSQL 2k或者更早版本,或者符合SQL的变体

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber = n

用于任何其他版本(或者用于支持标准符号的其他数据库系统),或者

SELECT ... LIMIT 1 OFFSET 0

对于其他一些没有标准SQL支持的变体。

另请参见此问题,以获取有关选择行的其他讨论。使用聚合函数max()可能更快,也可能不会更快,这取决于计算值是否需要表扫描。

回答

我认为吃了分隔符有点难以理解表设计。

处理此问题的基本方法是对固定字段进行GROUP BY,然后为一些不确定的值选择一个MAX(或者MIN)(日期时间通常效果很好)。在情况下,我认为GROUP BY将为BatchRef和ItemCount,而ID将为唯一列。

然后,重新连接到表以获取所有列。就像是:

SELECT * 
FROM HistoryTable
JOIN (
   SELECT 
       MAX(Id) as Id.
       BatchRef,
       ItemCount
   FROM HsitoryTable
   WHERE
       BacthRef = @batchRef
   GROUP BY
       BatchRef,
       ItemCount
 ) as Latest ON
   HistoryTable.Id = Latest.Id

回答

假设项目ID递增编号:

--Declare a temp table to hold the last step for each item id
DECLARE @LastStepForEach TABLE (
Id int,
Status int,
BatchRef char(10),
ItemCount int)

--Loop counter
DECLARE @count INT;
SET @count = 0;

--Loop through all of the items
WHILE (@count < (SELECT MAX(Id) FROM HistoryTable WHERE BatchRef = @BatchRef))
BEGIN
    SET @count = @count + 1;

    INSERT INTO @LastStepForEach (Id, Status, BatchRef, ItemCount)
        SELECT Id, Status, BatchRef, ItemCount
        FROM HistoryTable 
        WHERE BatchRef = @BatchRef
        AND Id = @count
        AND Status = 
        (
            SELECT MAX(Status) 
            FROM HistoryTable 
            WHERE BatchRef = @BatchRef 
            AND Id = @count
        )

END

SELECT * 
FROM @LastStepForEach