2017-05-02 4 views
0

Ich habe eine Aktivität changelog von Offizieren, die aktiv/inaktiv werden.Finden Sie Fehler in einer Sequenz

OfficerID ChangeTo ChangeDate 
1   active  2017-05-01 
1   active  2017-05-02 
1   inactive 2017-05-04 
6   active  2013-09-09 
6   inactive 2016-04-14 
6   recruit 2016-06-22 
6   active  2016-06-23 
6   inactive 2017-04-30 

Im obigen Fall ist die Offizier-ID 1 vom 1. Mai bis zum 4. Mai aktiv.

Dies ist im Wesentlichen eine "Hauswirtschaft" Aufgabe. Die zweite Zeile ist nicht erforderlich und sollte gelöscht werden. Ich möchte dies innerhalb eines MySQL-Verfahrens tun, das ein Ereignis nach einem Zeitplan verknüpft. Ich brauche eine Abfrage, die diese Zeilen identifizieren kann, aber ich weiß nicht wie.

In einem früheren System hatte ich eine geordnete Liste durchlaufen und den aktuellen Wert mit dem Wert der vorherigen Zeile verglichen. Ich habe gelesen, dass Schleifen in MySQL nicht erwünscht sind, also versuche ich herauszufinden, wie man das nur mit Abfragen macht.

Ich habe versucht, die folgenden:

SELECT 
    a.ActivityID, a.OfficerID, a.ChangeTo, a.ChangeDate 
FROM 
    tbl_Officers_Activity as a 
    INNER JOIN tbl_Officers_Activity AS b 
     ON a.OfficerID = b.OfficerID 
     AND a.ChangeDate > b.ChangeDate 
     AND a.ChangeTo = b.ChangeTo 
    INNER JOIN tbl_Officers_Activity AS c 
     ON a.OfficerID = c.OfficerID 
     AND a.ChangeDate < c.ChangeDate 
     AND a.ChangeTo <> c.ChangeTo 
ORDER BY 
    OfficerID, 
    ChangeDate; 

Ich hatte gehofft, ich die Kriterien irgendwie einbinden konnte ich in die Notwendigkeit verbindet, aber ich bin ratlos. jede Hilfe würde sehr geschätzt werden. Diese

Antwort

0

ist, was Sie brauchen

SQLFIddle Demo

select a1.officerid,a1.changedate,a1.changeto_a as changeto 
From 
(select a.officerid,a.changedate,max(a.changeto) as changeto_a,count(*) as rnk 
from tbl_Officers_Activity a 
inner join tbl_Officers_Activity b 
on a.OfficerID=b.OfficerID 
and a.ChangeDate>=b.ChangeDate 
group by a.officerid,a.changedate) a1 
left join 
(select a.officerid,a.changedate,max(a.changeto) as changeto_b,count(*) +1 as rnk 
from tbl_Officers_Activity a 
inner join tbl_Officers_Activity b 
on a.OfficerID=b.OfficerID 
and a.ChangeDate>=b.ChangeDate 
group by a.officerid,a.changedate) b1 
on a1.officerid=b1.officerid 
and a1.rnk=b1.rnk 
where changeto_a = changeto_b 

Erläuterung:

MySQL hat nicht row_Number Funktion, so Zuerst hatte ich es abzuleiten. Ich habe diese Abfrage verwendet, um row_number, die Namen wie rnk in der Abfrage ist. Rufen Sie die Tabelle a1.

(select a.officerid,a.changedate,max(a.changeto) as changeto_a,count(*) as rnk 
from tbl_Officers_Activity a 
inner join tbl_Officers_Activity b 
on a.OfficerID=b.OfficerID 
and a.ChangeDate>=b.ChangeDate 
group by a.officerid,a.changedate) 

Jetzt als MySQL, ich habe es nicht LEAD Funktion auch haben abgeleitet, indem die obige Abfrage erneut verwenden und die rnk-rnk+1 ändern, es ruft b1.

Jetzt LEAD, ich left joineda1 mit b1

Jetzt zu replizieren mit einer where-Klausel gleiche changeto zu finden, können Sie Ihre Ausgabe erhalten.

+0

Dankes- für Ihre Eingabe. Am Ende hatte ich eine ähnliche Lösung wie Sie, aber wenn Sie mit mehr Daten arbeiten, kommt Ihre Lösung ungenau zurück. Ich bin daran interessiert zu verstehen, warum dies der Fall ist. Können Sie sich darüber Gedanken machen? – ShadeBlack

+0

Verwenden Sie nach Möglichkeit die Geige, die ich angegeben habe, und fügen Sie einige Zeilen hinzu, um das falsche Verhalten zu replizieren. Es ist nicht sehr offensichtlich von den Screenshots. – Utsav

0

Meine Lösung war am Ende ähnlich zu dem, was Utsav gepostet hatte, aber nachdem ich seine Lösung mit meiner verglichen hatte, fand ich, dass meine genau war und seine ungenau. solution results comparison

Für meine Lösung, ich erstellen eine temporäre Tabelle für die erste geordnete Liste mit einem Auto inkrementellen Primärschlüssel. Klonen Sie dann die temporäre Tabelle und verbinden Sie sich mit dem primären pk, der mit sich selbst +1 übereinstimmt und auch gleich der Statusänderung ist.

mein Verfahren endet wie folgt auf:

-- create temp table 
DROP TABLE IF EXISTS tmp_act; 
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_act (
    AutoID INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    ActivityID INT(11), 
    OfficerID INT(11), 
    ChangeTo text 
); 

-- temp data 
insert into tmp_act (ActivityID,OfficerID,ChangeTo) 
    SELECT 
     a.ActivityID, a.OfficerID, a.ChangeTo 
    FROM 
     tbl_Officers_Activity as a 
    ORDER BY 
     OfficerID, 
     ChangeDate; 

-- housekeeping 
DROP TABLE IF EXISTS tmp_act1; 
DROP TABLE IF EXISTS tmp_act2; 
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_act1 AS (SELECT * FROM tmp_act); 
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_act2 AS (SELECT * FROM tmp_act); 
SELECT 
    a.AutoID, a.ActivityID, a.OfficerID, a.ChangeTo 
FROM 
    tmp_act1 as a 
    INNER JOIN tmp_act2 AS b 
     ON a.OfficerID = b.OfficerID 
     AND a.ChangeTo = b.ChangeTo 
     AND a.AutoID = b.AutoID+1; 
Verwandte Themen