2016-01-15 4 views
8

Angenommen, ich habe eine Tabelle von Einträgen aus wieSQL selbst kommt paarweise

ID Arrival Date Arrival City Departure Date Departure City 
1  Jun 27 2015  Berlin   Jun 20 2015  Paris 
1  Jul 1 2015  Rome   Jun 29 2015  Berlin 
1  Jul 30 2015  Vienna   Jul 15 2015  Rome 
2  Jun 28 2015  Prague   Jun 23 2015  Vienna 
2  Jul 1 2015  Rome   Jun 29 2015  Prague 
2  Jul 30 2015  Vienna   Jul 15 2015  Moscow 
... 

und für jede ID mag ich selbst diese Daten verbinden, so dass Beobachtungen mit anschließenden Departure Date und Arrival Date paarweise gruppiert sind - dh ein Abweichen wird mit der vorherigen Ankunft für jede ID gepaart.

Im obigen Beispiel (wo die Beobachtungen der Einfachheit halber sortiert sind) würde die zweite Zeile an die erste, die dritte an die zweite, die fünfte an die vierte und die sechste an die fünfte Zeile angehängt werden Felder ID Arrival Date Arrival City Departure Date Departure City Arrival Date2 Arrival City2 Departure Date2 Departure City2).

Es kann potenziell mehr als drei Abfahrten für jede ID geben, so dass ein allgemeiner Ansatz erforderlich ist. Bitte beachten Sie auch, dass es in den Daten Löcher geben kann, in denen Arrival City und Departure City nicht übereinstimmen - z. Die Arrival City der 5. Reihe ist nicht die Departure City der 6. Reihe, aber sie sollte noch zusammengeführt werden. Ein wichtiges Ziel ist es, eine bessere Übersicht über die Anzahl der Löcher in den Daten zu erhalten.

+1

könnten Sie bitte zeigen, was Ihr erwartetes Ergebnis aussehen sollte? –

+0

"Es kann potenziell mehr als drei Abweichungen für jede ID geben, so dass ein allgemeiner Ansatz erforderlich ist" jede bestimmte Abfrage erzeugt Ergebnismengen mit einer festen "Form" - die Anzahl, Namen und Typen der Spalten. Aber es scheint, als ob Sie nach einer Abfrage fragen, die abhängig von den Eingabedaten eine andere Anzahl von Spalten erzeugt (und auch, was passiert, wenn verschiedene IDs unterschiedliche Abfahrtszahlen haben?). Es ist möglicherweise besser, diese Art der Ausgabeverarbeitung auf einer höheren Ebene als SQL auszuführen. –

+2

Was ist die Version von SQL Server? Fügen Sie der Frage statt "Join" das entsprechende Tag hinzu. Bitte zeigen Sie anhand Ihrer Beispieldaten, wie das Endergebnis aussehen soll. –

Antwort

5

Try this:

SELECT a.id 
    ,a.arrival_date 
    ,a.arrival_city 
    ,a.departure_date 
    ,a.departure_city 
    ,b.arrival_date arrival_date_2 
    ,b.arrival_city arrival_city_2 
    ,b.departure_date departure_date_2 
    ,b.departure_city departure_city_2 
FROM triptable a 
JOIN triptable b ON a.id = b.id 
    AND a.departure_date = (SELECT min(departure_date) FROM so34815894 x WHERE x.departure_date > b.arrival_date AND x.id = b.id) 

Edited auf Ihrem Kommentar basiert auf:

  • den Rekord mit dem frühesten Abreisedatum finden nach dem vorherigen Ankunft Rekord und
  • die Tatsache ignorieren, dass der sechste Datensatz der Beispieldaten eine andere Startstadt hat als die Ankunftsstadt des 5. Datensatzes.
+0

Vielen Dank für Ihre Antwort. Tatsächlich möchte ich den sechsten Datensatz an den 5. angehängt haben - der Fehler hier war absichtlich (da es Löcher in den Daten geben kann). Ich werde das OP mit dieser Klarstellung aktualisieren – user787267

8

