查询具有非线性数据的日志 table
Querying a log table with nonlinear data
我正在尝试 运行 对包含大量非线性数据的日志样式 table 进行一些查询。我有以下架构:
Signouts
+------------+----------------+------------+----------+
| signout_id | environment_id | date_start | date_end |
+------------+----------------+------------+----------+
| int | int | datetime | datetime |
+------------+----------------+------------+----------+
Environments
+-----+---------+
| id | name |
+-----+---------+
| int | varchar |
+-----+---------+
Signouts
是日志 table(我说 "log table" 因为记录永远不会更新,只标记为 "disabled" 并重新添加)。当用户注销环境时,他们选择的开始和结束时间将输入注销 table。目前,要查看环境是否已注销,我只需检查当前日期是否在 date_start
和 date_end
之间。如果另一个用户想要退出该环境,他们可以选择的最短时间是当前退出的结束日期。
不过,我现在面临新的挑战。我现在需要实施一个 reservation 系统。一时之间,日期可以是未来任何地方,环境可以随时预约。现在我需要知道何时仍然可以注销环境,以及那些最小(现在是最大)值是多少!
我已经把它归结为这个天真的计划,但我很难把它变成 SQL:
get all signouts where start < curdate & end > curdate
if there is no current signout, get the min start of all signouts where start > curdate
if there is a signout, get the max end
这是我得到的最接近的,在 许多 其他废弃的查询中:
SELECT s.date_start_unavailable, s.date_available, e.id AS environment_id
FROM Environments AS e
LEFT OUTER JOIN (
SELECT TOP (100) PERCENT signout_id, environment_id, username, date_start, date_end, project, notes, in_use, max(date_end) as date_available, min(date_start) as date_start_unavailable
FROM dbo.Signouts
WHERE date_end >= GETDATE()
GROUP BY signout_id, environment_id, username, date_start, date_end, project, notes, in_use
ORDER BY date_start DESC
) AS s ON s.environment_id = e.id
这几乎有效。 date_start_unavailable
是系统无法注销的时间,dave_available
是不再有注销的时间。但是,这仍然存在问题;有人可以将未来几年的环境保留一个月,而普通用户将无法看到大部分时间都未分配。我必须找到一种方法来限制它,但我可以稍后再担心。
注销持续任意的、用户输入的时间量,否则实施时间块系统将是微不足道的。如果有人能提供一些DBA智慧,将不胜感激!
像这样设置我的测试环境:
create table environment (id int, name varchar(255));
insert into environment values (1, 'DVD');
insert into environment values (2, 'BluRay');
create table signout (id int, environment_id int, date_start date, date_end date);
insert into signout values (1, 1, '01.11.2015', '09.11.2015');
insert into signout values (2, 1, '10.11.2015', '12.11.2015');
insert into signout values (3, 1, '01.12.2015', '24.12.2015');
insert into signout values (4, 2, '01.12.2015', '02.12.2015');
insert into signout values (5, 2, '04.12.2015', '07.12.2015');
insert into signout values (6, 2, '11.12.2015', '13.12.2015');
insert into signout values (7, 2, '14.12.2015', '23.12.2015');
现在,选择预订时间很简单:
select e.name, s.date_start d_start, s.date_end d_end, 'booked' as d_status FROM
signout s inner join environment e ON e.id = s.environment_id
Bu 空闲时间呢?这些将是不存在预订的时间 - 因此您按给定顺序加入 table 自身:
select e.name, dateadd(DAY, 1, s.date_end) d_start,
COALESCE(dateadd(day, -1, s2.date_start), '31.12.2025') d_end, 'free'
FROM signout s
OUTER APPLY (
SELECT TOP 1 date_start, date_end from signout sx
WHERE sx.environment_id = s.environment_id
AND sx.date_start > s.date_end ORDER BY sx.date_start
) s2
inner join environment e ON e.id = s.environment_id
WHERE (s2.date_end is NULL OR s2.date_start > dateadd(DAY, 1, s.date_end))
现在将它们联合起来并根据环境和日期添加排序:
select e.name, s.date_start d_start, s.date_end d_end, 'booked' as d_status FROM
signout s inner join environment e ON e.id = s.environment_id
AND s.date_start > getdate()
UNION
select e.name, dateadd(DAY, 1, s.date_end) d_start,
COALESCE(dateadd(day, -1, s2.date_start), '31.12.2025') d_end, 'free'
FROM signout s
OUTER APPLY (
SELECT TOP 1 date_start, date_end from signout sx
WHERE sx.environment_id = s.environment_id
AND sx.date_start > s.date_end ORDER BY sx.date_start
) s2
inner join environment e ON e.id = s.environment_id
WHERE (s2.date_end is NULL OR s2.date_start > dateadd(DAY, 1, s.date_end))
AND s.date_start > getdate()
ORDER BY 1, 2
这让我明白了:
BluRay 2015-12-01 2015-12-02 booked
BluRay 2015-12-03 2015-12-03 free
BluRay 2015-12-04 2015-12-07 booked
BluRay 2015-12-08 2015-12-10 free
BluRay 2015-12-11 2015-12-13 booked
BluRay 2015-12-14 2015-12-23 booked
BluRay 2015-12-24 2025-12-31 free
DVD 2015-11-10 2015-11-12 booked
DVD 2015-11-13 2015-11-30 free
DVD 2015-12-01 2015-12-24 booked
DVD 2015-12-25 2025-12-31 free
我正在尝试 运行 对包含大量非线性数据的日志样式 table 进行一些查询。我有以下架构:
Signouts
+------------+----------------+------------+----------+
| signout_id | environment_id | date_start | date_end |
+------------+----------------+------------+----------+
| int | int | datetime | datetime |
+------------+----------------+------------+----------+
Environments
+-----+---------+
| id | name |
+-----+---------+
| int | varchar |
+-----+---------+
Signouts
是日志 table(我说 "log table" 因为记录永远不会更新,只标记为 "disabled" 并重新添加)。当用户注销环境时,他们选择的开始和结束时间将输入注销 table。目前,要查看环境是否已注销,我只需检查当前日期是否在 date_start
和 date_end
之间。如果另一个用户想要退出该环境,他们可以选择的最短时间是当前退出的结束日期。
不过,我现在面临新的挑战。我现在需要实施一个 reservation 系统。一时之间,日期可以是未来任何地方,环境可以随时预约。现在我需要知道何时仍然可以注销环境,以及那些最小(现在是最大)值是多少!
我已经把它归结为这个天真的计划,但我很难把它变成 SQL:
get all signouts where start < curdate & end > curdate
if there is no current signout, get the min start of all signouts where start > curdate
if there is a signout, get the max end
这是我得到的最接近的,在 许多 其他废弃的查询中:
SELECT s.date_start_unavailable, s.date_available, e.id AS environment_id
FROM Environments AS e
LEFT OUTER JOIN (
SELECT TOP (100) PERCENT signout_id, environment_id, username, date_start, date_end, project, notes, in_use, max(date_end) as date_available, min(date_start) as date_start_unavailable
FROM dbo.Signouts
WHERE date_end >= GETDATE()
GROUP BY signout_id, environment_id, username, date_start, date_end, project, notes, in_use
ORDER BY date_start DESC
) AS s ON s.environment_id = e.id
这几乎有效。 date_start_unavailable
是系统无法注销的时间,dave_available
是不再有注销的时间。但是,这仍然存在问题;有人可以将未来几年的环境保留一个月,而普通用户将无法看到大部分时间都未分配。我必须找到一种方法来限制它,但我可以稍后再担心。
注销持续任意的、用户输入的时间量,否则实施时间块系统将是微不足道的。如果有人能提供一些DBA智慧,将不胜感激!
像这样设置我的测试环境:
create table environment (id int, name varchar(255));
insert into environment values (1, 'DVD');
insert into environment values (2, 'BluRay');
create table signout (id int, environment_id int, date_start date, date_end date);
insert into signout values (1, 1, '01.11.2015', '09.11.2015');
insert into signout values (2, 1, '10.11.2015', '12.11.2015');
insert into signout values (3, 1, '01.12.2015', '24.12.2015');
insert into signout values (4, 2, '01.12.2015', '02.12.2015');
insert into signout values (5, 2, '04.12.2015', '07.12.2015');
insert into signout values (6, 2, '11.12.2015', '13.12.2015');
insert into signout values (7, 2, '14.12.2015', '23.12.2015');
现在,选择预订时间很简单:
select e.name, s.date_start d_start, s.date_end d_end, 'booked' as d_status FROM
signout s inner join environment e ON e.id = s.environment_id
Bu 空闲时间呢?这些将是不存在预订的时间 - 因此您按给定顺序加入 table 自身:
select e.name, dateadd(DAY, 1, s.date_end) d_start,
COALESCE(dateadd(day, -1, s2.date_start), '31.12.2025') d_end, 'free'
FROM signout s
OUTER APPLY (
SELECT TOP 1 date_start, date_end from signout sx
WHERE sx.environment_id = s.environment_id
AND sx.date_start > s.date_end ORDER BY sx.date_start
) s2
inner join environment e ON e.id = s.environment_id
WHERE (s2.date_end is NULL OR s2.date_start > dateadd(DAY, 1, s.date_end))
现在将它们联合起来并根据环境和日期添加排序:
select e.name, s.date_start d_start, s.date_end d_end, 'booked' as d_status FROM
signout s inner join environment e ON e.id = s.environment_id
AND s.date_start > getdate()
UNION
select e.name, dateadd(DAY, 1, s.date_end) d_start,
COALESCE(dateadd(day, -1, s2.date_start), '31.12.2025') d_end, 'free'
FROM signout s
OUTER APPLY (
SELECT TOP 1 date_start, date_end from signout sx
WHERE sx.environment_id = s.environment_id
AND sx.date_start > s.date_end ORDER BY sx.date_start
) s2
inner join environment e ON e.id = s.environment_id
WHERE (s2.date_end is NULL OR s2.date_start > dateadd(DAY, 1, s.date_end))
AND s.date_start > getdate()
ORDER BY 1, 2
这让我明白了:
BluRay 2015-12-01 2015-12-02 booked
BluRay 2015-12-03 2015-12-03 free
BluRay 2015-12-04 2015-12-07 booked
BluRay 2015-12-08 2015-12-10 free
BluRay 2015-12-11 2015-12-13 booked
BluRay 2015-12-14 2015-12-23 booked
BluRay 2015-12-24 2025-12-31 free
DVD 2015-11-10 2015-11-12 booked
DVD 2015-11-13 2015-11-30 free
DVD 2015-12-01 2015-12-24 booked
DVD 2015-12-25 2025-12-31 free