2008-08-27 4 views
4

Ich habe eine Verlaufstabelle in SQL Server, die im Grunde ein Element durch einen Prozess verfolgt. Das Element hat einige feste Felder, die sich während des gesamten Prozesses nicht ändern, hat aber einige andere Felder, einschließlich Status und ID, die sich erhöhen, wenn die Schritte des Prozesses zunehmen.Holen Sie das letzte Element in einer Tabelle - SQL

Grundsätzlich möchte ich den letzten Schritt für jedes Element mit einer Batch-Referenz abrufen. Also, wenn ich ein

Select * from HistoryTable where BatchRef = @BatchRef 

es alle Schritte für alle Gegenstände in der Menge zurück - zB

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

Aber was ich wirklich will, ist:

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

Edit: Appologies - scheint nicht, dass die TABLE-Tags mit Markdown funktionieren - folgte der Hilfe bis zum Buchstaben und sieht in der Vorschau gut aus

Antwort

6

Es ist ein bisschen schwer, Ihren Tischentwurf zu verstehen - ich denke, dass SO Ihre Begrenzer gegessen hat.

Der grundlegende Weg, dies zu handhaben, ist GROUP BY Ihre festen Felder, und wählen Sie eine MAX (oder MIN) für einen eindeutigen Wert (eine Datetime funktioniert in der Regel gut). In Ihrem Fall denke ich , dass die GROUP BY BatchRef und ItemCount wäre, und Id wird Ihre eindeutige Spalte sein.

Verbinden Sie sich dann wieder mit der Tabelle, um alle Spalten zu erhalten. Etwas wie:

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

Angenommen, Sie eine Identitätsspalte in der Tabelle haben ...

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

Es ist ein bisschen schwer ist, Ihre Daten, die die Art und Weise WMD zu entziffern ist es formatiert, aber Sie können von der Art Trick, den Sie mit gängigen Tabellenausdrücke benötigen ziehen auf 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 

oder eine Unterabfrage (vorausgesetzt, die Gruppe, die durch in der Unterabfrage funktioniert - aus der Spitze von meinem Kopf ich erinnere mich nicht):

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: ich war die Annahme, Sie wollte t er letzte Artikel für alle Charge. Wenn Sie es nur für die eine Charge benötigen, dann sind die anderen Antworten (eine Top 1 zu tun und absteigend zu bestellen) der richtige Weg.

0

Wie bereits vorgeschlagen, möchten Sie wahrscheinlich Ihre Abfrage neu sortieren, um sie in die andere Richtung zu sortieren, so dass Sie tatsächlich die erste Zeile abrufen. Dann würden Sie wahrscheinlich so etwas wie

SELECT TOP 1 ... 

verwenden möchten, wenn Sie mit MSSQL 2k oder früher oder die SQL-konforme Variante

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

für jede andere Version (oder für andere Datenbanksysteme, die unterstützt die Standardnotation), oder

für einige andere Varianten ohne die Standard-SQL-Unterstützung.

Siehe auch this Frage für einige zusätzliche Diskussion um das Auswählen von Zeilen. Die Verwendung der Aggregatfunktion max() kann oder kann nicht schneller sein, abhängig davon, ob die Berechnung des Werts einen Tabellenscan erfordert.

1

Vorausgesetzt, dass die Artikel-Ids werden inkrementell nummeriert:

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

von Sachen Wiki Markierung Sie Ihr Selbst von rep berauben, in der Regel gibt es keine Notwendigkeit ist. diese Antwort Art der Arbeit –