SQL-запрос для возврата строк, где список чисел находится между начальным и конечным значениями - PullRequest
1 голос
/ 05 января 2012

В Oracle есть таблица со столбцами:

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.

Используя приведенный выше пример;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
)

Ответы [ 3 ]

3 голосов
/ 05 января 2012

Вот полный пример:

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) и поместить table в select.

2 голосов
/ 05 января 2012

Это частично зависит от того, как вы храните свой список номеров.Я предполагаю, что они пока находятся в другой таблице, так как даже тогда у вас есть много вариантов.

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 и затем проверяют каждую запись по вашему списку.

Что может быть предпочтительнее, это сканировать список, а затем пытаться использовать индексы для проверки по исходным данным,Это потребует от вас возможности изменить оператор 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 в другой таблице и обновил бы его по мере изменения значений в вашей таблице.

1 голос
/ 05 января 2012

Вы захотите создать временную таблицу для хранения ваших чисел, если числа еще не в одном. Тогда это становится относительно простым:

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

Чтобы создать таблицу на основе массива переданных значений, вы можете использовать определения таблиц в своей процедуре. Я разбираюсь в синтаксисе Oracle и не имею под рукой TOAD, но вы должны иметь возможность заставить что-то подобное работать:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...