Bad Wolf
Bad Wolf

Reputation: 8349

Select Four Concurrent Events Meeting a Criteria MySQL

I have a MySQL query which is used to determine if a piece of equipment, which there are only 3 of, is being used by four concurrent events at once. I have a working query, but it seems inefficient and I am curious if there is a better way to do the select.

Table structure (columns not relevant to the query have been removed) The table currently contains around 7-8k rows.

CREATE TABLE IF NOT EXISTS `tc_event` (
  `WorkOrderNumber` int(11) NOT NULL DEFAULT '0',
  `EventName` varchar(120) DEFAULT NULL,
  `CrewStartTime` datetime DEFAULT NULL,
  `CrewEndTime` datetime DEFAULT NULL,
  `SoundConsole` varchar(30) DEFAULT NULL,
  `Canceled` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`WorkOrderNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Current (working) query:

SELECT UNIX_TIMESTAMP(T1.CrewStartTime) AS ConflictDate
            FROM tc_event T1, tc_event T2, tc_event T3, tc_event T4
            WHERE
                (T1.CrewStartTime BETWEEN T2.CrewStartTime AND T2.CrewEndTime)
                AND (T1.CrewStartTime BETWEEN T3.CrewStartTime AND T3.CrewEndTime)
                AND (T1.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
                AND (T2.CrewSTartTime BETWEEN T3.CrewStartTime AND T3.CrewEndTime)
                AND (T2.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
                AND (T3.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
                AND T1.WorkOrderNumber != T2.WorkOrderNumber
                AND T1.WorkOrderNumber != T3.WorkOrderNumber
                AND T1.WorkOrderNumber != T4.WorkOrderNumber
                AND T2.WorkOrderNumber != T3.WorkOrderNumber
                AND T2.WorkOrderNumber != T4.WorkOrderNumber
                AND T3.WorkOrderNumber != T4.WorkOrderNumber
                AND T1.CrewStartTime > NOW()
                AND T1.SoundConsole = '12-Chan/PA-12'
                AND T2.SoundConsole = '12-Chan/PA-12'
                AND T3.SoundConsole = '12-Chan/PA-12'
                AND T4.SoundConsole = '12-Chan/PA-12'
                AND (T1.Canceled = 0 AND T1.EventName NOT LIKE '%*NOTC*%')
                AND (T2.Canceled = 0 AND T2.EventName NOT LIKE '%*NOTC*%')
                AND (T3.Canceled = 0 AND T3.EventName NOT LIKE '%*NOTC*%')
                AND (T4.Canceled = 0 AND T4.EventName NOT LIKE '%*NOTC*%')
            GROUP BY DATE(T1.CrewStartTime)
            ORDER BY T1.CrewStartTime

Query EXPLAIN statement:

Query EXPLAIN

Upvotes: 1

Views: 60

Answers (2)

Gordon Linoff
Gordon Linoff

Reputation: 1269443

You just want to know if there is a conflict, which is 4 users at the same time. For this, you can just look at the event start time and check how many concurrent events there are:

select soundconsole, st.CrewStartTime, count(*)
from (select distinct CrewStartTime, soundconsole
      from tc_event
     ) st join
     tc_event e
     on st.CrewStratTime between e.CrewStartTime and e.CrewEndTime and
        st.soundconsole = e.soundconsole
group by st.CrewStartTime, tc.soundconsole
having count(*) >= 4

Upvotes: 1

Wolph
Wolph

Reputation: 80011

Start with changing the inequalities to less than/greater than comparisons. That simplifies things a lot as well:

SELECT UNIX_TIMESTAMP(T1.CrewStartTime) AS ConflictDate
        FROM tc_event T1, tc_event T2, tc_event T3, tc_event T4
        WHERE
            (T1.CrewStartTime BETWEEN T2.CrewStartTime AND T2.CrewEndTime)
            AND (T2.CrewSTartTime BETWEEN T3.CrewStartTime AND T3.CrewEndTime)
            AND (T3.CrewStartTime BETWEEN T4.CrewStartTime AND T4.CrewEndTime)
            AND T1.WorkOrderNumber < T2.WorkOrderNumber
            AND T2.WorkOrderNumber < T3.WorkOrderNumber
            AND T3.WorkOrderNumber < T4.WorkOrderNumber
            AND T1.CrewStartTime > NOW()
            AND T1.SoundConsole = '12-Chan/PA-12'
            AND T2.SoundConsole = '12-Chan/PA-12'
            AND T3.SoundConsole = '12-Chan/PA-12'
            AND T4.SoundConsole = '12-Chan/PA-12'
            AND (T1.Canceled = 0 AND T1.EventName NOT LIKE '%*NOTC*%')
            AND (T2.Canceled = 0 AND T2.EventName NOT LIKE '%*NOTC*%')
            AND (T3.Canceled = 0 AND T3.EventName NOT LIKE '%*NOTC*%')
            AND (T4.Canceled = 0 AND T4.EventName NOT LIKE '%*NOTC*%')
        GROUP BY DATE(T1.CrewStartTime)
        ORDER BY T1.CrewStartTime

After that you would do good to add an index on CrewStartTime, that should help quite a bit in performance. Indexes on other columns which you filter by could also be helpful.

Upvotes: 1

Related Questions