2010-04-29 9 views
1

J'ai une table (ROOMUSAGE) contenant les heures auxquelles les personnes enregistrent et sortent des pièces regroupées par PERSONKEY et ROOMKEY. Il ressemble à ceci:Application d'un CTE récursif sur des lignes de table groupées (SQL Server 2005)

PERSONKEY | ROOMKEY | CHECKIN   | CHECKOUT   | ROW 
---------------------------------------------------------------- 
1   | 8  | 13-4-2010 10:00 | 13-4-2010 11:00 | 1 
1   | 8  | 13-4-2010 08:00 | 13-4-2010 09:00 | 2 

1   | 1  | 13-4-2010 15:00 | 13-4-2010 16:00 | 1 
1   | 1  | 13-4-2010 14:00 | 13-4-2010 15:00 | 2 
1   | 1  | 13-4-2010 13:00 | 13-4-2010 14:00 | 3 

13  | 2  | 13-4-2010 15:00 | 13-4-2010 16:00 | 1 
13  | 2  | 13-4-2010 15:00 | 13-4-2010 16:00 | 2 

Je veux sélectionner seulement les rangées consécutives pour chaque groupement PERSONKEY, ROOMKEY. Donc la table résultante désirée est:

PERSONKEY | ROOMKEY | CHECKIN   | CHECKOUT   | ROW 
---------------------------------------------------------------- 
1   | 8  | 13-4-2010 10:00 | 13-4-2010 11:00 | 1 

1   | 1  | 13-4-2010 15:00 | 13-4-2010 16:00 | 1 
1   | 1  | 13-4-2010 14:00 | 13-4-2010 15:00 | 2 
1   | 1  | 13-4-2010 13:00 | 13-4-2010 14:00 | 3 

13  | 2  | 13-4-2010 15:00 | 13-4-2010 16:00 | 1 

Je veux éviter d'utiliser des curseurs alors j'ai pensé que j'utiliserais un CTE récursif. Voici ce que je suis venu avec:

;with CTE (PERSONKEY, ROOMKEY, CHECKIN, CHECKOUT, ROW) 
as (select RU.PERSONKEY, 
      RU.ROOMKEY, 
      RU.CHECKIN, 
      RU.CHECKOUT, 
      RU.ROW 
    from ROOMUSAGE RU 
    where RU.ROW = 1 

    union all 

    select RU.PERSONKEY, 
      RU.ROOMKEY, 
      RU.CHECKIN, 
      RU.CHECKOUT, 
      RU.ROW 
    from ROOMUSAGE RU inner join CTE on RU.ROW = CTE.ROW + 1 
    where CTE.CHECKIN = RU.CHECKOUT 
     and CTE.PERSONKEY = RU.PERSONKEY 
     and CTE.ROOMKEY = RU.ROOMKEY) 

Cela a fonctionné OK pour les ensembles de données très petits (moins de 100 dossiers) mais il est inutilisable sur de grands ensembles de données.

Je pense que je devrais appliquer d'une façon ou d'une autre le cte recursevely sur chaque PERSONKEY, ROOMKEY groupant sur ma table ROOMUSAGE mais je ne suis pas sûr comment faire ceci.

Toute aide serait appréciée,

Cheers!

+0

Avez-vous regardé le plan de requête pour cela, je serais prêt à parier que la jointure de RU à CTE est la table fait scrute la façon dont vous le joindre. – BlackICE

Répondre

0

Certaines choses à essayer

  • Au lieu de se joindre à tous les ligne et filtrer les résultats dans votre clause where, pourriez-vous essayer si réduire la quantité de données sont directement enregistrées dans la jointure accélère les choses?
  • Ajouter un index de couverture sur PersonKey, RoomKey, CheckOut & Row et voir si cela améliore les performances.

Déclaration SQL

;with CTE (PERSONKEY, ROOMKEY, CHECKIN, CHECKOUT, ROW) 
as (select RU.PERSONKEY, 
      RU.ROOMKEY, 
      RU.CHECKIN, 
      RU.CHECKOUT, 
      RU.ROW 
    from ROOMUSAGE RU 
    where RU.ROW = 1 

    union all 

    select RU.PERSONKEY, 
      RU.ROOMKEY, 
      RU.CHECKIN, 
      RU.CHECKOUT, 
      RU.ROW 
    from ROOMUSAGE RU 
     inner join CTE on CTE.ROW + 1 = RU.ROW 
          and CTE.CHECKIN = RU.CHECKOUT 
          and CTE.PERSONKEY = RU.PERSONKEY 
          and CTE.ROOMKEY = RU.ROOMKEY 
) 
+0

Désolé, j'aurais dû clarifier ROOMUSAGE est un autre cte non récursif qui est créé juste avant CTE. Les tables sous-jacentes sont toutes indexées. J'ai essayé votre suggestion et j'ai remarqué que lorsque je fais un select * à partir de CTE, j'obtiens toutes les lignes ROW = 1 et ensuite il reste bloqué en traitant le reste des lignes. Lorsque je supprime la condition PERSONKEY et ROOMKEY de la jointure, j'obtiens presque tous les enregistrements mais encore une fois il reste bloqué ... –

+0

Dans ce cas, il peut être plus rapide de créer une table temporaire #ROOMUSAGE, d'ajouter l'index et d'utiliser la table temporaire dans le CTE. –

+0

Merci Lieven, en utilisant une table temporaire considérablement amélioré les performances. –