MySQL 选择表的第一行

标签 mysql date

我知道有几十个“选择第一行”问题,但我有一个有趣的情况,我认为我无法用 LIMIT 来解决。

我正在尝试显示在开始日期和结束日期之间可用的属性,其中连续 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

这个联合将我们的两个日历放在一起以便于比较。每个条目都有一个开始日期和结束日期。介于两者之间的日期(包括开始和结束)被视为不可用。

计算器(第 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 是每个阻止日期之间的负空格。 blocked_days 就是 ct1 中被阻止的天数。造成问题的部分是 first_open

除非第一个阻止日期发生在用户指定的开始日期之后,否则此查询有效。在这种情况下,我们就错过了计算最初开放的几天。因此,我的解决方案的一部分是添加 first_open ,它只是简单地计算 DATEDIFF( ct1.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

最佳答案

您好!
该问题的解决方案是一个名为 MINSQL 函数,它的工作原理如下:

SELECT MIN(primary_key_column),the_other_columns FROM table_name;

如您所见,在查询开始时(在 SELECT 一词之后),您只需调用函数 MIN 并给出也是表主键的列。
因为此函数找到最小值表的寄存器。我的意思是,如果所选列是整数,它将找到该列中数字最小的行

如果您也使用PHP,则有一个名为mysql_fetch_array的函数,对于此函数,您必须首先使用另一个PHP创建一个quy名为 mysql_query 的函数并像这样使用它

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

然后我们调用函数 mysql_fetch_array 并将其存储在如下变量中:

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

现在要使用它,您必须像普通数组一样调用它:

$myQueryArray['COLUMN_NAME'] 它返回您该列的值是第一行

好了,就这些了。<​​/p>

谢谢!

关于MySQL 选择表的第一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34184475/

相关文章:

bash - 以秒为单位获取 UTC 时间

javascript - 操作日期时出现日期问题

bash/sed/awk 从文本文件中删除或 gsub 时间戳模式

mysql - 为每行选择范围内不同的日期

mysql - 是否可以将 varchar 限制为 MySQL 中的特定字符集?

MySql查询: ordering by two fields in two tables

php - 建立多重 Eloquent 关系并且有一个Where子句

MySQL 全文搜索仅在选定的行中

mysql - 对 MySQL DATE 或 TIME 列的整数查询速度慢吗?

php - 为什么 PHP 日期的迭代数周会出错?