获取表中的最后一项 - SQL

时间:2008-08-27 10:13:16

标签: sql sql-server database tsql

我在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

编辑:Appologies - 似乎无法让TABLE标签与Markdown一起使用 - 按照字母的帮助,在预览中看起来很好

6 个答案:

答案 0 :(得分:10)

假设表格中有一个标识栏......

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

答案 1 :(得分:6)

很难理解你的餐桌设计 - 我认为这样你的分隔符。

处理此问题的基本方法是对固定字段进行GROUP BY,并为某些unqiue值选择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

答案 2 :(得分:1)

假设Item Ids递增编号:

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

答案 3 :(得分:1)

SELECT id, status, BatchRef, MAX(itemcount) AS maxItemcount 
FROM HistoryTable GROUP BY id, status, BatchRef 
HAVING status > 1 

答案 4 :(得分:0)

用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和下降顺序)是要走的路。

答案 5 :(得分:0)

如前所述,您可能希望重新排序查询以在另一个方向对其进行排序,以便实际获取第一行。然后你可能想要使用像

这样的东西
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支持的其他一些变体。

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