Вопрос

У меня есть таблица истории в SQL Server, которая в основном отслеживает элемент в процессе.Элемент имеет несколько фиксированных полей, которые не меняются на протяжении всего процесса, но имеет несколько других полей, включая статус и идентификатор, которые увеличиваются по мере увеличения количества шагов процесса.

По сути, я хочу получить последний шаг для каждого элемента, имеющего ссылку на пакет.Итак, если я сделаю

Select * from HistoryTable where BatchRef = @BatchRef

Он вернет все шаги для всех элементов в пакете, например

Статус идентификатора BatchRef ItemCount
1       1       Batch001        100
1       2       Batch001        110
2       1       Batch001        60
2       2       Batch001        100

Но чего я действительно хочу:

Статус идентификатора BatchRef ItemCount
1       2       Batch001        110
2       2       Batch001        100

Редактировать:Приношу извинения - похоже, не удалось заставить теги TABLE работать с Markdown - внимательно следил за справкой и в предварительном просмотре выглядит нормально.

Это было полезно?

Решение

Трудно разобраться в дизайне вашей таблицы — я думаю, ТАК съели ваши разделители.

Основной способ справиться с этим — сгруппировать по фиксированным полям и выбрать 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

Другие советы

Предполагая, что у вас есть столбец идентификаторов в таблице...

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

Предполагая, что идентификаторы элементов пронумерованы постепенно:

--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
SELECT id, status, BatchRef, MAX(itemcount) AS maxItemcount 
FROM HistoryTable GROUP BY id, status, BatchRef 
HAVING status > 1 

Немного сложно расшифровать ваши данные в том виде, в каком их отформатировала 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() может быть быстрее, а может и нет, в зависимости от того, требует ли вычисление значения сканирования таблицы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top