2016-03-21 14 views
4

Ich habe eine Tabelle, die die folgende Struktur ähnelt:Abfrage, die in einigen Fällen funktioniert nur

City  start_date    end_date 
Paris  1995-01-01 00:00:00 1997-10-01 23:59:59 
Paris  1997-10-02 00:00:00 0001-01-01 00:00:00 
Paris  2013-01-25 00:00:00 0001-01-01 00:00:00 
Paris  2015-04-25 00:00:00 0001-01-01 00:00:00 
Berlin  2014-11-01 00:00:00 0001-01-01 00:00:00 
Berlin  2014-06-01 00:00:00 0001-01-01 00:00:00 
Berlin  2015-09-11 00:00:00 0001-01-01 00:00:00 
Berlin  2015-10-01 00:00:00 0001-01-01 00:00:00 
Milan  2001-01-01 00:00:00 0001-01-01 00:00:00 
Milan  2005-10-02 00:00:00 2006-10-02 23:59:59 
Milan  2006-10-03 00:00:00 2015-04-24 23:59:59 
Milan  2015-04-25 00:00:00 0001-01-01 00:00:00 

Die Daten enthalten einen historischen Blick auf Start- und Enddaten in Städten. Der letzte Datensatz für eine Stadt sollte derjenige sein, der das höchste Startdatum hat, und ein Enddatum von "0001-01-01 00:00:00", was anzeigt, dass es noch kein Enddatum gibt.

Ich brauche diese Daten zu reinigen und stellen Sie sicher, dass historische Aufzeichnungen für jede Stadt haben alle Enddaten eine Sekunde vor dem Startdatum des nächsten Datensatz, nur in Fällen, in denen die end_date auf ‚0001-01-01 gesetzt ist 00 : 00: 00 '. In Fällen, in denen das Enddatum ein tatsächliches Datum hat, wird das ignoriert. Außerdem muss für den Datensatz mit dem letzten Startdatum für eine Stadt das Enddatum nicht geändert werden.

Die resultierende Tabelle sollte wie folgt aussehen:

City  start_date    end_date 
Paris  1995-01-01 00:00:00 1997-10-01 23:59:59 
Paris  1997-10-02 00:00:00 2013-01-24 23:59:59 
Paris  2013-01-25 00:00:00 2015-04-24 23:59:59 
Paris  2015-04-25 00:00:00 0001-01-01 00:00:00 
Berlin  2014-11-01 00:00:00 2014-05-31 23:59:59 
Berlin  2014-06-01 00:00:00 2015-09-10 23:59:59 
Berlin  2015-09-11 00:00:00 2015-09-30 23:59:59 
Berlin  2015-10-01 00:00:00 0001-01-01 23:59:59 
Milan  2001-01-01 00:00:00 2005-10-01 23:59:59 
Milan  2005-10-02 00:00:00 2006-10-02 23:59:59 
Milan  2006-10-03 00:00:00 2015-04-24 23:59:59 
Milan  2015-04-25 00:00:00 0001-01-01 00:00:00 

habe ich versucht, das folgende Skript von einem Benutzer in this question vorgeschlagen.

update test join 
     (select t.*, 
       (select min(start_date) 
       from test t2 
       where t2.city = t.city and 
         t2.start_date > t.start_date 
       order by t2.start_date 
       limit 1 
       ) as next_start_date 
     from test t 
     ) tt 
     on tt.city = test.city and tt.start_date = test.start_date 
    set test.end_date = date_sub(tt.next_start_date, interval 1 second) 
where test.end_date = '0001-01-01' and 
     next_start_date is not null; 

Leider sind einige end_dates nicht wie vorgesehen (zB ID-Nummer 5 und 6), aus den Berliner Aufzeichnungen beginnen. Andere erscheinen jedoch so, wie sie sollen. Dies ist unten dargestellt:

enter image description here

Hier sind die erstellen und einfügen Aussagen der Lage sein, zu replizieren:

CREATE TABLE `test` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `city` varchar(50) DEFAULT NULL, 
    `start_date` datetime DEFAULT NULL, 
    `end_date` datetime DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; 

