查找同一表中特定用户MySQL的日期范围重叠
我绝对不是MySQL专家,所以我正在寻找任何关于这件事的帮助 我需要执行一个简单的测试(原则上),我有这个(简化的)表: 我需要在这里找到两件事:查找同一表中特定用户MySQL的日期范围重叠,mysql,database,alias,intervals,Mysql,Database,Alias,Intervals,我绝对不是MySQL专家,所以我正在寻找任何关于这件事的帮助 我需要执行一个简单的测试(原则上),我有这个(简化的)表: 我需要在这里找到两件事: 如果任何用户的车辆分配中存在超过一天的日期重叠(分配的结束日期可以与新分配的开始日期相同) 是否有任何两个用户试图在同一日期获得同一辆车的分配,或者他们在同一辆车上的日期范围重叠 因此,我要查找的查询应返回以下行: tableid | userid | car | From | To --------------------
tableid | userid | car | From | To
--------------------------------------------------------
3 | 1 | Navara | 2015-03-01 | 2015-03-31
4 | 1 | GTR | 2015-03-28 | 2015-04-30
7 | 2 | Aygo | 2015-03-01 | 2015-03-31
8 | 2 | 206 | 2015-03-29 | 2015-04-30
9 | 1 | Skyline | 2015-04-29 | 2015-05-31
10 | 2 | Skyline | 2015-04-29 | 2015-05-31
我觉得我的头撞到了墙上,我很高兴能够在单独的查询中进行这些比较。我需要将它们显示在一个表中,但我始终可以加入结果
我已经做了研究和几个小时的测试,但我无法得到任何接近我想要的结果
顺便说一句,我试过这些帖子(它们不完全是我需要的,但已经足够近了,或者我是这么想的):
这是我能找到的最接近的解决方案,但当我在单个表上尝试(将表连接到自身)时,我得到了疯狂的结果:
编辑
作为一个临时解决方案,我采用了不同的方法,类似于我在研究期间发现的帖子(如上)。我现在将检查新车租赁/分配日期是否与表中的任何日期范围重叠。如果是这样,我将保存与日期重叠的行的id。通过这种方式,我至少能够标记重叠,并允许用户查看标记的行并手动解决任何重叠
感谢所有在这方面提供帮助的人,除非有人有更好的方法来实现这一点,否则我会将philipxy answer标记为选中的答案(在接下来的24小时内)。我毫不怀疑,按照他的回答,我最终将能够达到我所需要的结果。目前,虽然我需要采取任何可行的解决方案,因为我需要在未来几天内完成我的项目,因此改变了方法
编辑#2
这两个答案都很精彩,如果有人发现这篇文章与我的问题相同,请阅读这两个答案,然后看看小提琴!:)他们做了很多惊人的脑力劳动!暂时我不得不使用我在#1编辑中提到的解决方案,但我将调整我的查询,以使用@Ryan Vincent approach+@philipxy编辑/注释,忽略最初的一天重叠。对于每个输入和输出表,找到其意义。即一个由列名参数化的语句模板,也称为谓词,行将其转换为真或假语句,也称为命题。表包含使其谓词成为真命题的行。也就是说,做出正确命题的行放在表中,而做出错误命题的行不在表中。例如,对于您的输入表:
rental [tableid] was user [userid] renting car [car] from [from] to [to]
然后根据输入表谓词对输出表谓词进行短语化。不要使用类似于1和2的描述:
rental [tableid] was user [user] renting car [car] from [from] to [to]
in self-conflict with some other rental
rental [tableid] was user [user] renting car [car] from [from] to [to]
in conflict with some other user's rental
为了让DBMS计算实现这一点的行,我们必须用给定的谓词加上文本和条件来表示:
-- query result holds the rows where
FOR SOME t2.tableid, t2.userid, ...:
rental [t1.tableid] was user [t1.userid] renting car [t1.car] from [t1.from] to [t1.to]
AND rental [t2.tableid] was user [t2.userid] renting car [t2.car] from [t2.from] to [t2.to]
AND [t1.userid] = [t2.userid] -- userids id the same users
AND [t1.to] > [t2.from] AND ... -- tos/froms id intervals with overlap more than one day
...
-- query result holds the rows where
FOR SOME t2.*
rental [t1.tableid] was user [t1.userid] renting car [t1.car] from [t1.from] to [t1.to]
AND rental [t2.tableid] was user [t2.userid] renting car [t2.car] from [t2.from] to [t2.to]
AND [t1.userid] <> [t2.userid] -- userids id different users
AND [t1.car] = [t2.car] -- .cars id the same car
AND [t1.to] >= [t2.from] AND [t2.to] >= [t1.from] -- tos/froms id intervals with any overlap
AND [t1.tableid] <> [t2.tableid] -- tableids id different rentals
(在SQLSELECT
语句中,JOIN
ed表的叉积具有alias
列
形式的列名。将
视为列名中允许的另一个字符。最后,SELECT
子句删除别名
我们将查询谓词转换为SQL查询,该查询计算使其成为真的行:
- 表的谓词将替换为表别名
- 要多次使用同一谓词/表,请生成别名
- 将谓词中的列
old
更改为new
将添加和old
=
- 谓词的
和被JOIN
替换
- 谓词的
或
被联合
替换
- 谓词的
和
被替换为,减
或适当的左连接
和
条件
被
替换,其中
或
上的
条件
列的谓词true,或者当存在要删除的
列时,选择要保留的不同的
列
-- query result holds the rows where
FOR SOME t2.tableid, t2.userid, ...:
rental [t1.tableid] was user [t1.userid] renting car [t1.car] from [t1.from] to [t1.to]
AND rental [t2.tableid] was user [t2.userid] renting car [t2.car] from [t2.from] to [t2.to]
AND [t1.userid] = [t2.userid] -- userids id the same users
AND [t1.to] > [t2.from] AND ... -- tos/froms id intervals with overlap more than one day
...
-- query result holds the rows where
FOR SOME t2.*
rental [t1.tableid] was user [t1.userid] renting car [t1.car] from [t1.from] to [t1.to]
AND rental [t2.tableid] was user [t2.userid] renting car [t2.car] from [t2.from] to [t2.to]
AND [t1.userid] <> [t2.userid] -- userids id different users
AND [t1.car] = [t2.car] -- .cars id the same car
AND [t1.to] >= [t2.from] AND [t2.to] >= [t1.from] -- tos/froms id intervals with any overlap
AND [t1.tableid] <> [t2.tableid] -- tableids id different rentals
--查询结果保存以下行:
对一些人来说*
rental[t1.tableid]是用户[t1.userid]将汽车[t1.car]从[t1.from]租到[t1.to]
出租[t2.tableid]是用户[t2.userid]从[t2.from]到[t2.to]出租汽车[t2.car]
和[t1.userid][t2.userid]——不同用户的userid
和[t1.car]=[t2.car]-.cars标识同一辆车
和[t1.to]>=[t2.from]和[t2.to]>=[t1.from]--tos/froms id间隔有任何重叠
和[t1.tableid][t2.tableid]——tableid不同的租金
谓词1和谓词2的查询的联合
返回谓词1
或谓词2
所对应的行
试着学习如何表达谓词——表中的行状态——如果只是作为直观(子)查询的目标
PS最好始终让数据检查边缘和非边缘情况,以确定条件是否为真。例如,尝试查询1,全球技术法规从31日开始,仅重叠一天,这不应该是自我冲突
PPS查询发票
SELECT `allCars`.`userid` AS `allCars_userid`,
`allCars`.`car` AS `allCars_car`,
`allCars`.`From` AS `allCars_From`,
`allCars`.`To` AS `allCars_To`,
`allCars`.`tableid` AS `allCars_id`
FROM
`cars` AS `allCars`
WHERE
EXISTS
(SELECT 1
FROM `cars` AS `overlapCar`
WHERE
`allCars`.`userid` = `overlapCar`.`userid`
AND `allCars`.`tableid` <> `overlapCar`.`tableid`
AND NOT ( `allCars`.`From` >= `overlapCar`.`To` /* starts after outer ends */
OR `allCars`.`To` <= `overlapCar`.`From`)) /* ends before outer starts */
ORDER BY
`allCars`.`userid`,
`allCars`.`From`,
`allCars`.`car`;
allCars_userid allCars_car allCars_From allCars_To allCars_id
-------------- ----------- ------------ ---------- ------------
1 Navara 2015-03-01 2015-03-31 3
1 GTR 2015-03-28 2015-04-30 4
1 Skyline 2015-04-29 2015-05-31 9
2 Aygo 2015-03-01 2015-03-31 7
2 206 2015-03-29 2015-04-30 8
2 Skyline 2015-04-29 2015-05-31 10
SELECT `allCars`.`car` AS `allCars_car`,
`allCars`.`userid` AS `allCars_userid`,
`allCars`.`From` AS `allCars_From`,
`allCars`.`To` AS `allCars_To`,
`allCars`.`tableid` AS `allCars_id`
FROM
`cars` AS `allCars`
WHERE
EXISTS
(SELECT 1
FROM `cars` AS `overlapUser`
WHERE
`allCars`.`car` = `overlapUser`.`car`
AND `allCars`.`tableid` <> `overlapUser`.`tableid`
AND NOT ( `allCars`.`From` >= `overlapUser`.`To` /* starts after outer ends */
OR `allCars`.`To` <= `overlapUser`.`From`)) /* ends before outer starts */
ORDER BY
`allCars`.`car`,
`allCars`.`userid`,
`allCars`.`From`;
allCars_car allCars_userid allCars_From allCars_To allCars_id
----------- -------------- ------------ ---------- ------------
Skyline 1 2015-04-29 2015-05-31 9
Skyline 2 2015-04-29 2015-05-31 10