使用非线性数据查询日志表

时间:2015-02-18 18:09:33

标签: sql sql-server database database-design

我正在尝试在包含一堆非线性数据的日志样式表上运行一些查询。我有以下架构:

Signouts
+------------+----------------+------------+----------+
| signout_id | environment_id | date_start | date_end |
+------------+----------------+------------+----------+
| int        | int            | datetime   | datetime |
+------------+----------------+------------+----------+

Environments
+-----+---------+
| id  |  name   |
+-----+---------+
| int | varchar |
+-----+---------+

Signouts是日志表(我说“日志表”因为记录永远不会更新,只会标记为“已禁用”并重新添加)。当用户注销环境时,他们选择的开始和结束时间将输入到注销表中。目前,要查看环境是否已注销,我只需检查当前日期是否介于date_startdate_end之间。如果其他用户想要退出该环境,他们可以选择的最短时间是当前退出的结束日期。

但我现在面临新的挑战。我现在需要实现预订系统。突然之间,日期可以在将来的任何地方,并且可以随时保留环境。现在我需要知道什么时候仍然可以注销一个环境,以及那些最小(现在最大)的值是什么!

我已经把它归结为这个天真的计划,但是我无法将其纳入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智慧,那将非常感激!

1 个答案:

答案 0 :(得分:1)

像这样设置我的测试环境:

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

那么空闲时间呢?这些将是没有预订的时间 - 因此您按照给定的顺序加入表格:

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