简体   繁体   English

MySQL选择表的第一行

[英]MySQL select the first row of a table

I know there are dozens of "select the first row" questions, but I have an interesting situation that I don't think I can fix with a LIMIT. 我知道有许多“选择第一行”问题,但是我有一个有趣的情况,我认为我无法解决LIMIT问题。

I'm trying to show properties that are available between a start and end date, with N days consecutively available. 我试图显示在开始日期和结束日期之间可用的属性,并连续N天可用。 I'm so close. 我好亲近

I'm going to break this query apart into bits because it's a big one. 我将把这个查询分成几部分,因为它是一个很大的查询。

Blocked Dates (part 1) 封锁日期(第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

This union smashes our two calendars together for easy comparison. 此联合将我们的两个日历粉碎在一起以便于比较。 Each entry has a start_date and end_date. 每个条目都有一个开始日期和结束日期。 Dates that fall between (including the start and end) are considered to be unavailable. 介于之间的日期(包括开始和结束)被认为不可用。

The Calculator (part 2) 计算器(第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

This takes the table in part 1, and joins it to itself allowing us to compare the previous blocked date with the next. 这是第1部分中的表格,并将其与自身连接起来,使我们可以将上一个阻止日期与下一个阻止日期进行比较。 open_days is the negative space between each blocked date. open_days是每个阻止日期之间的负空格。 blocked_days is just how many days are blocked in ct1 . blocked_days就是ct1被阻止的天数。 The part that's causing trouble is first_open . 引起麻烦的部分是first_open

This query works, unless the first blocked date occurs after the start date the user gave. 该查询有效,除非第一个阻止日期发生在用户指定的开始日期之后。 In that case, we miss out on counting those first few days that are open. 在这种情况下,我们会错过对开放的前几天进行计数的机会。 So, part of my solution was to add the first_open which just simply calculates DATEDIFF( ct1.start_date, {the given start date}) . 因此,我的解决方案的一部分是添加first_open ,它只需简单地计算DATEDIFF( ct1.start_date, {the given start date})

The Final Sum 最终总和

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

As I said, here is where I have the problem. 正如我所说,这是我遇到的问题。 Selecting MAX(cj.first_open) obviously won't work for me. 选择MAX(cj.first_open)显然对我不起作用。 There's no unique ID either I can go by because the availability is the combination of two tables where the IDs can possibly collide. 我也没有唯一的ID,因为可用性是ID可能冲突的两个表的组合。 And MySQL doesn't have a FIRST() function to use. 而且MySQL没有要使用的FIRST()函数。 But basically I only care about the greatest available consecutive days because we just don't care where the consecutive days occur, just that they happen between the user's start and end dates. 但是基本上,我只关心最大的连续天数,因为我们不关心连续天数在哪里发生,而只是在用户的开始日期和结束日期之间发生。

So is there a better way to structure this query? 因此,有没有更好的方法来构造此查询? I've tried exploring methods to get only the first row in The Calculator to actually DATEDIFF() and all others are 0, but the problem I had using IF(ct1.start_date = MIN(ct1.start_date), DATEDIFF(...), 0) was that the first two rows would have a non 0 value and I only want just the first. 我尝试探索一些方法,仅将IF(ct1.start_date = MIN(ct1.start_date), DATEDIFF(...), 0)计算器DATEDIFF()的第一行实际设置为DATEDIFF() ,其他所有均为0,但是我使用IF(ct1.start_date = MIN(ct1.start_date), DATEDIFF(...), 0)是前两行将具有非0值,而我只想要第一行。 And I think that has something to do with how I'm joining a table on itself. 我认为这与我如何在其自身上连接表有关。

Any help is appreciated. 任何帮助表示赞赏。 Thanks. 谢谢。

Edit 编辑

For the curious parties here's the query all in one piece. 对于好奇的各方,这里的查询全部都是一件。 This is now working (as far as I can tell) as intended. 现在(按我所知)正在按预期工作。 Now I'm just wondering if there's a better way or if there's any tips. 现在我只是想知道是否有更好的方法或是否有任何提示。

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

Hello! 你好!
The solution for that problem is a SQL Function called MIN and it works like this: 该问题的解决方案是一个名为MINSQL函数 ,它的工作方式如下:

SELECT MIN(primary_key_column),the_other_columns FROM table_name;

As you can see , at the start of the Query (After the word SELECT) you just Call the function MIN and give the column that also is the Primary Key of the table. 如您所见,在查询开始时(在SELECT单词之后),您只需调用函数MIN,然后为该列提供表的主键。
Because this function find the minimum of the registers of the table.I mean that if the selected column is an INTEGER it will be going to find the row with the Smallest Number in that column 因为此函数查找表中的寄存器的最小值。我的意思是,如果所选列是INTEGER,它将在该列中查找具有最小编号的行

If you are using PHP too there is a function to make that called mysql_fetch_array ,for this function you have to make first a quy with another PHP function called mysql_query and use it like this 如果您也使用PHP ,则有一个函数可以使该函数名为mysql_fetch_array ,对于该函数,您首先必须与另一个名为mysql_query的 PHP函数进行查询,然后像这样使用它

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

Then we call the function mysql_fetch_array and store it in a variable like this: 然后我们调用函数mysql_fetch_array并将其存储在这样的变量中:

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

Now for use it you have to call it like a normal Array: 现在要使用它,您必须像普通数组一样调用它:

$myQueryArray['COLUMN_NAME'] And it return you the value of that column is the first Row $myQueryArray['COLUMN_NAME']并返回该列的值是第一行

Well,that all. 好吧,这一切。

Thanks! 谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM