Получить последний элемент в таблице – SQL
-
09-06-2019 - |
Вопрос
У меня есть таблица истории в 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() может быть быстрее, а может и нет, в зависимости от того, требует ли вычисление значения сканирования таблицы.