Eine Lösung ist es, einen CTE zu verwenden, und zu berücksichtigen, dass die Differenz zwischen zwei aufeinanderfolgenden Reihen (von der ROWNO identifiziert) 1 ist die ganze Zeit (und auch prüfen, die Daten):

;WITH CTE AS (
SELECT 
    rownum = ROW_NUMBER() OVER (ORDER BY t.ID, t.arrivalDate), 
    t.ID, 
    t.arrivalDate, 
    t.arrivalCity, 
    t.departureDate, 
    t.departureCity 
FROM #test t 
) 
SELECT * 
FROM CTE c1 
JOIN CTE c2 
ON c1.ID = c2.ID 
    AND c2.departureDate > c1.arrivalDate 
    AND c2.rownum - c1.rownum = 1 
GO 

-- structure of the #test table 
CREATE TABLE #test (
    ID int, 
    arrivalDate date, 
    arrivalCity varchar(30), 
    departureDate date, 
    departureCity varchar(30) 
) 

SQL Geige hier: SQLFiddle

+1

Und hinzufügen 'WHERE c1.arrivalCity <> c2.departureCity' hilft definitiv * um einen besseren Überblick zu erhalten, wie viele Löcher es in den Daten gibt * :-) – dnoeth

4

Nicht ganz sicher, welches Ergebnis Sie suchen .. aber ich dachte, ich würde dies eine Chance geben und sehen, ob einige davon Ihnen helfen.

drop table #t1 
create table #t1 (id int, ArrivalDate datetime, ArrivalCity varchar(50), Departuredate datetime, DepartureCity varchar(50)) 

insert into #t1 
values (1, 'Jun 27 2015', 'Berlin', 'Jun 20 2015','Paris'), 
     (1, 'Jul 1 2015', 'Rome','Jun 29 2015','Berlin'), 
     (1, 'Jul 30 2015', 'Vienna','Jul 15 2015','Rome'), 
     (2, 'Jun 28 2015','Prague','Jun 23 2015','Vienna'), 
     (2, 'Jul 1 2015','Rome','Jun 29 2015','Prague'), 
     (2, 'Jul 30 2015','Vienna','Jul 15 2015','Moscow') 

select *, case when lead(departurecity) over (partition by id order by Arrivaldate) = ArrivalCity or lead(departurecity) over (partition by id order by Arrivaldate) is null then 1 else 0 end as PairID into #t2 from #t1 

update #t2 
set PairID = id 
where pairid != id 
and pairid != 0 

Dies ist der Code bis zu starten ..

select * from #t2 

in Folge hat:

id ArrivalDate ArrivalCity Departuredate DepartureCity PairID 
1 2015-06-27 Berlin  2015-06-20  Paris   1 
1 2015-07-01 Rome  2015-06-29  Berlin   1 
1 2015-07-30 Vienna  2015-07-15  Rome   1 
2 2015-06-28 Prague  2015-06-23  Vienna   2 
2 2015-07-01 Rome  2015-06-29  Prague   0 
2 2015-07-30 Vienna  2015-07-15  Moscow   2 

Jeder Ort, wo das Paar id = 0 ... Sie eine Lücke haben/baddata aber Sie möchten es setzen ..

Sie könnten auch:

select *, lead(departurecity) over (partition by ID order by ArrivalDate) as PreviousDepartureCity, lead(Departuredate) over (partition by ID order by ArrivalDate) as PreviousDepartureDate from #t2 

Dies wird vorherigen Abflugsort und Datum hinzufügen .. und Sie können tun, was Sie mit dem nulls wollen .. werden sie den ersten Flug bedeuten .. oder eine Lücke, wenn die nachfolgenden Paare id = 0 ...

Die Auswahloptionen werden endlos .... Wenn null und lag (pairid) = 0 dann haben Sie die Zeile mit der Lücke .. Wenn null und Paar id = id .. und lag (pairid) = ID dann haben Sie Ihre erster Flug..

Ich meine, ich halten kann gehen .. und geben Ihnen mehr Details, aber ich bin nicht sicher, ob dies ist, was Sie suchen .. Hoffe, dass es auf jeden Fall geholfen ..

Viel Glück!

