Получить последний элемент в таблице - SQL - PullRequest
4 голосов
/ 27 августа 2008

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

Как правило, я хочу получить последний шаг для каждого элемента с заданной ссылкой на пакет. Так что, если я сделаю

Select * from HistoryTable where BatchRef = @BatchRef

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

<b>Id      Status  BatchRef        ItemCount</b>
1       1       Batch001        100
1       2       Batch001        110
2       1       Batch001        60
2       2       Batch001        100

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

<b>Id      Status  BatchRef        ItemCount</b>
1       2       Batch001        110
2       2       Batch001        100

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

Ответы [ 6 ]

10 голосов
/ 27 августа 2008

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

select 
    top 1 <fields> 
from 
    HistoryTable 
where 
    BatchRef = @BatchRef 
order by 
    <IdentityColumn> DESC
6 голосов
/ 27 августа 2008

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

Основной способ справиться с этим - это GROUP BY ваших фиксированных полей и выбрать MAX (или MIN) для некоторого нестандартного значения (datetime обычно работает хорошо). В вашем случае я думаю , что 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
1 голос
/ 31 октября 2011
SELECT id, status, BatchRef, MAX(itemcount) AS maxItemcount 
FROM HistoryTable GROUP BY id, status, BatchRef 
HAVING status > 1 
1 голос
/ 31 августа 2008

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

--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
0 голосов
/ 27 августа 2008

Как уже предлагалось, вы, вероятно, захотите изменить порядок запроса, чтобы отсортировать его в другом направлении, чтобы вы фактически получили первую строку. Тогда вы, вероятно, захотите использовать что-то вроде

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

0 голосов
/ 27 августа 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...