Question

J'ai une table d'historique dans SQL Server qui suit essentiellement un élément tout au long d'un processus.L'élément comporte des champs fixes qui ne changent pas tout au long du processus, mais comporte quelques autres champs, notamment le statut et l'identifiant, qui s'incrémentent à mesure que les étapes du processus augmentent.

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

Select * from HistoryTable where BatchRef = @BatchRef

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

Identifiant Statut BatchRef ItemCount
1       1       Batch001        100
1       2       Batch001        110
2       1       Batch001        60
2       2       Batch001        100

Mais ce que je veux vraiment c'est :

Identifiant Statut BatchRef ItemCount
1       2       Batch001        110
2       2       Batch001        100

Modifier:Toutes mes excuses - je n'arrive pas à faire fonctionner les balises TABLE avec Markdown - j'ai suivi l'aide à la lettre et cela semble bien dans l'aperçu

Était-ce utile?

La solution

Il est un peu difficile de donner un sens à la conception de votre table – je pense que vous avez tellement mangé vos délimiteurs.

La manière de base de gérer cela consiste à GROUPER PAR vos champs fixes et à sélectionner un MAX (ou MIN) pour une valeur unique (une date/heure fonctionne généralement bien).Dans votre cas, je pense que 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

Autres conseils

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

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

En supposant que les identifiants d'articles sont numérotés de manière incrémentielle :

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

Il est un peu difficile de déchiffrer vos données telles que WMD les a formatées, mais vous pouvez utiliser le type d'astuce dont vous avez besoin avec les expressions de table courantes 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 une sous-requête (en supposant que le groupe by dans la sous-requête fonctionne - de mémoire, 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

Modifier:Je pensais que tu voulais le dernier objet pour chaque lot.Si vous en avez juste besoin pour un lot, les autres réponses (faire un top 1 et classer par ordre décroissant) sont la voie à suivre.

Comme déjà suggéré, vous souhaiterez probablement réorganiser votre requête pour la trier dans l'autre sens afin de récupérer la première ligne.Ensuite, vous voudriez probablement utiliser quelque chose comme

SELECT TOP 1 ...

si vous utilisez MSSQL 2k ou version antérieure, 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 bases de données prenant en charge la notation standard), ou

SELECT ... LIMIT 1 OFFSET 0

pour certaines autres variantes sans le support SQL standard.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top