Pregunta

Hola, me encontré con este sitio en busca de soluciones para el evento se superpone en las tablas de MySQL. Yo estaba tan impresionado con la solución (que ya está ayudando) pensé que vería si podía conseguir más ayuda ...

De acuerdo, así que Joe quiere intercambiar los turnos de a con alguien en el trabajo. Él tiene una fecha de corte. Va a la forma de intercambio de cambios y que tire hacia arriba de la agenda de esta semana (o lo que queda de ella). Esto se hace con una consulta de base de datos. Sin sudar. Coge un cambio. A partir de este punto, se vuelve espinoso.

Por lo tanto, en primer lugar, la forma pasa el comienzo de cambios y cambiar fin a la secuencia de comandos. Se ejecuta una consulta para cualquier persona que tiene un desplazamiento que se superpone a este cambio. No pueden trabajar dos turnos a la vez, por lo que todos los identificadores de usuario de esta consulta se ponen en una lista de negro. Esta consulta se ve así:

SELECT DISTINCT user_id FROM shifts
WHERE
FROM_UNIXTIME('$swap_shift_start') < shiftend
AND FROM_UNIXTIME('$swap_shift_end') > shiftstart

A continuación, se ejecuta una consulta para todos los cambios que son a) la misma longitud (política de la empresa), y b) no se superponen con otros cambios Joe está trabajando.

Lo que tengo actualmente es algo como esto:

SELECT *
FROM shifts
AND shiftstart BETWEEN  FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ($busy_users) 
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
$conflict_dates
ORDER BY shiftstart, lastname

Ahora, ustedes probablemente se preguntan "¿cuál es $ conflict_dates ???"

Bueno, cuando Joe presenta el cambio de intercambio, se vuelven a cargar sus turnos para la semana en caso de que decida retirar el potencial del otro turno. Así que cuando se hace que la primera consulta, mientras que el guión es un bucle a través de sus opciones y dar salida, sino que también es la construcción de una cadena que se ve algo así como:

AND NOT(
'joe_shift1_start' < shiftend
AND 'joe_shift1_end' > shiftstart)
AND NOT(
'joe_shift2_start' < shiftend
AND 'joe_shift2_end' > shiftstart)
...etc

Para que la base de datos es cada vez una consulta bastante largo a lo largo de las líneas de:

SELECT *
FROM shifts
AND shiftstart BETWEEN  FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ('blacklisteduser1', 'blacklisteduser2',...etc) 
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
AND NOT(
'joe_shift1_start' < shiftend
AND 'joe_shift1_end' > shiftstart)
AND NOT(
'joe_shift2_start' < shiftend
AND 'joe_shift2_end' > shiftstart)
AND NOT(
'joe_shift3_start' < shiftend
AND 'joe_shift3_end' > shiftstart)
AND NOT(
'joe_shift4_start' < shiftend
AND 'joe_shift4_end' > shiftstart)
...etc
ORDER BY shiftstart, lastname

Por lo tanto, mi esperanza es que sea SQL tiene alguna manera genio de tratar con esto de una manera más simple, o que alguien puede señalar un director lógica fantástica que da cuenta de los posibles conflictos de una manera mucho más inteligente. (Observe el uso de la 'start> extremo, extremo

Gracias!

A

¿Fue útil?

Solución

Creo que debería ser capaz de excluir a otros turnos de Joe utilizando un selecto interior, en lugar de la cadena generada, algo como:

SELECT *
FROM shifts s1
AND shiftstart BETWEEN  FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ($busy_users) 
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
AND (SELECT COUNT(1) FROM shifts s2
     WHERE s2.user_id = $joes_user_id
     AND   s1.shiftstart < s2.shiftend
     AND   s2.shiftstart < s1.shiftend) = 0
ORDER BY shiftstart, lastname

Básicamente, cada fila tiene una consulta interna para el recuento de los cambios de Joe que se superponen, y se asegura de que es cero. Por lo tanto, sólo se devolverán las filas que no se solapan con cualquiera de los turnos existentes de Joe.

Otros consejos

Se puede cargar los valores joe_shift{1,2,3} en una tabla temporal y luego hacer una consulta a unirse en contra de ella, utilizando una combinación externa para encontrar único cambio que no coincide con ninguna:

CREATE TEMPORARY TABLE joes_shifts (
 shiftstart DATETIME
 shiftend   DATETIME
);
INSERT INTO joes_shifts (shiftstart, shiftend) VALUES
  ('$joe_shift1_start', '$joe_shift1_end'),
  ('$joe_shift2_start', '$joe_shift2_end'),
  ('$joe_shift3_start', '$joe_shift3_end'),
  ('$joe_shift4_start', '$joe_shift4_end');
-- make sure you have validated these variables to prevent SQL injection

SELECT s.*
FROM shifts s
  LEFT OUTER JOIN joes_shifts j
  ON (j.shiftstart < s.shiftend OR j.shiftend > s.shiftstart) 
WHERE j.shiftstart IS NULL
  AND s.shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
  AND s.user_id NOT IN ('blacklisteduser1', 'blacklisteduser2',...etc) 
  AND (TIME_TO_SEC(TIMEDIFF(s.shiftend,s.shiftstart)) = '$swap_shift_length');

Debido a la combinación externa izquierda, cuando no hay fila coincidente en joes_shifts, las columnas son NULL.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top