2016-03-24 1 views
1

J'ai un problème avec les exigences complexes, j'espère pouvoir obtenir de l'aide pour résoudre ce problème. Ma connaissance SQL est très basique, et je n'ai aucune idée de comment résoudre ce problème. À l'heure actuelle, je une table Events structuré comme suit:Comment combiner des lignes en une seule ligne dans SQL?

ID  | Name | Time     | Event Type 
---------------------------------------------------------- 
133000 | Elise | 2016-02-17 06:39:42.000 | Arrival 
133000 | Elise | 2016-02-18 06:20:22.000 | Arrival 
133000 | Elise | 2016-02-18 20:43:46.000 | Departure 
133020 | Elise | 2016-02-19 06:29:46.000 | Arrival 
133445 | Peter | 2016-02-01 20:09:00.000 | Departure 
133445 | Peter | 2016-02-02 06:32:02.000 | Arrival 
133445 | Peter | 2016-02-02 17:03:04.000 | Departure 
133445 | Peter | 2016-02-02 19:44:06.000 | Arrival 
133445 | Peter | 2016-02-02 19:56:56.000 | Departure 

Maintenant, je veux interroger ces données d'une manière de sorte qu'il est structuré de cette façon:

ID  | Name | Arrival     | Departure 
---------------------------------------------------------- 
133000 | Elise | 2016-02-17 06:39:42.000 | NULL 
133000 | Elise | 2016-02-18 06:20:22.000 | 2016-02-18 20:43:46.000 
133000 | Elise | 2016-02-19 06:29:46.000 | NULL 
133445 | Peter | NULL     | 2016-02-01 20:09:00.000 
133445 | Peter | 2016-02-02 06:32:02.000 | 2016-02-02 17:03:04.000 
133445 | Peter | 2016-02-02 19:44:06.000 | 2016-02-02 19:56:56.000 

En d'autres termes, j'ai deux nouvelles colonnes: Arrival et Departure. Ensuite, pour chaque personne dans le tableau, appliquer la logique suivante dans l'ordre chronologique:

  • Si le Event Type est Arrival, il devrait être mis en correspondance avec une nouvelle ligne avec la valeur Time dans la colonne Arrival.
  • Si le Event Type est Departure, vérifiez si la ligne précédente est également Departure. Si c'est le cas, il doit être mappé à une nouvelle ligne avec la valeur Time dans la colonne Departure et Arrival est null. Si ce n'est pas le cas, il suffit de transférer la valeur Time dans la colonne Departure de la ligne précédente.

Il est préférable que cela puisse se faire via une requête SQL, mais une fonction est également bonne. J'utilise MS SQL Server. Merci!

Répondre

1

Si vos données a toujours bonne quantité de lignes d'arrivée, la solution de Gordon Linoff est probablement mieux, mais si les données est cassé, vous aurez probablement besoin de faire la ruse plus complexe avec row_number, quelque chose comme ceci:

select 
    Name, 
    max(case when [Event Type] = 'Arrival' then Time end) as Arrival, 
    max(case when [Event Type] = 'Departure' then Time end) as Departure 
from (
    select case when [Event Type] = 'Departure' and lag([Event Type]) over (partition by Name order by [Time] asc) = 'Arrival' then RN -1 else RN end as RN2, * 
    from (
    select row_number() over (partition by Name order by [Time]) as RN, * 
    from yourtable 
) X 
) Y 
group by Name, RN2 
order by Name, Arrival, Departure 

Cela va affecter toutes les lignes avec un numéro de ligne, et dans le cas où la ligne est un départ, et la ligne précédente est une arrivée, il déduira un du numéro de ligne -> ces lignes auront le même numéro. Ce numéro est ensuite utilisé pour regrouper les données, de sorte que toutes les lignes orphelines seront affichées séparément.

+0

J'ai dû le changer un petit peu pour utiliser apply au lieu de lag, puisque je suis sur le serveur '08. Mais c'est exactement ce que je voulais. – painiyff

1

Vous pouvez le faire de différentes manières. Une méthode est lead(), mais vous devez être prudent:

select id, name, time as Arrival, 
     (case when next_eventtype = 'Departure' then next_time end) as Departure 
from (select e.*, 
      lead(time) over (partition by id order by time) as next_time, 
      lead(eventtype) over (partition by id order by time) as next_eventtype, 
     from events e 
    ) e 
where eventtype = 'Arrival'; 

lead() est disponible dans SQL Server 2012+. Dans les versions antérieures, vous utiliseriez apply à la place.