2017-10-06 157 views
0

我有以下的列的預訂表:MySQL的算兩個日期之間的星期在一個表

編號,日期,結束日期

我想知道哪些日子已經過了最預訂我的數據集。

我可以在開始日期使用dayofweek(),也可以使用這個數字並使用count(*)。但我也想包括從預訂開始到結束之間的日子。

一個例子輸出wouldbe

dayofweek  count(*) 
1    1 
2    1 
3    1 
4    2 
5    3 
6    3 
7    1 

爲以下設置

id  start_date   end_date 
1  2017-10-01   2017-10-07 
2  2017-10-04   2017-10-07 
3  2017-10-06   2017-10-08 
+0

使用日曆表(包含您需要的所有日期)並使用BETWEEN條件將其加入到表中。 –

+0

不幸的是,10月份是在星期天開始的。 – Strawberry

回答

0

我假設你想知道的東西比如在開始和結束之間的每個日期有多少個房間被填滿。這裏的「訣竅」是,從開始/結束之間的很長一段時間將重複一天或一週,並且/或者一週的結束日可能小於一週的開始日。所以,我有:

  1. 產生100000個日期(1每行)的列表
  2. 加入你的表的開始/結束
  3. 轉換的各參加行的週數日之間的日期算
  4. 左接合到清單1至7,並計數步驟中的行3

注意:如果END_DATE是「簽出日期」,那麼它可能有必要扣除1天從每個記錄要補償(這不是在下面做)。

這種方法可用於審查在這裏SQL Fiddle

的MySQL 5.6架構設置

CREATE TABLE Table1 
    (`id` int, `start_date` datetime, `end_date` datetime) 
; 

INSERT INTO Table1 
    (`id`, `start_date`, `end_date`) 
VALUES 
    (1, '2017-09-21 00:00:00', '2017-10-07 00:00:00'), ## added this row 
    (1, '2017-10-01 00:00:00', '2017-10-07 00:00:00'), 
    (2, '2017-10-04 00:00:00', '2017-10-07 00:00:00'), 
    (3, '2017-10-06 00:00:00', '2017-10-08 00:00:00') 
; 

查詢

set @commence := str_to_date('2000-01-01','%Y-%m-%d') 

select 
    w.dy 
    , count(t.wdy) 
from (
     select 1 dy union all select 2 dy union all select 3 dy union all 
     select 4 dy union all select 5 dy union all select 6 dy union all select 7 dy 
    ) w 
left join (
     select DAYOFWEEK(cal.dy) wdy 
     from (
       select adddate(@commence ,t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dy 
       from ( select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t0 
       cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t1 
       cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2 
       cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3 
       cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4 
     ) cal 
     INNER JOIN Table1 t on cal.dy between t.start_date and t.end_date 
    ) t on w.dy = t.wdy 
group by 
    w.dy 

Results

| dy | count(t.wdy) | 
|----|--------------| 
| 1 |   4 | 
| 2 |   3 | 
| 3 |   3 | 
| 4 |   4 | 
| 5 |   5 | 
| 6 |   6 | 
| 7 |   6 | 

另見:How to get list of dates between two dates in mysql select query那裏接受的答案是一組交叉的基礎上加入產生從提名日起10萬周的日期。然而,我修改了語法(顯式交叉連接語法),一個參數作爲起點,並使用union all來提高效率。

+0

這個工程!然而,我有一個100行的測試表,目前需要20秒,如果說我擁有100,000個,這個查詢運行得如何? –

+0

a。我無法真正預測到,而且b。它很可能取決於你的索引,並且c。代替動態生成的日期列表,您可以改爲創建一個表並將其也編入索引。請始終參考性能詳情的解釋計劃。如果問一個關於性能的新問題,包括表和相關索引的完整DDL。加解釋計劃輸出(如文本) –

0

您可以用遞歸表實現這一點:

WITH cte AS 
(
    SELECT DATE_ADD(start_date INTERVAL 1 DAY) AS date, end_date, DAYOFWEEK(start_date) AS dw from bookings 
    UNION ALL 
    SELECT DATE_ADD(start_date INTERVAL 1 DAY), end_date, DAYOFWEEK(date) 
    FROM cte WHERE date <= end_date 
) 
SELECT COUNT(*), dw FROM cte GROUP BY dw 
+1

附加說明:遞歸表可能不可用,具體取決於所使用的版本(即MariaDB <10.2不可能) –

+0

使用MySQL 5。7 –

相關問題