Mysql Select Query 以查找在两个给定日期之间也部分空闲的项目
Posted
技术标签:
【中文标题】Mysql Select Query 以查找在两个给定日期之间也部分空闲的项目【英文标题】:Mysql Select Query to find items also partially free between two given dates 【发布时间】:2021-09-30 12:17:29 【问题描述】:我需要列出两个给定日期之间的免费物品。 我在 A 表中有物品,在 B 表中有它们的入住情况。 当我搜索两个日期之间的免费项目时,我还需要列出部分免费的项目。
Tabel A:
| ID | ITEM_NAME |
| -------- | -------------- |
| 1 | Item1 |
| 2 | Item2 |
| 3 | Item3 |
Table B:
|id_item |occupancy_start_date |occupancy_end_date|
|---------------------------------------------------------|
|1 |2021-07-24 |2021-08-06 |
|2 |2021-07-24 |2021-07-31 |
|3 |2021-07-29 |2021-08-03 |
当我在 2021-07-24 和 2021-08-06 之间搜索免费物品时,我必须得到 Item2 和 Item3。
Item2 is free from 2021-08-01 till 2021-08-06
Item3 is free from 2021-07-24 till 2021-07-29
Item3 is free from 2021-08-04 till 2021-08-06
(实际上我必须在用户给定的两个给定日期之间找到空闲的日期时段)
你们能帮帮我吗?谢谢。
【问题讨论】:
请向我们展示您的尝试。看看***.com/help/minimal-reproducible-example。此外,我们需要知道您是如何定义范围开始和结束的。 两个日期之间的范围。 【参考方案1】:无窗口功能:
有一种方法是把提取分成三部分:“From start date”、“Till end date”和“Others”,并按每个查询过滤行,如下所示:
SET @sdate = DATE'2021-07-24';
SET @edate = DATE'2021-08-06';
-- From start date
SELECT
b.id_item id_item,
@sdate from_date,
DATE_ADD(MIN(b.occupancy_start_date), INTERVAL -1 DAY) to_date
FROM TableB b
GROUP BY b.id_item
HAVING from_date <= to_date
-- Till end date
UNION ALL
SELECT
b.id_item id_item,
DATE_ADD(MAX(b.occupancy_end_date), INTERVAL 1 DAY) from_date,
@edate to_date
FROM TableB b
GROUP BY b.id_item
HAVING from_date <= to_date
-- Others
UNION ALL
SELECT
b1.id_item,
DATE_ADD(b1.occupancy_end_date, INTERVAL 1 DAY),
DATE_ADD(b2.occupancy_start_date, INTERVAL -1 DAY)
FROM TableB b1 INNER JOIN TableB b2
ON b1.id_item=b2.id_item AND
b1.occupancy_end_date < b2.occupancy_start_date AND
-- Exclude inappropriate rows
NOT EXISTS (SELECT 1 FROM TableB b WHERE
b1.id_item = b.id_item AND (
( b1.occupancy_end_date < b.occupancy_start_date AND
b.occupancy_start_date < b2.occupancy_start_date) OR
( b1.occupancy_end_date < b.occupancy_end_date AND
b.occupancy_end_date < b2.occupancy_start_date) ) )
ORDER BY 1,2
;
DB Fiddle
带窗口功能:
如果是 mysql8,可以使用 LAG(或 LEAD)函数,像这样:
SET @sdate = DATE'2021-07-24';
SET @edate = DATE'2021-08-06';
SELECT
a.ITEM_NAME,
w.id_item,
w.from_date,
w.to_date
FROM (
-- Non-free period(s) exist
SELECT * FROM (
SELECT
id_item,
DATE_ADD(LAG(occupancy_end_date, 1)
OVER (PARTITION BY id_item ORDER BY occupancy_end_date),
INTERVAL 1 DAY) from_date,
DATE_ADD(occupancy_start_date, INTERVAL -1 DAY) to_date
FROM TableB
WHERE @sdate < occupancy_end_date AND occupancy_start_date < @edate
) t
WHERE from_date <= to_date
-- From start date
UNION ALL
SELECT
id_item,
@sdate from_date,
DATE_ADD(MIN(occupancy_start_date), INTERVAL -1 DAY) to_date
FROM TableB
GROUP BY id_item
HAVING from_date <= to_date
-- Till end date
UNION ALL
SELECT
id_item,
DATE_ADD(MAX(occupancy_end_date), INTERVAL 1 DAY) from_date,
@edate to_date
FROM TableB
GROUP BY id_item
HAVING from_date <= to_date
-- No occupancy
UNION ALL
SELECT
ID,
@sdate from_date,
@edate to_date
FROM TableA a
WHERE NOT EXISTS (SELECT 1 FROM TableB b WHERE a.ID=b.id_item)
) w
INNER JOIN TableA a ON w.id_item=a.ID
ORDER BY
w.id_item,
w.from_date
;
DB Fiddle
【讨论】:
谢谢。这似乎是一个很好的操作,但是对于很多行,这变得非常非常慢! 我改为过滤每个查询。我认为这将比以前的查询提高性能。我添加了带有窗口功能的案例。 您好 Etsuhisa,我已将 Mysql 升级到 Versione del 服务器:10.4.20-MariaDB。现在您的功能运行良好。我需要这个查询的另外两个细节:1)tableA 中的项目名称(那么,如何在这个查询中加入两个表)2)在给定时间跨度内完全免费的项目。非常感谢您的专业回答。 我重写了“带窗口函数”的查询。 1)“tableA”中的项目名称可以通过使用INNER JOIN进行查询。 2) 将“包括免费”、“从开始”和“直到结束”分开,并在查询中添加“无占用”。 我在回答中更新了“带窗口功能”的查询。并查看 DB Fiddle "db-fiddle.com/f/bj8hYcSwFmUyZS82bYyTB6/3" 的链接。【参考方案2】:这是另一个起点(使用其他人慷慨提供的小提琴 - 推送到更新的版本)......如果没有人击败我,我将在下周发布更完整的答案......
WITH RECURSIVE cte AS (
SELECT '2021-07-24' dt
UNION ALL
SELECT dt + INTERVAL 1 DAY
FROM cte
WHERE dt < '2021-08-06')
SELECT x.dt
, a.*
FROM cte x
JOIN TableA a
LEFT
JOIN TableB b
ON b.id_item = a.id
AND x.dt BETWEEN b.occupancy_start_date AND b.occupancy_end_date
WHERE b.id_item IS NULL
【讨论】:
这很简短,似乎很好。我无法验证它,因为 phpmyadmin 产生错误“Sono stati trovati 1 errori durante l'analisi。Tipo statement non riconosciuto. (near "WITH" at position 0)"。错误号 #1064。 +-------------------------+--------------- ------------------+ |变量名 |价值 | +-------------------------+------------------------ ----------+ | innodb_version | 5.6.41-84.1 | |协议版本 | 10 | |版本 | 10.1.37-MariaDB | +-------------------------+------------------------ ----------+ Etsuhisa 抛出以下错误:#1064 - Errore di sintassi nella query SQL vicino a 'OVER ( PARTITION BY id_item ORDER BY ' linea 9 我会努力更新的!并让你知道。谢谢。 升级后就可以了。但问题并没有解决!这很好。 db-fiddle.com/f/bj8hYcSwFmUyZS82bYyTB6/0 但我需要在给定日期范围内完全免费的项目。以上是关于Mysql Select Query 以查找在两个给定日期之间也部分空闲的项目的主要内容,如果未能解决你的问题,请参考以下文章
SET 和 Select Query 结合 Run in a Single MySql Query 将结果传递到 pentaho