Question

Hé, je suis tombé sur ce site à la recherche de solutions pour l'événement chevauche dans les tableaux mySQL. J'ai été tellement impressionné par la solution (ce qui est déjà apporté leurs améliorations) Je pensais voir si je pouvais obtenir plus d'aide ...

Ok, donc Joe veulent échanger de quarts de travail à avec quelqu'un au travail. Il a une date d'audience. Il va à la forme d'échange de décalage et tirer vers le haut le calendrier de cette semaine (ou ce qu'il en reste). Cela se fait avec une requête DB. Pas de transpiration. Il choisit un changement. De ce point, il devient épineuse.

Alors, d'abord, la forme passe le début de décalage et passer fin au script. Il exécute une requête pour toute personne qui a un changement qui chevauche ce changement. Ils ne peuvent pas travailler deux quarts de travail à la fois, tous les ID utilisateur de cette requête sont mis sur une liste noire. Cette requête ressemble à:

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

Ensuite, nous courons une requête pour tous les changements qui sont a) la même longueur (politique de l'entreprise), et b) ne se chevauchent pas avec d'autres quarts de travail Joe travaille.

Ce que j'ai actuellement est quelque chose comme ceci:

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

Maintenant, vous vous demandez probablement "ce qui est $ conflict_dates ???"

Eh bien, quand Joe soumet le changement de swap, il recharge ses quarts de travail pour la semaine au cas où il décide de vérifier le potentiel d'un autre quart de travail. Alors, quand il fait la première requête, alors que le script est une boucle à travers ses choix et la sortie, il est également la construction d'une chaîne qui ressemble un peu comme:

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

Alors que la base de données devient une requête assez long le long des lignes 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

Alors, mon espoir est que soit SQL a une certaine façon de génie de faire face à cela d'une manière plus simple, ou que quelqu'un peut signaler un principe logique fantastique qui tient compte des conflits potentiels d'une manière beaucoup plus intelligente. (Notez l'utilisation du « début> fin, fin

Merci!

Était-ce utile?

La solution

Je pense que vous devriez être en mesure d'exclure d'autres changements de Joe à l'aide d'une sélection au lieu de la chaîne générée intérieure, quelque chose comme:

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

Fondamentalement, chaque ligne a une requête interne pour le comptage des changements de Joe qui se chevauchent, et fait en sorte qu'il est égal à zéro. Ainsi, seules les lignes qui ne se chevauchent pas avec aucun des quarts de travail existants de Joe seront retournés.

Autres conseils

Vous pouvez charger les valeurs joe_shift{1,2,3} dans une table temporaire puis effectuez une requête à se joindre contre elle, en utilisant une jointure externe pour trouver seul changement qui ne correspondent pas:

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');

En raison de la LEFT OUTER JOIN, lorsqu'il n'y a pas de ligne correspondante dans joes_shifts, les colonnes sont NULL.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top