2012-12-11 45 views
0

我試圖選擇MySQL數據庫中約會之間的前10個空時隙。MySQL:更改每個選定行的用戶變量

約會表基本上有3個字段:appointment_id INT,startDateTime DATETIME和endDateTime DATETIME。

我們可以設想一些這樣的數據(爲了簡單起見,我已經把日期部分留在了日期時間之外,所以讓我們考慮這些時間是在同一天)。另外,數據是通過有序的startDateTime:

4 | 09:15:00 | 09:30:00 
5 | 09:30:00 | 09:45:00 
8 | 10:00:00 | 10:15:00 
3 | 10:30:00 | 10:45:00 
7 | 10:45:00 | 11:00:00 
2 | 11:00:00 | 11:15:00 
1 | 11:30:00 | 12:00:00 

所以我的目標是提取:

00:00:00 | 09:15:00 
09:45:00 | 10:00:00 
10:15:00 | 10:30:00 
11:15:00 | 11:30:00 

在結束了這樣:

SET @myStart = '2012-10-01 09:15:00'; 
SET @myEnd = NULL; 
SET @prevEnd = NULL; 
SELECT a.endDateTime, b.startDateTime, @myStart := a.endDateTime 
FROM appointment a, appointment b, (
    SELECT @myEnd := min(c.startDateTime) 
    FROM appointment c 
    WHERE c.startDateTime >= @myStart 
    ORDER BY startDateTime ASC 
) as var , 
(SELECT @prevEnd := NULL) v 
WHERE a.appointment_id = (
    SELECT appointment_id 
    FROM (
     SELECT appointment_id, max(endDateTime), @prevEnd := endDateTime 
     FROM appointment d 
     WHERE (@prevEnd IS NULL OR @prevEnd = d.startDateTime) 
      AND d.startDateTime >= @myEnd 
    ) as z 
) 
    AND b.startDateTime > a.endDateTime 
ORDER BY b.startDateTime ASC LIMIT 0,10; 

這不返回任何結果。我想這是因爲我的用戶定義變量的初始化不正確(剛發現它們,我可能完全錯誤地使用它們)。

如果我只運行第一個子查詢,其目標是在@myStart之後的第一個約會處初始化@myEnd,則可以看到它實際上返回了09:15:00。

第二個子查詢(SELECT @prevEnd := NULL) v旨在每次在主查詢中選擇一行時,將@prevEnd設置回NULL。我不太確定它是如何工作的...

最後一個子查詢的含義是,從一個空的@prevEnd和一個初始化的@myEnd開始,選擇約會之後存在差距。如果與查詢的其餘部分分開,我可以驗證它是否也可以工作。

對於我能做些什麼來解決查詢,關於我該怎麼做/應該這樣做,或者甚至可能做到這一點,你有什麼建議嗎?

非常感謝。

編輯:我已經編輯這樣說:

SELECT * 
    FROM (
     SELECT COALESCE(s1.endDateTime, '0000-00-00 00:00:00') AS myStart, MIN(s2.startDateTime) AS minSucc 
     FROM appointment s1 
     RIGHT JOIN appointment s2 ON s1.endDateTime < s2.startDateTime 
      AND s1.radiologyroom_id = s2.radiologyroom_id 
     WHERE s1.startDateTime >= '2012-10-01 00:00:00' 
      AND s1.radiologyroom_id =174 
      AND s1.endDateTime < '2013-01-01 00:00:00' 
     GROUP BY myStart 
     ORDER BY s1.startDateTime 
    )s 
WHERE NOT 
    EXISTS (
     SELECT NULL 
     FROM appointment 
     WHERE startDateTime >= myStart 
      AND endDateTime <= minSucc 
      AND radiologyroom_id =174 
     ORDER BY startDateTime 
    ) 

,並在14.6秒檢索369行了6530條記錄

回答

1

如果有ids之間沒有間隙,並且id總是增加,你可以這樣使用:

SELECT coalesce(s1.endDateTime, '0000-00-00 00:00:00'), s2.startDateTime 
FROM 
    slots s1 right join slots s2 
    on s1.appointment_id=s2.appointment_id-1 
WHERE coalesce(s1.endDateTime, '0000-00-00 00:00:00')<s2.startDateTime 
LIMIT 10 

編輯:你也可以試試這個:

SELECT * FROM 
    (SELECT 
    coalesce(s1.endDateTime, '0000-00-00 00:00:00') as start, 
    min(s2.startDateTime) minSucc 
    from slots s1 right join slots s2 
     on s1.endDateTime<s2.startDateTime 
    group by start) s 
WHERE 
    not exists (select null 
       from slots 
       where startDateTime>=start 
       and endDateTime<=minSucc) 

EDIT2:我承認,我不是用變量查詢多之實踐,但是這看起來像它可以工作:

select d1, d2 from (
    select 
    @previous_end as d1, 
    s.startDateTime as d2, 
    @previous_end:=s.endDateTime 
    from (select startDateTime, endDateTime from slots order by startDateTime) s, 
     (select @previous_end := '0000-00-00 00:00:00') t) s 
where d1<d2 
+0

可悲的是DB是沒有設計這樣的約束。我應該提到它。不管怎麼說,還是要謝謝你! – ixM

+0

@ixM第二個查詢應該仍然給出相同的結果,即使存在間隙或者行沒有排序,但可能會更慢......如果存在重疊間隔,它將不起作用,否則它應該沒關係。 – fthiella

+0

我修改了它(請參閱編輯),它可以工作,但速度很慢(完成10個結果大約需要7秒)。有沒有辦法改善這一點?非常感謝! – ixM