INSERT INTO test (city, start_date, end_date) VALUES ('Paris','1995-01-01 00:00:00','1997-10-01 23:59:59'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','1997-10-02 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','2013-01-25 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','2015-04-25 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2014-11-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2014-06-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2015-09-11 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2015-10-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2001-01-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2005-10-02 00:00:00','2006-10-02 23:59:59'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2006-10-03 00:00:00','2015-04-24 23:59:59'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2015-04-25 00:00:00','0001-01-01 00:00:00'); 
+0

Ihre 'UPDATE' Aussage arbeitete ok mit den Probendaten, die Sie zur Verfügung gestellt. Bitte überprüfen Sie [diese] (http://sqlfiddle.com/#!9/d879f/2) Demo. –

Antwort

-1
-- query wanted 
UPDATE test t1 INNER JOIN 
    (SELECT *, @id := @id + 1 AS new_id 
    FROM test CROSS JOIN (SELECT @id := 0) param 
    ORDER BY city, start_date) t2 
    ON t1.city = t2.city AND t1.start_date = t2.start_date 
    INNER JOIN 
    (SELECT *, @id2 := @id2 + 1 AS new_id 
    FROM test CROSS JOIN (SELECT @id2 := 0) param 
    ORDER BY city, start_date) t3 
    ON t2.new_id + 1 = t3.new_id AND t2.city = t3.city 
SET t1.end_date = DATE_SUB(t3.start_date, INTERVAL 1 SECOND) 
WHERE t1.end_date = '0001-01-01 00:00:00'; 

Hier finden Sie eine vollständige Demo.

SQL:

-- data 
CREATE TABLE `test` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `city` varchar(50) DEFAULT NULL, 
    `start_date` datetime DEFAULT NULL, 
    `end_date` datetime DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; 

INSERT INTO test (city, start_date, end_date) VALUES ('Paris','1995-01-01 00:00:00','1997-10-01 23:59:59'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','1997-10-02 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','2013-01-25 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Paris','2015-04-25 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2014-11-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2014-06-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2015-09-11 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Berlin','2015-10-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2001-01-01 00:00:00','0001-01-01 00:00:00'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2005-10-02 00:00:00','2006-10-02 23:59:59'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2006-10-03 00:00:00','2015-04-24 23:59:59'); 
INSERT INTO test (city, start_date, end_date) VALUES ('Milan','2015-04-25 00:00:00','0001-01-01 00:00:00'); 
select * from test; 

-- query wanted 
UPDATE test t1 INNER JOIN 
    (SELECT *, @id := @id + 1 AS new_id 
    FROM test CROSS JOIN (SELECT @id := 0) param 
    ORDER BY city, start_date) t2 
    ON t1.city = t2.city AND t1.start_date = t2.start_date 
    INNER JOIN 
    (SELECT *, @id2 := @id2 + 1 AS new_id 
    FROM test CROSS JOIN (SELECT @id2 := 0) param 
    ORDER BY city, start_date) t3 
    ON t2.new_id + 1 = t3.new_id AND t2.city = t3.city 
SET t1.end_date = DATE_SUB(t3.start_date, INTERVAL 1 SECOND) 
WHERE t1.end_date = '0001-01-01 00:00:00'; 

select * from test; 

Ausgang:

mysql> -- query wanted 
mysql> UPDATE test t1 INNER JOIN 
    -> (SELECT *, @id := @id + 1 AS new_id 
    -> FROM test CROSS JOIN (SELECT @id := 0) param 
    -> ORDER BY city, start_date) t2 
    -> ON t1.city = t2.city AND t1.start_date = t2.start_date 
    -> INNER JOIN 
    -> (SELECT *, @id2 := @id2 + 1 AS new_id 
    -> FROM test CROSS JOIN (SELECT @id2 := 0) param 
    -> ORDER BY city, start_date) t3 
    -> ON t2.new_id + 1 = t3.new_id AND t2.city = t3.city 
    -> SET t1.end_date = DATE_SUB(t3.start_date, INTERVAL 1 SECOND) 
    -> WHERE t1.end_date = '0001-01-01 00:00:00'; 
rom tesQuery OK, 6 rows affected (0.00 sec) 
Rows matched: 6 Changed: 6 Warnings: 0 

mysql> select * from test; 
+----+--------+---------------------+---------------------+ 
| id | city | start_date   | end_date   | 
+----+--------+---------------------+---------------------+ 
| 13 | Paris | 1995-01-01 00:00:00 | 1997-10-01 23:59:59 | 
| 14 | Paris | 1997-10-02 00:00:00 | 2013-01-24 23:59:59 | 
| 15 | Paris | 2013-01-25 00:00:00 | 2015-04-24 23:59:59 | 
| 16 | Paris | 2015-04-25 00:00:00 | 0001-01-01 00:00:00 | 
| 17 | Berlin | 2014-11-01 00:00:00 | 2014-05-31 23:59:59 | 
| 18 | Berlin | 2014-06-01 00:00:00 | 2015-09-10 23:59:59 | 
| 19 | Berlin | 2015-09-11 00:00:00 | 2015-09-30 23:59:59 | 
| 20 | Berlin | 2015-10-01 00:00:00 | 0001-01-01 00:00:00 | 
| 21 | Milan | 2001-01-01 00:00:00 | 2005-10-01 23:59:59 | 
| 22 | Milan | 2005-10-02 00:00:00 | 2006-10-02 23:59:59 | 
| 23 | Milan | 2006-10-03 00:00:00 | 2015-04-24 23:59:59 | 
| 24 | Milan | 2015-04-25 00:00:00 | 0001-01-01 00:00:00 | 
+----+--------+---------------------+---------------------+ 
12 rows in set (0.00 sec) 
+0

Wird in dieser Abfrage davon ausgegangen, dass der ID-Wert für jede Stadt sequenziell ist? Da merke ich die 'ID + 1' Join-Bedingung. In diesem Fall würde es leider nicht für alle Fälle funktionieren, da die Datensätze für jede Stadt möglicherweise nicht vollständig nacheinander eingefügt werden. –

+0

Müssen die Parameter für jeden Datensatz manuell eingegeben werden? –

+0

Also müssen die @id-Werte nicht ausgefüllt werden? –

Verwandte Themen