[英]Filtering down specific criteria for all rows and return only one row for each column with the same value
I have house_leases and house_lease_terms (see table schemas below).我有house_leases和house_lease_terms (参见下面的表格模式)。 A house_lease can have multiple house_lease_terms however there can only be one "active" term at a time.一个house_lease可以有多个house_lease_term,但一次只能有一个“活动”期限。
Table Definitions:表定义:
CREATE TABLE `house_leases` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`house_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `house_lease_terms` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`house_lease_id` int(10) unsigned NOT NULL,
`date_start` datetime NOT NULL,
`date_end` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `house_lease_terms_house_lease_id_foreign` (`house_lease_id`),
CONSTRAINT `house_lease_terms_house_lease_id_foreign` FOREIGN KEY (`house_lease_id`) REFERENCES `house_leases` (`id`) ON DELETE CASCADE
);
As you can see the house_lease_terms.house_lease_id corresponds to a specific house_lease , however there can be multiple rows with the same house_lease_id .如您所见, house_lease_terms.house_lease_id对应于特定的house_lease ,但是可以有多个具有相同house_lease_id 的行。
The rules for determining the "active" terms are:确定“活动”术语的规则是:
date_start <= NOW() AND date_end > NOW() OR date_end IS NULL date_start <= NOW() AND date_end > NOW() OR date_end IS NULL
If no rows are returned then the "active" terms must be in the future, so then the rules change to be:如果没有返回行,那么“活动”条款必须在未来,因此规则更改为:
date_start > NOW() date_start > 现在()
We order by date_start DESC if the terms are not in the future since multiple rows could be returned we want the latest date_start at the top of the results.如果条款不在未来,我们按date_start DESC排序,因为可能返回多行,我们希望最新的date_start位于结果的顶部。 Otherwise we sort by date_start ASC because we want the closest date_start to now to be at the top.否则,我们按date_start ASC排序,因为我们希望现在最接近的date_start位于顶部。
I then limit by 1 to get only one result and that row is considered the "active" terms.然后我将其限制为 1 以仅获得一个结果,并且该行被视为“活动”术语。 If no results come back, then there are no "active" terms.如果没有返回结果,则没有“活动”术语。
I have a SQL statement that has this logic for getting a specific house_lease_id .我有一个 SQL 语句,它具有获取特定house_lease_id 的逻辑。 That looks like this:看起来像这样:
SELECT * FROM house_lease_terms
WHERE
CASE
WHEN
(SELECT COUNT(*) FROM house_lease_terms WHERE date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL) AND house_lease_id = 1)
THEN
date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL)
ELSE
date_start > NOW()
END
AND house_lease_id = 1
ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms WHERE date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL) AND house_lease_id = 1),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC
LIMIT 1;
This statement works, but I wish there was a better way (more efficient) of fetching the "active" terms for a specific house_lease_id (If you know a better solution please share).此语句有效,但我希望有一种更好的方法(更有效)来获取特定house_lease_id的“活动”条款(如果您知道更好的解决方案,请分享)。
Now I need to have a query that will fetch the "active" terms for all the different house_lease_id 's.现在我需要一个查询来获取所有不同house_lease_id的“活动”术语。
I don't want any type of custom MySQL function or stored procedure to do this.我不希望任何类型的自定义 MySQL 函数或存储过程来执行此操作。 I don't know where to start to create this query.我不知道从哪里开始创建这个查询。 I figure I can use the query from above in some sub select or join, but am not sure how I would do so.我想我可以在某些子选择或连接中使用上面的查询,但我不确定我将如何这样做。
Any help will be appreciated!任何帮助将不胜感激!
SQLFiddle with data: http://sqlfiddle.com/#!9/cab159/2/0带有数据的 SQLFiddle: http ://sqlfiddle.com/#!9/cab159/2/0
Look for:寻找:
SELECT *
FROM house_lease_terms
WHERE house_lease_id = 1
AND ( ( ( date_start <= NOW()
AND date_end > NOW()
)
OR date_end IS NULL
)
OR (date_start > NOW()
)
)
ORDER BY CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
THEN DATEDIFF(NOW(), date_start)
ELSE DATEDIFF(date_start, NOW()) + 1000000
END
SELECT id,
CASE WHEN @var2=house_lease_id
THEN @var1:=house_lease_id
ELSE 1
END row_number_in_house_lease_id,
@var2:=house_lease_id house_lease_id,
date_start,
date_end,
created_at,
updated_at,
deleted_at
FROM house_lease_terms, (SELECT @var1:=0, @var2:=0) variables
WHERE house_lease_id = 1
AND ( ( ( date_start <= NOW()
AND date_end > NOW()
)
OR date_end IS NULL
)
OR (date_start > NOW()
)
)
ORDER BY house_lease_id,
CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
THEN DATEDIFF(NOW(), date_start)
ELSE DATEDIFF(date_start, NOW()) + 1000000
END
Next generation.下一代。
SELECT id, house_lease_id, date_start, date_end
FROM (
SELECT id,
CASE WHEN @var2=house_lease_id
THEN @var1:=@var1+1
ELSE @var1:=1
END row_number_in_house_lease_id,
@var2:=house_lease_id house_lease_id,
date_start,
date_end
FROM house_lease_terms, (SELECT @var1:=0, @var2:=0) variables
WHERE ( ( ( date_start <= NOW()
AND date_end > NOW()
)
OR date_end IS NULL
)
OR (date_start > NOW()
)
)
ORDER BY house_lease_id,
CASE WHEN ((date_start <= NOW() AND date_end > NOW()) OR date_end IS NULL)
THEN DATEDIFF(NOW(), date_start)
ELSE DATEDIFF(date_start, NOW()) + 1000000
END
) AS cte
WHERE row_number_in_house_lease_id = 1;
I'm not sure this is what you would consider clean, but it seems like any approach to this is going to result in a fairly complex and messy query.我不确定这是你认为干净的,但似乎任何方法都会导致相当复杂和混乱的查询。
Based on your original query:根据您的原始查询:
SELECT house_lease_id,
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms AS hlt2
WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt2.house_lease_id = hlt.house_lease_id),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC),',',1) AS id,
SUBSTRING_INDEX(GROUP_CONCAT(date_start ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms AS hlt3
WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt3.house_lease_id = hlt.house_lease_id),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC),',',1) AS date_start,
SUBSTRING_INDEX(GROUP_CONCAT(date_end ORDER BY
IF(
(SELECT COUNT(*) FROM house_lease_terms AS hlt4
WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt4.house_lease_id = hlt.house_lease_id),
unix_timestamp(date_start),
-unix_timestamp(date_start)
) DESC),',',1) AS date_end
FROM house_lease_terms AS hlt
WHERE
CASE
WHEN
(SELECT COUNT(*) FROM house_lease_terms AS hlt5 WHERE date_start <= NOW()
AND (date_end > NOW() OR date_end IS NULL)
AND hlt5.house_lease_id = hlt.house_lease_id)
THEN
date_start <= NOW() AND (date_end > NOW() OR date_end IS NULL)
ELSE
date_start > NOW()
END
GROUP BY hlt.house_lease_id;
That should work.那应该工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.