2010-12-29 9 views
2

Ich möchte eine Lösung in T-SQL finden, die einen Weg finden könnte, eine Änderung in einer bestimmten Liste oder Datensätzen zu erkennen.Funktion zum Erkennen von Änderungen in einer geordneten Liste

Die physische Tabelle ist wie folgt:

| id |val | 
|----|----| 
| 1 | A | 
|----|----| 
| 2 | A | 
|----|----| 
| 3 | B | 
|----|----| 
| 4 | B | 
|----|----| 
| 5 | A | 
|----|----| 
| 6 | A | 
|----|----| 

id ist eine sequentielle integer

val ein willkürlicher Wert ist

Ich möchte ein berechnetes Feld hinzuzufügen, das irgendwie eine Veränderung bedeuten könnte von val

Gewünschtes Ergebnis:

| id |val | segment | 
|----|----|---------| 
| 1 | A | 1  | 
|----|----|---------| 
| 2 | A | 1  | 
|----|----|---------| 
| 3 | B | 2  | 
|----|----|---------| 
| 4 | B | 2  | 
|----|----|---------| 
| 5 | A | 3  | 
|----|----|---------| 
| 6 | A | 3  | 
|----|----|---------| 

Was ich versuche ist die Möglichkeit, durch „Segmente“ wie diese Gruppe zu tun:

| from_id | to_id | val | 
|---------|-------|-----| 
|  1 | 2 | A | 
|  3 | 4 | B | 
|  5 | 6 | A | 
|---------|-------|-----| 
+0

Sie haben zu benutze einen cursor, ich tendiere dazu, an eine set-basierte lösung zu denken, weil ich cursors hasse, aber ich kann mir keinen einfallen lassen ... EDIT: Ich meine, du machst es wirklich ein Set-basierter Betrieb, da die Reihenfolge Ihrer Daten wichtig ist ... – kralco626

+0

Welche Version von SQL Server verwenden Sie? – Lamak

+1

Kann ich fragen, was Sie zu tun versuchen? Was versuchst du eigentlich zu erreichen? – kralco626

Antwort

4

Unter der Annahme, SQL Server 2005+

DECLARE @T TABLE (
id INT PRIMARY KEY, 
val CHAR(1)) 

INSERT INTO @T 
SELECT 1,'A' UNION ALL SELECT 2,'A' UNION ALL 
SELECT 3,'B' UNION ALL SELECT 4,'B' UNION ALL 
SELECT 5,'A' UNION ALL SELECT 6,'A' 

;WITH cte1 AS(
SELECT 
     id, 
     val, 
     ROW_NUMBER() OVER (ORDER BY id) - ROW_NUMBER() OVER (PARTITION BY val ORDER BY id) AS Grp 
FROM @T 
), 
cte2 AS(
SELECT 
     id, 
     val, 
     MIN(id) OVER (PARTITION BY Grp, val) AS GrpStart 
FROM cte1 
) 
SELECT 
     id, 
     val, 
     DENSE_RANK() OVER (ORDER BY GrpStart) AS segment 
FROM cte2 

Oder die aktualisierte Anforderung ist ein bisschen einfacher

;WITH cte AS(
SELECT 
     id, 
     val, 
     ROW_NUMBER() OVER (ORDER BY id) - ROW_NUMBER() OVER (PARTITION BY val ORDER BY id) AS Grp 
FROM @T 
) 
SELECT 
     val, 
     MIN(id) AS from_id, 
     MAX(id) AS to_id 
FROM cte 
GROUP BY Grp, val 
ORDER BY from_id 
+0

Das ist eine schöne Lösung ... gut eins – Lamak

+0

@user - wenn diese Lösung funktioniert, sollten Sie diese lieber als meine verwenden. nette Lösung Martin ... – kralco626

+0

Martin: vielen Dank! – pvieira

0

Dies könnte ein wenig geändert werden müssen, arbeiten. Außerdem verwende ich nie Schleifen, ist dies nicht der effizienteste Weg, dies zu tun.

Declare @counter int 

Set @counter = 1 

Declare @seg int 

Set @seg = 1 

Declare @cur varchar(50) 

Set @ cur = select val from table where id = 1 

While @counter <= select max id from table 

Begin 

    if(@cur == select val from table where id = @counter) 
     update table set segment = @seg where id = @counter 
    else 
    { 
     set @cur = select val from table where id = @counter 
     set @ seg = @seg + 1 
     update table set segment = @seg where id = @counter 
    } 
    Set @counter = @counter + 1 

End 

Nun das ist die allgemeine Idee sowieso ...

Verwandte Themen