2014-09-27 115 views
0

我有哪里范围存储SQL查找范围

Fileno|fileFrom|fileTo 
Abc |1  |20 
Abc |21  |50 
DGM |51  |60 

我显示此记录用户使用gridview的asp.net

用户输入他已经完成印刷范围的SQL表差距

例如; 31至40

现在我想告诉用户他再次访问该页面时 像

Fileno|fileFrom|fileTo 
Abc |1  |30 
Abc |41  |50 
DGM |51  |60 

如何使用SQL服务器来达到相同的结果待定的范围?

+1

只要是明确的:如果用户输入A..B,并没有为范围X..Y的记录(用X <=A & Y> = B),要更换这个纪录一个用于范围X..A-1(如果X <= A-1)和B + 1..Y(如果Y> = B + 1)? – 2014-09-27 12:55:47

+0

对不起!我已编辑输出 – 2014-09-27 12:59:40

+0

您是否考虑存储用户已完成打印的范围? – 2014-09-27 13:23:07

回答

0

您应该更新在末端部分重叠的范围,删除完全覆盖的范围并拆分中间覆盖的范围。

-- partial overlap at the begining 
update table ranges 
set filefrom = @to + 1 
where fileno = @fileno and @from <= filefrom and @to < fileto 

-- partial overlap at the end 
update table ranges 
set fileto = @from - 1 
where fileno = @fileno and @from > filefrom and @to >= fileto 

-- complete overlap 
delete from ranges 
where fileno = @fileno and @from <= filefrom and @to >= fileto 

-- split 
insert into ranges 
select fileno, filefrom, @from - 1 
from ranges 
where fileno = @fileno and @from > filefrom and @to < fileto 

insert into ranges 
select fileno, @to + 1, fileto 
from ranges 
where fileno = @fileno and @from > filefrom and @to < fileto 

delete from ranges 
where fileno = @fileno and @from > filefrom and @to < fileto 
+0

我想到了。我们需要在每个插页上执行六个命令。所以这会影响表现,所以我有第二个想法。但这是最好的选择吗? – 2014-09-28 04:18:56

+0

如果您的原始范围不重叠,则分割范围的情况会排除其他范围。你可以查询范围内的字段进行拆分,如果没有前三个字段,则执行拆分。 – 1010 2014-09-29 16:13:24

1

当存储范围

当你想从一组可能重叠 范围删除范围,需要多个语句。

 
To be printed   |-------| 
Actually printed  |---| 

例如,当用户打印范围的“中间”块,留下 开始和结束区块未打印的,你不能更新与 一个SQL语句中的数据。您必须更新原始行,并且 会插入一个新行,或者您必须删除原始行并插入两行 行。

事实上,无法预测是否需要更新语句,多个更新语句或更新和插入语句的组合是红色标记。

在任何情况下,每个用户都必须在该表上选择,插入,更新和删除 特权。您是否可以忍受这是依赖于应用程序的 ,但这是另一个红旗。

这些红旗并不意味着“永远不要这样做”。他们意思是停下来,坐在你的手上,并说,“等一下......”

当存储个别事实

这往往简单存储个别事实,而不是他们的 范围。有几种不同的方法:a)仅存储需要打印的 ; b)存储需要打印的内容和 已打印的内容。

如果您只存储需要打印的内容,记录什么已被 打印只需要选择和删除权限。

如果使用两个表 - 存储在一个“要打印”,并在其他“已经 印” - 用户需要只选择特权“是 印有”(选择,如果插入特权用户可以添加要打印的东西 ),并在“已打印”上选择并插入权限。

例如,如果您只存储需要打印的内容,请使用此表启动 。

-- Does *not* assume that to_print is unique. 
create table to_be_printed (
    file_no varchar(10) not null, 
    to_print integer not null 
    check (to_print > 0), 
    primary key (file_no, to_print) 
); 

create index on to_be_printed (to_print); 

insert into to_be_printed values 
('Abc', 1), ('Abc', 2), ('Abc', 3), ('Abc', 4), ('Abc', 5), 
('Abc', 6), ('Abc', 7), ('Abc', 8), ('Abc', 9), ('Abc', 10), 
('Abc', 11), ('Abc', 12), ('Abc', 13), ('Abc', 14), ('Abc', 15), 
('Abc', 16), ('Abc', 17), ('Abc', 18), ('Abc', 19), ('Abc', 20), 
('Abc', 21), ('Abc', 22), ('Abc', 23), ('Abc', 24), ('Abc', 25), 
('Abc', 26), ('Abc', 27), ('Abc', 28), ('Abc', 29), ('Abc', 30), 
('Abc', 31), ('Abc', 32), ('Abc', 33), ('Abc', 34), ('Abc', 35), 
('Abc', 36), ('Abc', 37), ('Abc', 38), ('Abc', 39), ('Abc', 40), 
('Abc', 41), ('Abc', 42), ('Abc', 43), ('Abc', 44), ('Abc', 45), 
('Abc', 46), ('Abc', 47), ('Abc', 48), ('Abc', 49), ('Abc', 50), 
('DGM', 51), ('DGM', 52), ('DGM', 53), ('DGM', 54), ('DGM', 55), 
('DGM', 56), ('DGM', 57), ('DGM', 58), ('DGM', 59), ('DGM', 60); 

为了指示用户已经通过31 40印刷号码,从该表只是删除 那些行。

delete from to_be_printed 
where to_print between 31 and 40; 

友好的呈现

存储单个事实并不完全解决问题。您 可能仍然需要向用户提供数据作为每个 文件编号的范围。这类问题的搜索条件是“sql间隙和 岛屿”。

select file_no, min(to_print) as range_start, max(to_print) as range_end 
from 
    (select file_no 
      , to_print 
      , to_print - row_number() over 
          (partition by file_no order by to_print) as grouping 
    from to_be_printed 
    ) as d 
group by file_no, grouping 
order by file_no, range_start; 
 
file_no range_start range_end 
-- 
Abc  1   30 
Abc  41   50 
DGM  51   60