2010-08-16 4 views
1

J'ai un des dossiers comme celui-ci:SQL: L'expansion d'une ligne avec début/fin en lignes individuelles

start, end , total 
830 , 1300, 5 
1400, 1430, 2 

que je voudrais étendre à:

instance , total 
    830 , 5 
    831 , 5 
    832 , 5 
    ... 
    1299 , 5 
    1300 , 5 

    1400 , 2 
    1401 , 2 
    ... 
    1429 , 2 
    1430 , 2 

Comment puis-je faire en utilisant SQL dans MSSQL 2005?

EDIT: merci à tous, bonnes réponses. J'ai quelques-uns à travailler. J'ai juste oublié de dire que le début/fin était vraiment un temps stocké comme un int, donc 0830 à 1300 devrait aller jusqu'à 0859 puis 0900. Je ne peux pas attendre de vous les gars à répondre à cette question, je vais travailler autour de. Merci encore

+1

Quel DB utilisez-vous? –

+0

Désolé, aurait dû dire MSSQL 2005 –

Répondre

1

L'utilisation d'un CTE:

with number_cte(n) as 
(select n from (select 0 n) m union all select n+1 n 
    from number_cte where n< 2400) 
select start+n instance, total 
from 
datatable 
join number_cte on start+n between start and [end] 
where start+n - 100*floor((start+n)/100) between 0 and 59 
order by 1 
option (maxrecursion 2401) 

(Augmentation n < ... et les numéros de maxrecursion le cas échéant, si les distances supérieures à 2400 sont nécessaires.)

Edited pour empêcher instance non valide (ie. les valeurs de temps de fin soit tween 60 et 99) étant inclus.

+0

Merci, cela semble très bien, mais je ne comprends pas comment je l'utiliser: sélectionnez start + n instance, total - Je choisis un début, une fin et le total, comment puis-je faire cela? –

+0

Veuillez noter que ceci est limité de la même manière que la réponse de Joe. –

+0

@Igor, 'datatable' est mon nom pour la table ou la requête que vous utilisez pour obtenir vos valeurs de début, de fin et de total. En supposant qu'ils sont réellement appelés start, end et total, remplacez simplement 'datatable' par votre nom de table ou votre requête, selon le cas. ('n' vient de mon CTE, alors que' instance' est le nom de la colonne pour le résultat de l'expression 'start + n'.) –

1

Cela devrait faire l'affaire:

create table input (start int, [end] int, total int) 

insert input values (830, 1300, 5) 
insert input values (1400, 1430, 2) 

declare @output table (instance int, start int, [end] int, total int) 

insert @output select start, start, [end], total from input 

while @@rowcount > 0 
    insert @output 
    select 
     max(instance) + 1, 
     start, 
     [end], 
     total 
    from @output 
    group by 
     start, 
     [end], 
     total 
    having max(instance) < [end] 

select instance, total from @output order by instance 

Ceci produit les résultats les mêmes (que vous) non tronquées décrites dans la question.

Il pourrait y avoir une approche CTE de fantaisie mais je ne pense pas que cela pourrait fonctionner puisque vous auriez besoin d'une quantité indéfinie de récursivité.

+0

Merci, cela semble bon. –

0

Si l'on suppose il y a un maximum à vos valeurs de fin finie, vous pouvez utiliser une table de nombres (changer le 2000, je l'habitude d'être votre valeur max END):

declare @Test table (
    start int, 
    [end] int, 
    total int 
) 

insert into @Test 
    (start, [end], total) 
    select 830, 1300, 5 
    union 
    select 1400, 1430, 2 

;WITH Nbrs (n) AS (
     SELECT 1 UNION ALL 
     SELECT 1 + n FROM Nbrs WHERE n < 2000 
) 
select n.n, t.total 
    from @Test t 
     cross join Nbrs n 
    where n.n between t.start and t.[end] 
    option (MAXRECURSION 2000) 
+0

Merci Joe, une autre approche –

+0

Note: cela ne fonctionnera que tant que l'écart maximum entre 'start' et' end' est inférieur à 2000. –

+0

@Daniel, vous avez raison. J'ai supposé (et édité ma réponse pour refléter cette hypothèse) que END aurait un max fini. valeur. Vous changeriez alors 2000 pour être ce maximum. –

Questions connexes