문제

이 사이트를 우연히 발견하여 MySQL 테이블의 이벤트 중첩 솔루션을 찾고 있습니다. 나는 솔루션에 깊은 인상을 받았습니다 (이미 도움이되고 있습니다) 나는 더 많은 도움을받을 수 있을지 알았습니다 ...

자, 조는 직장에서 누군가와 교대를 바꾸고 싶어합니다. 그는 법원 날짜가 있습니다. 그는 교대 스왑 양식으로 가서 이번 주 일정 (또는 남은 것)을 끌어 올린다. 이것은 DB 쿼리로 수행됩니다. 땀 없습니다. 그는 교대를 선택합니다. 이 시점부터, 그것은 가시가됩니다.

따라서 먼저 양식은 Shift Start 및 Shift End를 스크립트로 전달합니다. 이 변화와 겹치는 변화가있는 사람이라면 누구나 쿼리를 실행합니다. 두 번의 교대 근무를 한 번에 작동시킬 수 없으므로이 쿼리의 모든 사용자 ID가 블랙리스트에 올려집니다. 이 쿼리는 다음과 같습니다.

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

다음으로, 우리는 a) 동일한 길이 (회사 정책) 인 모든 교대에 대한 쿼리를 실행하고 Joe가 작동하는 다른 변화와 겹치지 않습니다.

내가 현재 가지고있는 것은 다음과 같습니다.

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

자, 당신은 아마도 "$ clict_dates가 무엇입니까 ???"라고 궁금해 할 것입니다.

Joe가 스왑 시프트를 제출할 때 다른 시프트의 잠재력을 확인하기로 결정한 경우 일주일에 대한 교대 근무를 다시로드합니다. 따라서 첫 번째 쿼리를 할 때 스크립트가 자신의 선택을 반복하고 출력하는 동안 다음과 같은 문자열도 구축하고 있습니다.

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

데이터베이스가 다음의 줄을 따라 꽤 긴 쿼리를 받고 있습니다.

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

그래서, 내 희망은 SQL이 이것을 더 간단한 방식으로 다루는 천재적인 방법을 가지고 있거나 누군가가 훨씬 더 똑똑한 방식으로 잠재적 갈등을 설명하는 환상적인 논리적 원칙을 지적 할 수 있기를 희망합니다. ( 'start> end, end <start'의 사용에 주목하십시오.

감사!

도움이 되었습니까?

해결책

생성 된 문자열 대신 내부 선택을 사용하여 Joe의 다른 교대를 다음과 같은 것입니다.

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

기본적으로 각 행에는 Joe의 교대 수가 겹치는 내부 쿼리가 있으며 0임을 확인합니다. 따라서 Joe의 기존 교대 근무와 겹치지 않는 행만 반환됩니다.

다른 팁

당신은로드 할 수 있습니다 joe_shift{1,2,3}임시 테이블에 값을 획득 한 다음 외부 조인을 사용하여 쿼리를 수행하여 다음과 일치하지 않는 시프트 만 찾습니다.

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

왼쪽 외부 조인으로 인해 일치하는 행이 없을 때 joes_shifts, 열은 null입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top