SQL请求(不包括时间段)

时间:2019-06-07 09:01:35

标签: mysql sql left-join right-to-left period

我需要获取所有DISTINCT用户(根据不可用时间段不可用的用户除外)。

SHIFT表:

user

+------+-----------+--------------------------------------+ | id | firstname | content | +------+-----------+--------------------------------------+ | 13 | John | ... | | 44 | Marc | ... | | 55 | Elise | ... | +------+-----------+--------------------------------------+ 期表:

unavailability

例如,我们希望在2019-06-20到2019-07-05期间可用的用户:Marc和Elise可用。

我必须使用LEFT JOIN吗?该请求无效:

+------+-----------+--------------+--------------+
| id   | user_id   | start        | end          |
+------+-----------+--------------+--------------+
| 1    | 13        | 2019-07-01   | 2019-07-10   |
| 2    | 13        | 2019-07-20   | 2019-07-30   |
| 3    | 13        | 2019-09-01   | 2019-09-30   |
| 4    | 44        | 2019-08-01   | 2019-08-15   |
+------+-----------+--------------+--------------|

结果我需要:

SELECT DISTINCT user.*, unavailability.start, unavailability.end,
FROM user
LEFT JOIN unavailability ON unavailability.user_id = user.id
WHERE  
unavailability.start < "2019-06-20" AND unavailability.end > "2019-06-20"
AND unavailability.start < "2019-07-05" AND unavailability.end > "2019-07-05"

有了这个请求,我不会遇到没有空闲时间段的Elise。

3 个答案:

答案 0 :(得分:2)

DROP TABLE IF EXISTS user;

CREATE TABLE user

(id SERIAL PRIMARY KEY
,firstname VARCHAR(12) NOT NULL UNIQUE
);

INSERT INTO user VALUES
(13,'John'),
(44,'Marc'),
(55,'Elise');

DROP TABLE IF EXISTS unavailability ;

CREATE TABLE unavailability 
(id SERIAL PRIMARY KEY
,user_id INT NOT NULL
,start DATE NOT NULL
,end DATE NOT NULL
);

INSERT INTO unavailability VALUES
(1,13,'2019-07-01','2019-07-10'),
(2,13,'2019-07-20','2019-07-30'),
(3,13,'2019-09-01','2019-09-30'),
(4,44,'2019-08-01','2019-08-15');

SELECT x.* 
  FROM user x 
  LEFT 
  JOIN unavailability y 
    ON y.user_id = x.id 
   AND y.start <= '2019-07-05' 
   AND y.end >= '2019-06-20' 
 WHERE y.id IS NULL;
+----+-----------+
| id | firstname |
+----+-----------+
| 44 | Marc      |
| 55 | Elise     |
+----+-----------+
2 rows in set (0.01 sec)

答案 1 :(得分:2)

可以使用这种方法:

select * from user k
where not exists (
select 1 from user 
join unavailability u on u.user_id = user.id
and ('2019-06-20' between start and end or '2019-07-05' between start and end)
where user.id = k.id)

答案 2 :(得分:1)

您可以选择不可用的ID,并在子查询中使用此结果:

模式(MySQL v5.7)

CREATE TABLE user (
  `id` INTEGER,
  `firstname` VARCHAR(5),
  `content` VARCHAR(3)
);

INSERT INTO user
  (`id`, `firstname`, `content`)
VALUES
  (13, 'John', '...'),
  (44, 'Marc', '...'),
  (55, 'Elise', '...');



CREATE TABLE unavailability (
  `id` INTEGER,
  `user_id` INTEGER,
  `start` DATETIME,
  `end` DATETIME
);

INSERT INTO unavailability
  (`id`, `user_id`, `start`, `end`)
VALUES
  (1, 13, '2019-07-01', '2019-07-10'),
  (2, 13, '2019-07-20', '2019-07-30'),
  (3, 13, '2019-09-01', '2019-09-30'),
  (4, 44, '2019-08-01', '2019-08-15');

查询#1

SELECT *
FROM user us
WHERE us.id NOT IN (
  SELECT u.user_id
  FROM unavailability u
  WHERE u.start <= '2019-07-05' AND u.end >= '2019-06-20'
);

| id  | firstname | content |
| --- | --------- | ------- |
| 44  | Marc      | ...     |
| 55  | Elise     | ...     |

View on DB Fiddle


注意

这种情况:

unavailability.start < 2019-06-20 AND unavailability.end > 2019-06-20
AND unavailability.start < 2019-07-05 AND unavailability.end > 2019-07-05

将被这样评估:

unavailability.start < 2019-06-20 AND unavailability.end > 2019-07-05

因为对于部分unavailability.start < 2019-06-20 AND unavailability.start < 2019-07-052019-07-05以下但2019-06-20以上的所有内容都将被排除(您正在使用AND)。 unavailability.end

都一样