Ich arbeite an einem Zeitmesssystem und versuche zu ermitteln, ob es für jede Person früh oder zu spät für die geplante Schicht ist. Die Tabelle "TB_Scan" hatte ursprünglich den Personencode und die Abtastzeit, bei der es sich um ein Datetime-Feld handelt. Aufgrund der Frage, die ich hatte, entschied ich mich, die Felder scYear, scMonth und scDay hinzuzufügen, weil ich dachte, es könnte helfen.Wie macht man mehrere LINKE VERBINDUNGEN mit ODER verwenden Sie vollständig einen zusammengesetzten Index?
Es ist ein System, das berechnet, wie die Benutzer ihre Fingerabdrücke beim Betreten/Verlassen des Arbeitsplatzes scannen. Ich weiß nicht, wie es auf Englisch heißt. Ich muss feststellen, ob der Benutzer spät am Morgen ist und ob der Benutzer die Arbeit vorzeitig verlässt.
Diese Tabelle tb_scan
enthält Datum und Uhrzeit, zu der ein Benutzer einen Fingerabdruck scannt.
CREATE TABLE `tb_scan` (
`scpercode` varchar(6) DEFAULT NULL,
`scyear` varchar(4) DEFAULT NULL,
`scmonth` varchar(2) DEFAULT NULL,
`scday` varchar(2) DEFAULT NULL,
`scscantime` datetime,
KEY `all` (`scyear`,`scmonth`,`scday`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Es hat 100.000 Zeilen, so etwas wie dieses
scpercode scyear scmonth scday scdateandtime
000001 2010 10 10 2016-01-10 08:02:00
000001 2010 10 10 2016-01-02 17:33:00
000001 2010 10 11 2016-01-11 07:48:00
000001 2010 10 11 2016-01-11 17:29:00
000002 2010 10 10 2016-01-10 17:31:00
000002 2010 10 10 2016-01-02 17:28:00
000002 2010 10 11 2016-01-11 05:35:00
000002 2010 10 11 2016-01-11 05:29:00
Und diese tb_workday
Tabelle enthält jedes Datum
CREATE TABLE `tb_workday` (
`wdpercode` varchar(6) DEFAULT NULL,
`wdshift` varchar(1) DEFAULT NULL,
`wddate` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Es hat Zeilen mit Datum Reihenfolge wie folgt aus:
wdpercode wdshift wddate
000001 1 2010-10-10
000001 1 2010-10-11
000001 1 2010-10-12
000001 1 2010-10-13
000002 2 2010-10-10
000002 2 2010-10-11
000002 2 2010-10-12
000002 2 2010-10-13
Es ist eine weitere tb_shift
Tabelle mit Schaltzeit
CREATE TABLE `tb_shift` (
`shiftcode` varchar(1) DEFAULT NULL,
`shiftbegin2` varchar(4) DEFAULT NULL,
`shiftbegin` varchar(4) DEFAULT NULL,
`shiftmid` varchar(4) DEFAULT NULL,
`shiftend` varchar(4) DEFAULT NULL,
`shiftend2` varchar(4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
shiftcode shiftbegin2 shiftbegin shiftmid shiftend shiftend2
1 04:00:00 08:00:00 12:00:00 17:30:00 21:30:00
2 12:00:00 17:30:00 21:00:00 05:30:00 09:30:00
ich, dass an jedem Tag bestimmen will, ist der Mitarbeiter zu spät zur Arbeit kommt oder Blätter arbeiten früh, und zu welchem Zeitpunkt. Hier
SELECT wdpercode,wddate,shiftbegin,shiftend,time(tlate.scscantime) wdlate,time(tearly.scscantime) wdearly
FROM tb_workday
LEFT JOIN tb_shift
ON wdshift=shiftcode
LEFT JOIN tb_scan tlate
ON wdpercode=tlate.scpercode
AND tlate.scyear=year(wddate)
AND tlate.scmonth=month(wddate)
AND (tlate.scday=day(wddate)
OR tlate.scday=day(wddate)+1)
AND tlate.scscantime>=ADDDATE(CONCAT(wddate,' ',shiftbegin),INTERVAL IF(shiftbegin2>shiftbegin,1,0) DAY)
AND tlate.scscantime<=ADDDATE(CONCAT(wddate,' ',shiftmid),INTERVAL IF(shiftbegin2>shiftmid,1,0) DAY)
LEFT JOIN tb_scan tearly
ON wdpercode=tearly.scpercode
AND tearly.scyear=year(wddate)
AND tearly.scmonth=month(wddate)
AND (tearly.scday=day(wddate)
OR tearly.scday=day(wddate)+1)
AND tearly.scscantime>ADDDATE(CONCAT(wddate,' ',shiftmid),INTERVAL IF(shiftbegin2>shiftmid,1,0) DAY)
AND tearly.scscantime<ADDDATE(CONCAT(wddate,' ',shiftend),INTERVAL IF(shiftbegin2>shiftend,1,0) DAY)
ist das Beispiel eines Ausgangs:
wdpercode wddate shiftbegin shiftend wdlate wdearly
000001 2016-01-10 08:00:00 17:30:00 08:02:00 (null)
000001 2016-01-11 08:00:00 17:30:00 (null) 17:29:00
000002 2016-01-11 17:30:00 05:30:00 17:31:00 (null)
000002 2016-01-11 17:30:00 05:30:00 (null) 05:29:00
diese ADDDATE(CONCAT(wddate,' ',shiftbegin),INTERVAL IF(shiftbegin2>shiftbegin,1,0) DAY)
ist für Mitarbeiter, die in der Nachtschicht arbeiten, so hat es 1 Tag in die Schaltzeit hinzufügen
Das Problem Wenn ich einen Index für scscantime
erstelle, weigert sich MySQL, ihn für den Vergleich zu verwenden (>=
, <=
, >
, <
). finden Sie in diesem Thread Why does MySQL not use an index for a greater than comparison?
Aus diesem Grund Ich habe die scyear
, scmonth
und scday
Felder und kombinieren sie in einem Index zusammen mit scpercode
. Und ich muss sicherstellen, dass es auch für Arbeiter berechnet wird, die in Nachtschicht arbeiten, also muss ich es mit OR scday=day(wddate)+1
Bedingung hinzufügen.
Bevor ich die OR-Bedingung hinzugefügt habe, war das Ergebnis EXPLAIN
52 Zeilen. Aber als ich die OR scday=day(wddate)+1
Bedingung hinzufügte, wurde das EXPLAIN
Ergebnis 364 Zeilen, das bedeutet, dass MySQL keinen SCTAG-Teil des Index verwendet hat. Gibt es eine Möglichkeit, den gesamten Index zu verwenden, so dass das Ergebnis EXPLAIN
52 Zeilen wird? Ich habe auch versucht die +1
Teil zu entfernen und das Ergebnis ist auch 52.
Möchten Sie wirklich 'table2.day = table1.month' und' table2.day = table1.month + 1' vergleichen? – KaeL
@KaeL oops Sorry falsches Feld –
Was ist die EXPLAIN-Ausgabe von diesem: 'EXPLAIN SELECT * FROM Tabelle1 LINKE VERBINDUNG Tabelle2 ON Tabelle2.Jahr = Tabelle1.Jahr UND Tabelle2.Monat = Tabelle1.Monat UND Tabelle2.Tag = Tabelle1.TAG UNION SELECT * FROM table1 LINKS JOIN table2 ON table2.year = table1.year UND table2.month = table1.month UND table2.day = table1.day + 1' – 1000111