Domanda

Ehi, sono incappato in questo sito alla ricerca di soluzioni per l'evento si sovrappone in tabelle MySQL. Sono rimasto così colpito con la soluzione (che sta aiutando già) ho pensato di vedere se ho potuto ottenere un po 'di aiuto ...

Ok, Joe vuole di di scambiare turni con qualcuno sul posto di lavoro. Ha una data della corte. Va a forma spostamento di swap e tirare su programma di questa settimana (o ciò che ne resta). Questo viene fatto con una query DB. Non c'è problema. Prende un cambiamento. Da questo punto, diventa pungente.

Quindi, in primo luogo, la forma passa l'inizio turno e fine turno allo script. Si esegue una query per chi ha un cambiamento che si sovrappone questo cambiamento. Essi non possono lavorare su due turni in una sola volta, in modo che tutti gli ID utente da questa ricerca sono messi su una lista nera. Questa interrogazione si presenta come:

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

Successivamente, eseguire una query per tutti gli spostamenti che sono a) la stessa lunghezza (politica aziendale), e b) non si sovrappongono con altri turni Joe sta lavorando.

Quello che ho attualmente è qualcosa di simile:

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

Ora, si sono probabilmente chiedendo "che cosa è $ conflict_dates ???"

Bene, quando Joe sottopone il turno di swap, si ricarica i suoi spostamenti per la settimana nel caso in cui decida di controllare il potenziale di un altro turno. Così, quando lo fa prima interrogazione, mentre lo script è scorrendo ed emettere le sue scelte, ma è anche la costruzione di una stringa che sembra un po 'come:

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

In modo che il database è sempre una bella lunga interrogazione lungo le linee di:

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

Quindi, la mia speranza è che o SQL ha un modo geniale di affrontare questo in un modo più semplice, o che qualcuno può indicare un fantastico principio logico che rappresenta i potenziali conflitti in un modo molto più intelligente. (Si noti l'uso del 'inizio> fine, fine

Grazie!

A

È stato utile?

Soluzione

Credo che si dovrebbe essere in grado di escludere altre turni di Joe utilizzando un select interna al posto della stringa generata, qualcosa come:

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

In sostanza, ogni riga ha una query interna per il conteggio di turni di Joe che si sovrappongono, e fa in modo che sia zero. Così, saranno restituite solo le righe che non si sovrappongono con uno qualsiasi dei turni esistenti di Joe.

Altri suggerimenti

Si potrebbe caricare i valori joe_shift{1,2,3} in una tabella temporanea e poi fare una query di unirsi contro di essa, utilizzando un outer join di trovare solo cambiamento che non corrisponde a nessuno:

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

A causa della LEFT OUTER JOIN, quando non v'è nessuna riga corrispondente nella joes_shifts, le colonne sono NULL.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top