2008-08-27 13 views
4

J'ai une table d'historique dans SQL Server qui suit fondamentalement un élément à travers un processus. L'élément a des champs fixes qui ne changent pas tout au long du processus, mais possède quelques autres champs, y compris l'état et l'identifiant qui augmentent au fur et à mesure que les étapes du processus augmentent.Obtenir le dernier élément dans une table - SQL

Fondamentalement, je veux récupérer la dernière étape pour chaque élément donné une référence de lot. Donc, si je fais un

Select * from HistoryTable where BatchRef = @BatchRef 

Il retournera toutes les étapes pour tous les éléments du lot - par exemple

 
Id  Status BatchRef  ItemCount 
1  1  Batch001  100 
1  2  Batch001  110 
2  1  Batch001  60 
2  2  Batch001  100 

Mais ce que je veux vraiment est:

 
Id  Status BatchRef  ItemCount 
1  2  Batch001  110 
2  2  Batch001  100 

Edit: Appologies - ne peut pas sembler obtenir les étiquettes de TABLE pour travailler avec Markdown - suivi l'aide à la lettre, et l'air bien dans l'aperçu

Répondre

6

Il est difficile de donner un sens à votre conception de table - je pense que vous avez mangé vos délimiteurs. La méthode de base pour gérer ceci est de GROUP BY vos champs fixes, et sélectionnez un MAX (ou MIN) pour une valeur unqiue (une datetime fonctionne généralement bien). Dans votre cas, je pense que le GROUP BY serait BatchRef et ItemCount, et Id sera votre colonne unique.

Ensuite, revenez à la table pour obtenir toutes les colonnes. Quelque chose comme:

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 
10

En supposant que vous avez une colonne d'identité dans le tableau ...

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

Il est un peu difficile à déchiffrer vos données comme ADM a formaté, mais vous pouvez tirer de ce genre de truc dont vous avez besoin avec des expressions de table commune sur 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 

Ou un sous-requête (en supposant que le groupe par les travaux de sous-requête - du haut de ma tête, je ne me souviens pas):

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: je suppose que vous voulait t Le dernier article pour chaque lot. Si vous en avez juste besoin pour un lot, alors les autres réponses (faire un top 1 et commander en descendant) sont le chemin à parcourir.

0

Comme déjà suggéré, vous souhaitez probablement réorganiser votre requête pour le trier dans l'autre direction afin que vous récupériez réellement la première rangée. Ensuite, vous voudrez probablement utiliser quelque chose comme

SELECT TOP 1 ... 

si vous utilisez MSSQL 2k ou plus tôt, ou la variante compatible SQL

SELECT * FROM (
    SELECT 
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber, 
    columns 
    FROM tablename 
) AS foo 
WHERE rownumber = n 

pour toute autre version (ou pour d'autres systèmes de base de données prend en charge la notation standard), ou

SELECT ... LIMIT 1 OFFSET 0 

pour d'autres variantes sans le support SQL standard.

Voir aussi this pour une discussion supplémentaire sur la sélection des lignes. L'utilisation de la fonction d'agrégation max() peut ou non être plus rapide selon que le calcul de la valeur nécessite un balayage de table.

1

En supposant que les Ids de l'article sont progressivement numérotés:

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

par marquage wiki stuff vous privez votre auto de représentant, en général il n'y a pas besoin. cette réponse genre de travail –