4

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

基本上我想检索给定批次参考的每个项目的最后一步。所以如果我做一个

Select * from HistoryTable where BatchRef = @BatchRef

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

Id 状态 BatchRef ItemCount
1 1 批次001 100
1 2 批次001 110
2 1 批次001 60
2 2 批次001 100

但我真正想要的是:

Id 状态 BatchRef ItemCount
1 2 批次001 110
2 2 批次001 100

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

4

6 回答 6

10

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

select 
    top 1 <fields> 
from 
    HistoryTable 
where 
    BatchRef = @BatchRef 
order by 
    <IdentityColumn> DESC
于 2008-08-27T10:15:55.543 回答
7

很难理解您的表格设计 - 我认为 SO 吃了您的分隔符。

处理此问题的基本方法是按您的固定字段分组,并为某些 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
于 2008-08-27T10:29:03.920 回答
1

假设项目 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
于 2008-08-31T08:52:31.640 回答
1
SELECT id, status, BatchRef, MAX(itemcount) AS maxItemcount 
FROM HistoryTable GROUP BY id, status, BatchRef 
HAVING status > 1 
于 2011-10-31T02:19:10.117 回答
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

或子查询(假设子查询中的 group by 有效 - 我不记得了):

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 并按降序排列)是可行的方法。

于 2008-08-27T10:19:08.203 回答
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 支持的其他一些变体。

有关选择行的其他讨论,另请参阅此问题。根据计算值是否需要表扫描,使用聚合函数 max() 可能会或可能不会更快。

于 2008-08-27T10:28:33.907 回答