2012-01-05 40 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

相關問題