Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Wie identifizieren Sie Datensatzmustersequenzen in Datensätzen mit TSQL?

Sie können die folgende in einen CTE eingeschlossene Abfrage verwenden um den in Ihrer Sequenz enthaltenen Werten Sequenznummern zuzuweisen:

;WITH Seq AS (
    SELECT v, ROW_NUMBER() OVER(ORDER BY k) AS rn
    FROM (VALUES(1, 5), (2, 9), (3, 6)) x(k,v)
)

Ausgabe:

v   rn
-------
5   1
9   2
6   3

Verwenden Sie den obigen CTE Sie können Inseln identifizieren, d. h. Segmente aufeinanderfolgender Zeilen, die die gesamte Sequenz enthalten:

;WITH Seq AS (
    SELECT v, ROW_NUMBER() OVER(ORDER BY k) AS rn
    FROM (VALUES(1, 5), (2, 9), (3, 6)) x(k,v)
), Grp AS (
SELECT [Key], [Value], 
       ROW_NUMBER() OVER (ORDER BY [Key]) - rn AS grp            
FROM mytable AS m
LEFT JOIN Seq AS s ON m.Value = s.v
)
SELECT *
FROM Grp

Ausgabe:

    Key Value   grp
   -----------------
    1   5       0
    2   9       0
    3   6       0
    6   5       3
    7   9       3
    8   6       3

grp Feld hilft Ihnen, genau diese Inseln zu identifizieren.

Jetzt müssen Sie nur noch Teilgruppen herausfiltern:

;WITH Seq AS (
    SELECT v, ROW_NUMBER() OVER(ORDER BY k) AS rn
    FROM (VALUES(1, 5), (2, 9), (3, 6)) x(k,v)
), Grp AS (
SELECT [Key], [Value], 
       ROW_NUMBER() OVER (ORDER BY [Key]) - rn AS grp            
FROM mytable AS m
LEFT JOIN Seq AS s ON m.Value = s.v
)
SELECT g1.[Key], g1.[Value]
FROM Grp AS g1
INNER JOIN (
   SELECT grp
   FROM Grp
   GROUP BY grp
   HAVING COUNT(*) = 3 ) AS g2
ON g1.grp = g2.grp

Demo hier

Hinweis: Die ursprüngliche Version dieser Antwort verwendete einen INNER JOIN zu Seq . Dies funktioniert nicht, wenn die Tabelle Werte wie 5, 42, 9, 6 enthält , als 42 wird durch den INNER JOIN herausgefiltert und diese Folge fälschlicherweise als gültig identifiziert. Diese Bearbeitung geht an @HABO.