2012-01-05 45 views
1

有Oracle中的表中的列之间:SQL查询返回行,其中编号的列表是开始和结束值

id | start_number | end_number 
---+--------------+------------ 
1 | 100   | 200 
2 | 151   | 200 
3 | 25   | 49 
4 | 98   | 99 
5 | 49   | 100 

有数字(50,99,150)的列表。

我想要一个sql语句,它返回数字列表中的任何数字与start_number和end_number之间相等的所有id。

使用上面的例子;应该返回1,4和5。
1 - 150是和之间或等于100 200
2 - 没有数字的是之间或等于151和200
3 - 没有数字的是之间或等于25和49
4 - 99在和之间或等于98 99
5 - 50 99之间或等于49和100

drop table TEMP_TABLE; 

create table TEMP_TABLE(
THE_ID number, 
THE_START number, 
THE_END number 
); 

insert into TEMP_TABLE(THE_ID, THE_START, THE_END) values (1, 100, 200); 
insert into TEMP_TABLE(THE_ID, THE_START, THE_END) values (2, 151, 200); 
insert into TEMP_TABLE(THE_ID, THE_START, THE_END) values (3, 25, 49); 
insert into TEMP_TABLE(THE_ID, THE_START, THE_END) values (4, 98, 99); 
insert into TEMP_TABLE(the_id, the_start, the_end) values (5, 49, 100); 

以下是我想出了根据该意见,并回答下面加上一些额外的研究解决方案:

SELECT 
* 
from 
TEMP_TABLE 
where 
EXISTS (select * from(
select column_value as id 
from table(SYS.DBMS_DEBUG_VC2COLL(50,99,150)) 
) 
where id 
BETWEEN TEMP_TABLE.the_start AND TEMP_TABLE.the_end 
) 

这工作太:

SELECT 
* 
from 
TEMP_TABLE 
where 
EXISTS (select * from(
select column_value as id 
from table(sys.ku$_vcnt(50,99,150)) 
) 
where id 
BETWEEN TEMP_TABLE.the_start AND TEMP_TABLE.the_end 
) 
+0

谢谢你的快速反应(和民主党重新格式化我的问题)。 – irrational 2012-01-05 18:17:08

+0

在这种情况下,数字列表不在表格中。有没有办法做到这一点,而不把数字列表放入不同的表格? – irrational 2012-01-05 18:18:07

+0

你如何提供数字列表? – MatBailie 2012-01-05 18:19:22

回答

2

这部分取决于你是如何存储你的号码清单。我假设他们现在在另一张桌子上,因为即使你有很多选择。

SELECT 
    * 
FROM 
    yourTable 
WHERE 
    EXISTS (SELECT * FROM yourList WHERE number BETWEEN yourTable.start_number AND yourTable.end_number) 

或者......

SELECT 
    * 
FROM 
    yourTable 
INNER JOIN 
    yourList 
    ON yourList.number BETWEEN yourTable.start_number AND yourTable.end_number 

那些无论是最简单的表达,而对于小数据集工作。如果您的数字列表相对较小,而您的原始数据相对较大,则这可能无法很好地扩展。这是因为以上两种情况都会扫描整个yourTable,然后根据yourList检查每条记录。

可能更可取的是扫描列表,然后尝试使用索引来检查原始数据。这将要求您能够将BETWEEN语句翻转为yourTable.start_number BETWEEN x and y

这只能在知道start_number和end_number之间的最大差距时完成。

SELECT 
    * 
FROM 
    yourList 
INNER JOIN 
    yourTable 
    ON yourTable.end_number >= yourList.number 
    AND yourTable.start_number <= yourList.number 
    AND yourTable.start_number >= yourList.number - max_gap 

为了达到这个目的,我会将max_gap的值存储在另一个表中,并将其更新为yourTable中的值更改。

3

这是一个完整的例子:

create table #list (
number int 
) 

create table #table (
id int, 
start_number int, 
end_number int 
) 

insert into #list values(50) 
insert into #list values(99) 
insert into #list values(150) 


insert into #table values(1,100,200) 
insert into #table values(2,151,200) 
insert into #table values(3,25,49) 
insert into #table values(4,98,99) 
insert into #table values(5,49,100) 


select distinct a.* from #table a 
inner join #list l --your list of numbers 
on l.number between a.start_number and a.end_number 


drop table #list 
drop table #table 

你只需要删除代码约#table (create, insert and drop),并把你的tableselect

+0

我使用SQL 2008 R2编写了几乎完全相同的代码。唯一的区别是我不是隐式连接的粉丝,所以我的FROM子句是FROM #table CROSS JOIN #list l – OCary 2012-01-05 18:14:01

+0

+1,但注意:这是有效的,并且是逻辑的最简单表达式。但无论您创建了什么索引,它总是会产生#table的扫描。这意味着它对于小数据集非常适用,并且对于大型数据集来说很痛苦。 – MatBailie 2012-01-05 18:16:54

1

如果数字不在一个,您将需要创建一个临时表来存放您的号码。然后它变得相对简单:

SELECT DISTINCT mt.ID FROM MyTable mt 
INNER JOIN TempTable tt --your list of numbers 
    ON tt.number Between mt.start_number and mt.end_number 

要基于传递值数组创建表,可以在过程中使用表定义。我对甲骨文语法轻,没有蟾蜍方便,但你应该能够得到这样的工作:

CREATE OR REPLACE PROCEDURE FindIdsFromList 
AS 
DECLARE 
    TYPE NumberRecord IS RECORD (Number int NOT NULL) 
    TYPE NumberList IS TABLE OF NumberRecord; 
    NumberList myNumberList; 
BEGIN 
myNumberList := (50,99,150); 
SELECT DISTINCT mt.ID FROM MyTable mt 
    INNER JOIN myNumberList nt --your list of numbers 
     ON nt.Number Between mt.start_number and mt.end_number 
END 
+0

+1不错的解决方案,我喜欢它! :) – 2012-01-05 18:16:27

+0

+1,但注意:这是有效的,是最简单的逻辑表达式。但无论您创建了什么索引,它总是会产生#table的扫描。这意味着它对于小数据集非常适用,并且对于大型数据集来说很痛苦。 – MatBailie 2012-01-05 18:17:52

+0

无论如何,我们正在主表中进行选择;这就是OP需要数据的地方,所以几乎任何算法都必须至少检查一次主表的每一行。它将以M * N时间时间执行,其中M是整个表的基数,N是列表的基数。在一般情况下,进一步降低问题的复杂性并不是一个好方法;您可以过滤MyTable中的最小值大于最大列表值或最大值小于最小值的记录。有效性取决于范围(#list)。 – KeithS 2012-01-05 18:31:42