查询具有非线性数据的日志 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_startdate_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