PS Haben Sie nicht sehen, warum Sie sich auf den Tisch kommen benötigt .. vielleicht habe ich das ganze point..lol..sorry wenn das der Fall ist ..

3

Diese Arbeit sollte:

with cte as(select *, row_number() over(partition by id order by date) rn from table) 
select * from cte c1 
join cte c2 on c1.id = c2.id and c1.rn = c2.rn - 1 
4

Es klingt für mich so, als wollten Sie die Ergebnisse drehen und die Ergebnisse in zusätzliche Spalten einfügen. Ich habe ROW_NUMBER() für die Bestellung verwendet. Ich verkettete die Spalten in einer Reihe vor dem Drehpunkt, schwenkte und verwendete dann eine Funktion, um die Verkettung umzukehren.

SELECT 
    p.ID, 
    dbo.SplitString(p.[1], CHAR(13), 1) AS arrivalDate1, 
    dbo.SplitString(p.[1], CHAR(13), 2) AS arrivalCity1, 
    dbo.SplitString(p.[1], CHAR(13), 3) AS departureDate1, 
    dbo.SplitString(p.[1], CHAR(13), 4) AS departureCity1, 
    * 
FROM 
    (
     SELECT * 
     FROM 
     (
      SELECT 
       ID, 
       ROW_NUMBER() OVER (PARTITION BY ID ORDER BY arrivalDate) RowNum, 
       CAST(arrivalDate AS VARCHAR(MAX)) + CHAR(13) 
       + arrivalCity + CHAR(13) 
       + CAST(departureDate AS VARCHAR(MAX)) + CHAR(13) 
       + departureCity TripDetails 
      FROM trip t 
     ) t 
     PIVOT (MIN(t.TripDetails) FOR t.RowNum IN ([1], [2], [3], [4], [5] /* , ... */)) p 
    ) p; 

mit dieser Funktion split

CREATE FUNCTION dbo.SplitString ( 
    @stringToSplit VARCHAR(MAX), 
    @delim VARCHAR(255), 
    @occurence INT) 
RETURNS VARCHAR(MAX) AS 
BEGIN 

DECLARE @name NVARCHAR(255); 

DECLARE @pos INT; 

DECLARE @orderNum INT; 

SET @orderNum=0; 

WHILE CHARINDEX(@delim, @stringToSplit) > 0 

BEGIN 
    SELECT @[email protected]+1; 
    SELECT @pos = CHARINDEX(@delim, @stringToSplit) ; 
    SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1); 

    IF @orderNum = @occurence 
    BEGIN 
    RETURN @name; 
    END 

    SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)[email protected]) 
END 

    SELECT @[email protected]+1; 

    IF @orderNum = @occurence 
    BEGIN 
    RETURN @stringToSplit; 
    END 

    RETURN NULL; 
END 
3

dies versuchen,

declare @t table(ID int,ArrivalDate datetime, ArrivalCity varchar(50) 
,DepartureDate datetime,DepartureCity varchar(50)) 
insert into @t values 
(1,  'Jun 27 2015',  'Berlin',   'Jun 20 2015',  'Paris ') 
,(1,  'Jul 1 2015 ',  'Rome ',   'Jun 29 2015',  'Berlin ') 
,(1,  'Jul 30 2015',  'Vienna',   'Jul 15 2015',  'Rome ') 
,(2,  'Jun 28 2015',  'Prague',   'Jun 23 2015',  'Vienna ') 
,(2,  'Jul 1 2015 ',  'Rome ',   'Jun 29 2015',  'Prague ') 
,(2 , 'Jul 30 2015',  'Vienna',   'Jul 15 2015',  'Moscow ') 

;WITH CTE 
AS (
    SELECT * 
     ,ROW_NUMBER() OVER (
      ORDER BY id 
       ,arrivaldate 
      ) rn 
    FROM @t 
    ) 
SELECT A.arrivaldate 
    ,a.arrivalcity 
    ,a.DepartureDate 
    ,a.DepartureCity 
    ,b.arrivaldate 
    ,b.arrivalcity 
    ,b.DepartureDate 
    ,b.DepartureCity 
FROM CTE A 
LEFT JOIN CTE b ON a.rn + 1 = b.rn