表子集中最小的可用整数 - SQL

时间:2015-07-06 19:27:05

标签: sql sql-server

我正在使用现有的表来存储开始日期,结束日期和用于排序的整数。

对于特定的开始&结束日期,我需要能够确定具有重叠日期范围的条目的最小可用整数。

例如,我的表可能存储这些记录:

7月8日 - > 7月9日订货指数为0。

7月9日 - > 7月10日,订购指数为1。

7月9日 - > 7月11日订货指数为2.

然后,给定日期范围 7月10日 - > 7月11日,我想将排序索引设置为 0

它需要在输入日期范围内没有其他条目的情况下工作(因此它可以默认为0)。日期范围并不总是相隔两个日期,订购索引没有限制。

我所拥有的只返回最大订单索引之上的一个:

SELECT ISNULL(MAX(order_index),-1) + 1 FROM table
WHERE start_date <= @end AND end_date >= @start)

我尝试使用this answer,但无法获得所需的结果。

3 个答案:

答案 0 :(得分:1)

这样的事情怎么样?

declare @SampleData table ([BeginDate] date, [EndDate] date, [Order] int);
insert @SampleData values
    ('2015-07-08', '2015-07-09', 0),
    ('2015-07-09', '2015-07-10', 1),
    ('2015-07-09', '2015-07-11', 2);

declare @Start date = '2015-07-10';
declare @End date = '2015-07-11';

with [OrderingCTE] as
(
    select
        [Order],
        [Ideal Order] = row_number() over (order by [Order]) - 1
    from
        @SampleData
    where
        [BeginDate] <= @End and
        [EndDate] >= @Start
)
select coalesce
(
    min(case [Order] when [Ideal Order] then null else [Ideal Order] end),
    max([Order]) + 1
)
from
    [OrderingCTE];

CTE为源表中的每条记录生成两个排序:[Order]是存储在记录中的实际值,而[Ideal Order] 的值。所有可能的排序(从零开始)都在给定的日期范围内使用。

如果[Ideal Order]在任何时候与[Order]不同,您可以推断当前[Ideal Order]值尚未使用,因此是最小可用值。如果在任何时候都不是这样,那么最小可用值比目前使用的最大值大1;这是脚本底部COALESCE的后半部分。

最后请注意:您链接的问题another answer引发了对可能出现的竞争条件的担忧,具体取决于您尝试使用以这种方式查询的数据的方式。如果你还没有这样做,我强烈建议你去看看。

答案 1 :(得分:0)

我认为你可以通过枚举值来做到这一点。如果我假设订单索引没有重复,那么你可以使用row_number()和一些算术来找到&#34; hole&#34;。需要额外的逻辑来处理边缘情况。

with t as (
      select t.*,
             row_number() over (order by order_index) as seqnum,
             min(order_index) over () as minoi,
             max(order_index) over () as maxoi
      from table t
      where start_date <= @end and end_date >= @start
     )
select (case when min(minoi) > 0 then 0
             when min(minoi) is null then min(maxoi + 1)
             else min(minoi + seqnum - 1)
        end)
from t 
where order_index <> minoi + seqnum - 1 or
      order_index = maxoi

答案 2 :(得分:0)

我会尝试这样的事情:

SELECT
  COALESCE(
    MIN(CASE WHEN t2.order_index IS NULL THEN t1.order_index - 1 ELSE NULL END),
    MAX(t1.order_index) + 1,
    0)
FROM TheTable t1
LEFT JOIN TheTable t2
  ON t2.order_index = t1.order_index - 1
    AND t2.start_date <= @end
    AND t2.end_date >= @start
WHERE t1.start_date <= @end
  AND t1.end_date >= @start