2015-12-09 70 views
0

我知道有幾十個「選擇第一行」的問題,但我有一個有趣的情況,我認爲我不能用LIMIT修復。MySQL選擇表格的第一行

我試圖顯示在開始和結束日期之間可用的連續N天可用的屬性。我很親密。

我打算把這個查詢拆分成多個位,因爲它是一個很大的問題。

阻止日期(第1部分)

(SELECT c.id,c.property_id,c.start_date,c.end_date FROM property_calendar as c WHERE c.start_date <= '.$endQuote.' AND c.end_date >= '.$startQuote) 
UNION 
(SELECT l.id,l.property_id,l.start_date,l.end_date FROM lease as l WHERE l.start_date <= '.$endQuote.' AND l.end_date >= '.$startQuote.' AND l.status < 6) 
ORDER BY start_date ASC 

這一聯合搗毀了兩個日曆在一起,便於比較。每個條目都有一個start_date和end_date。落在(包括開始和結束)之間的日期被認爲是不可用的。

計算器(部分2)

SELECT IFNULL(DATEDIFF(IFNULL(ct2.start_date, '2015-12-09'), ct1.end_date) - 1, 0) as open_days, 
(DATEDIFF(ct1.start_date, '2015-12-01') - 1) as first_open, 
IFNULL(DATEDIFF(LEAST(ct1.end_date, '2015-12-09'), GREATEST(ct1.start_date, '2015-12-01')) + 1, 0) as blocked_days, 
ct1.property_id as property_id 
FROM ({blocked dates}) as ct1 
LEFT JOIN ({blocked dates}) as ct2 ON ct2.property_id = ct1.property_id AND ct2.start_date > ct1.end_date 
GROUP BY ct1.property_id,ct1.start_date 

這需要在第1部分表,並將其加入到自己讓我們來比較先前阻斷日期下。 open_days是每個阻止日期之間的負面空間。 只是ct1被封鎖了多少天。造成問題的部分是first_open

此查詢有效,除非第一個阻止日期發生在用戶開始日期之後。在那種情況下,我們錯過了計算那些開放的前幾天的情況。所以,我的解決方案的一部分是添加first_open,它只是簡單地計算DATEDIFF(ct1.start_date, {the given start date})

最後一筆

SELECT cj.property_id, 
IFNULL(SUM(cj.blocked_days), 0) as total_blocked, 
IFNULL(GREATEST(MAX(cj.open_days), MAX(cj.first_open)), 0) as consec_days_avail 
FROM {the calculator} as cj 

正如我所說的,這裏是我的問題。選擇MAX(cj.first_open)顯然不適合我。沒有唯一的ID可以通過,因爲可用性是ID可能發生碰撞的兩個表的組合。而且MySQL沒有使用FIRST()函數。但基本上我只關心最大的可用連續日期,因爲我們不關心連續幾天發生的情況,只是它們發生在用戶的開始日期和結束日期之間。

那麼有沒有更好的方法來構造這個查詢?我試圖探索方法來獲得計算器中的第一行實際上DATEDIFF()和其他所有的都是0,但我使用IF(ct1.start_date = MIN(ct1.start_date), DATEDIFF(...), 0)的問題是,前兩行將有一個非0值,我只想第一個。我認爲這與我如何加入表格本身有關。

任何幫助表示讚賞。謝謝。

編輯

對於好奇各方這裏的查詢都在一塊。這正在按照預期工作(據我所知)。現在我只是想知道是否有更好的方法或者是否有任何提示。

SELECT p.* as id, IFNULL(cd.total_blocked, 0) as total_blocked, IFNULL(cd.consec_days_avail, 0) as consec_days_avail 
FROM properties AS p 
LEFT JOIN (
SELECT cj.property_id, IFNULL(SUM(cj.blocked_days), 0) as total_blocked, IFNULL(GREATEST(MAX(cj.open_days), MAX(cj.first_open)), 0) as consec_days_avail 
FROM (
SELECT IFNULL(DATEDIFF(IFNULL(ct2.start_date2, {user_end_date}), ct1.end_date) - 1, 0) as open_days,IF(MIN(ct1.start_date) = ct1.start_date, DATEDIFF(ct1.start_date, {user_start_date}), 0) as first_open,IFNULL(DATEDIFF(LEAST(ct1.end_date, {user_end_date}), GREATEST(ct1.start_date, {user_start_date})) + 1, 0) as blocked_days,ct1.property_id as property_id 
FROM ((SELECT c.id,c.property_id,c.start_date,c.end_date FROM property_calendar as c WHERE c.start_date <= {user_end_date} AND c.end_date >= {user_start_date}) UNION (SELECT l.id,l.property_id,l.start_date,l.end_date FROM lease as l WHERE l.start_date <= {user_end_date} AND l.end_date >= {user_start_date} AND l.status < 6) ORDER BY start_date ASC) as ct1 
LEFT JOIN ((SELECT c.id as id2,c.property_id as property_id2,c.start_date as start_date2,c.end_date as end_date2 FROM property_calendar as c WHERE c.start_date <= {user_end_date} AND c.end_date >= {user_start_date}) UNION (SELECT l.id,l.property_id,l.start_date,l.end_date FROM lease as l WHERE l.start_date <= {user_end_date} AND l.end_date >= {user_start_date} AND l.status < 6) ORDER BY start_date2 ASC) as ct2 ON ct2.property_id2 = ct1.property_id AND ct2.start_date2 > ct1.end_date 
GROUP BY ct1.property_id,ct1.start_date) as cj 
GROUP BY cj.property_id) as cd on cd.property_id = p.id 
WHERE p.state = 1 
GROUP BY p.id 
HAVING total_blocked < DATEDIFF({user_end_date},{user_start_date}) + 1 AND (consec_days_avail >= {user_days_avail} OR total_blocked = 0) 
ORDER BY p.id asc 
+0

我寧願只是一些數據和期望的結果 - 至少這表明你正在嘗試 – Strawberry

+0

@Strawberry我得到你。對不起,我已經花了好幾天的時間研究這個問題,並且我認爲這將是一個更簡單的解讀。我會把小提琴放在一起並更新。 – Squeegy

+0

只是一個珍聞。 'MIN(datestamp)'和'MAX(datestamp)'作爲聚合函數正常工作,返回第一個和最後一個日期戳記。另外,你可能會濫用令人討厭的非標準MySQL擴展到'GROUP BY',這可能會讓你瘋狂。 https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html –

回答

0

您好!
該問題的解決方案是一個名爲MIN一個SQL函數和它的工作原理是這樣的:

SELECT MIN(primary_key_column),the_other_columns FROM table_name; 

正如你所看到的,在查詢的開始(字選擇後)你剛纔調用函數MIN並給出也是表的主鍵的列。
因爲這個函數找到表格的最小寄存器。我的意思是如果選擇的列是INTEGER,它將會找到該列中最小數字的行

如果您也使用PHP還有就是讓那個叫mysql_fetch_array,對於這個功能,你必須首先做一個歸仁一個名爲的mysql_query另一PHP功能和使用它像這樣

$myQuery = mysql_query("SELECT * FROM tablename",$conectionVariable)or die(mysql_error); 

然後我們調用函數mysql_fetch_功能陣列並將其存儲在一個變量是這樣的:

$myQueryArray = mysql_getch_array($myQuery)or die(mysql_error()); 

現在使用它,你必須把它像一個正常的數組:

$myQueryArray['COLUMN_NAME'] 並返回你列的值是第一行

那麼,這一切。

謝謝!