简体   繁体   English

Mysql左连接Group By和Between

[英]Mysql Left Join with Group By and Between

I am having trouble to create a select query that will retrieve all users id that isn't in the games and availability between dates. 我无法创建一个选择查询,该查询将检索游戏中不存在的所有用户ID以及日期之间的可用性。

Example: Retrieve all users that are not between dates 2017-08-10 and 2017-08-12 . 示例:检索不在2017-08-102017-08-12之间的所有用户。

Get [3 , 4, 5] 获得[3 , 4, 5]

Users 用户

| Id | Name     |
| 1  | Jonh     |
| 2  | Mark     |
| 3  | Caroline |
| 4  | David    |
| 5  | George   |

Games 游戏

| Id | User_Id  | Start_Date | End_Date   |
| 1  | 1        | 2017-06-01 | 2017-06-01 |
| 2  | 1        | 2017-08-12 | 2017-08-13 |
| 3  | 4        | 2017-08-13 | 2017-08-14 |

Availability 可用性

| Id | User_Id | Start_Date | End_Date   |
| 1  | 1       | 2017-05-01 | 2017-05-25 |
| 1  | 2       | 2017-08-10 | 2017-08-17 |
| 1  | 3       | 2017-06-20 | 2017-07-10 |

I am using Laravel 5.4 but I'll glad if the answer is on Raw or Eloquent. 我正在使用Laravel 5.4,但如果答案是Raw或Eloquent,我会很高兴的。

In SQL, you can use NOT EXISTS : 在SQL中,您可以使用NOT EXISTS

select *
from users u
where not exists (
        select 1
        from games g
        where u.id = g.user_id
            and (
                g.start_date between '2017-08-10' and '2017-08-12'
                or g.end_date between '2017-08-10' and '2017-08-12'
                )
        )
    and not exists (
        select 1
        from Availability a
        where u.id = a.user_id
            and (
                a.start_date between '2017-08-10' and '2017-08-12'
                or a.end_date between '2017-08-10' and '2017-08-12'
                )
        );

Demo 演示

Another way using LEFT JOIN would be: 使用LEFT JOIN另一种方法是:

select distinct u.*
from t_users u
left join games g on u.id = g.user_id
    and (g.start_date between '2017-08-10' and '2017-08-12'
        or g.end_date between '2017-08-10' and '2017-08-12')
left join availability a on u.id = a.user_id
    and (a.start_date between '2017-08-10' and '2017-08-12'
        or a.end_date between '2017-08-10' and '2017-08-12')
where g.user_id is null and a.user_id is null;

Demo 演示

I dont like using human readable dates because of MMDDYYYY vs DDMMYYYY, but rather use UNIXTIME dates, so i will pseudocode accordingly 因为MMDDYYYY和DDMMYYYY,我不喜欢使用人类可读的日期,而是使用UNIXTIME日期,所以我将相应地伪代码

SELECT * 
FROM Users
LEFT JOIN Games ON Users.Id = Games.Id_User
LEFT JOIN Availability ON Users.Id = Availability.Id_User
WHERE ISNULL(Games.Id) AND ((Start_Date > EndDateUnixtime OR End_Date < StartDateUnixtime)  OR ISNULL(Start_Date) OR ISNULL(End_Date))

You can use this logic to convert DMMYYYY dates to unixtime in case you keep on recording human readable dates. 如果继续记录人类可读日期,您可以使用此逻辑将DMMYYYY日期转换为unixtime。

unix_timestamp(str_to_date('30/05/2011','%d/%m/%Y'))

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

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