Сведения о вопросе

Junior

00:54, 7th August, 2020

Теги

sql   sql-server   database   tsql    

Получить последний элемент в таблице-SQL

Просмотров: 550   Ответов: 6

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

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

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

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



  Сведения об ответе

SSESION

10:25, 2nd August, 2020

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

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


  Сведения об ответе

padenie

23:47, 9th August, 2020

Это довольно сложно понять в дизайне вашей таблицы - я думаю, что SO съел ваши разделители.

Основной способ обработки этого состоит в том, чтобы сгруппировать ваши фиксированные поля и выбрать MAX (или MIN) для некоторого значения unqiue (обычно хорошо работает a datetime). В вашем случае, я думаю , что группа 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


  Сведения об ответе

KOMP

09:45, 13th August, 2020

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

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


  Сведения об ответе

pumpa

07:42, 5th August, 2020

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


  Сведения об ответе

SKY

17:50, 5th August, 2020

Немного трудно расшифровать ваши данные так, как их отформатировал 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

Или подзапрос (предполагая, что группа 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

Edit: я предполагал, что вы хотите получить последний элемент для каждой партии. Если вы просто нуждаетесь в нем для одной партии, то другие ответы (выполнение топ-1 и заказ по убыванию) - это способ пойти.


  Сведения об ответе

LAST

20:55, 1st August, 2020

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться