2015-08-27 4 views
2

S'il vous plaît voir violon: http://sqlfiddle.com/#!6/e6768/2TSQL - Difficile Groupement

J'ai données, comme ci-dessous:

DRIVER DROP 
1  1 
1  2 
1  ReturnToBase 
1  4 
1  5 
1  ReturnToBase 
1  6 
1  7  
2  1 
2  2 
2  ReturnToBase 
2  4 

Je suis en train de regrouper mes données, donc pour chaque conducteur, chaque groupe de retour aux bases ont un numéro de groupe.

Ma sortie devrait ressembler à ceci:

DRIVER  DROP   GROUP 
1   1    1 
1   2    1 
1   ReturnToBase 1 
1   4    2 
1   5    2 
1   ReturnToBase 2 
1   6    3 
1   7    3 
1   ReturnToBase 3    
2   1    1   
2   2    1 
2   ReturnToBase 1 
2   4    2 

J'ai essayé d'obtenir ce résultat avec une combinaison de fonctions fenêtrées mais que je suis miles au large jusqu'à

Voici ce que j'avais si loin, il n'est pas censé être fonctionnel J'essayais de comprendre comment cela pourrait être fait, si c'est même possible.

SELECT 
    ROW_NUMBER() OVER (Partition BY Driver order by Driver Desc) rownum, 
    Count(1) OVER (Partition By Driver Order By Driver Desc) counter, 
    Count 
    DropNo, 
    Driver, 
    CASE DropNo 
     WHEN 'ReturnToBase' THEN 1 ELSE 0 END AS EnumerateRound 
FROM 
    Rounds 
+0

Pouvez-vous s'il vous plaît ajouter le SQL que vous avez essayé jusqu'à présent. On dirait que Row_Number devrait tenir ici – Mark

+0

Vous cherchez une sorte d'expression récurrente de table commune LEAD LAG pour accomplir ceci. – saarrrr

+0

Il y a aussi un identifiant séquentiel, désolé j'aurais dû l'inclure dans l'exemple. –

Répondre

5

Vous pouvez utiliser la requête suivante:

SELECT id, DRIVER, DROPno, 
     1 + SUM(flag) OVER (PARTITION BY DRIVER ORDER BY id) - 
     CASE 
      WHEN DROPno = 'ReturnToBase' THEN 1 
      ELSE 0 
     END AS grp  
FROM (
    SELECT id, DRIVER, DROPno, 
     CASE 
      WHEN DROPno = 'ReturnToBase' THEN 1 
      ELSE 0 
     END AS flag 
    FROM rounds) AS t 

Demo here

Cette requête utilise la version fenêtré de SUM avec ORDER BY dans la clause OVER pour calculer un total de fonctionnement. Cette version de SUM est disponible à partir de SQL Server 2012 AFAIK.

Fouiller un peu avec cette valeur totale cumulée est tout ce dont nous avons besoin pour obtenir la bonne valeur .

EDIT: (crédit va à @Conrad Frix)

En utilisant CROSS APPLY au lieu d'une vue en ligne peut simplifier considérablement les choses:

SELECT id, DRIVER, DROPno, 
     1 + SUM(x.flag) OVER (PARTITION BY DRIVER ORDER BY id) - x.flag 
FROM rounds 
CROSS APPLY (SELECT CASE WHEN DROPno = 'ReturnToBase' THEN 1 ELSE 0 END) AS x(flag) 

Demo here

+0

Parfait, j'étais loin. Merci –

+0

Vous voudrez peut-être envisager d'utiliser la fonction Appliquer au lieu d'une vue en ligne si vous voulez alias un seul calcul .. [par exemple] (http://data.stackexchange.com/stackoverflow/query/356003) –

+0

@ConradFrix Vous avez absolument raison, merci beaucoup! –

2

Ajout d'un ID séquentiel colonne à votre exemple pour une utilisation dans un CTE récursif:

with cte as (
select ID,DRIVER,DROPno,1 as GRP 
FROM rounds 
where ID = 1 
union all 
select a.ID 
,a.DRIVER 
,a.DROPno 
,case when b.DROPno = 'ReturnToBase' 
     or b.DRIVER <> a.DRIVER then b.GRP + 1 
     else b.GRP end 
from rounds a 
    inner join cte b 
    on a.ID = b.ID + 1 
) 

select * from cte 

SQL Fiddle