Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Переписать запрос  [new]
SqlDreamer
Guest
Довольно распространенная задача, фильтры по входным параметрам (параметры могут быть, а могут и не быть).
Т.е. упрощенно, в наличии две таблицы,
надо вывести все записи из первой таблицы, в привязке ко второй (параметры),
но если во второй записей нет (параметры не заданы), то из первой вывести все записи. Без дин.скл.
Обычно что-то типа такого:
create table table1
as
select level lvl
  from dual connect by level<1000000;
  
create table table2
as
select cast(null as number) lvl from dual where 1=2;

-- вариант 1
with t2 as (select count(*) cnt from table2)
select t1.*
  from table1 t1, t2
 where t2.cnt = 0
    or (t2.cnt > 0 and t1.lvl in (select lvl from table2 t3));
    
-- вариант 2    
with t2 as (select null lvl 
             from dual
            where 0 = (select count(*) cnt from table2)
            union all
            select lvl from table2)
select t1.*
  from table1 t1, t2
 where t1.lvl = nvl(t2.lvl, t1.lvl);

По сути не сильно отличаются по-моему и вроде работает,
но что-то не нравится (в первом случае каждый раз проверка t2.cnt, во втором NVL)
и ощущение, что можно переписать как-то более изящно что ли.
15 апр 17, 09:48    [20404127]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
Elic
Member

Откуда:
Сообщений: 29990
SqlDreamer
Довольно распространенная задача, фильтры по входным параметрам (параметры могут быть, а могут и не быть).
Т.е. упрощенно, в наличии две таблицы,
надо вывести все записи из первой таблицы, в привязке ко второй (параметры),
но если во второй записей нет (параметры не заданы), то из первой вывести все записи.
Каждый кулик своёболото считает образцом для подражания.
SqlDreamer
Обычно что-то типа такого:
Обычно используют bind-ы. А если приложение недо-, то обычно с этого и начинают.
15 апр 17, 10:00    [20404143]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
SqlDreamer
Guest
Elic
Обычно используют bind-ы. А если приложение недо-, то обычно с этого и начинают.

Чота вы сегодня не с той ноги, сразу болтом обзываетесь ) между тем действительно встречал немало болот, где используют подобный подход. Бинды конечно есть, по ним и достаются данные в table2, здесь упростил, чтобы отразить суть вопроса.
То есть данные из table2 достаются по биндам, а далее они являются фильтром для table1, но если в table2 ничего не попало, то из table1 надо достать все.
15 апр 17, 14:09    [20404424]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
ora601
Member

Откуда:
Сообщений: 750
SqlDreamer
Т.е. упрощенно, в наличии две таблицы,
надо вывести все записи из первой таблицы, в привязке ко второй (параметры),
но если во второй записей нет (параметры не заданы), то из первой вывести все записи. Без дин.скл.


LEFT JOIN ?? :)
15 апр 17, 20:25    [20404877]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
SqlDreamer
Guest
ora601
LEFT JOIN ?? :)

Типа такого?
with t2 as (select lvl 
              from table1
             where 0 = (select count(*) cnt from table2)
             union all
            select lvl from table2)
select t1.*
  from t2, table1 t1
 where t2.lvl = t1.lvl(+);

Но тогда если в table2 нет записей, то джоин как бы вообще не нужен. Выходит, только дин.скл.
16 апр 17, 10:26    [20405355]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
JaRo
Member

Откуда:
Сообщений: 1659
select lvl from (
select table1.*, table2.lvl t2_lvl, count(table2.lvl) over () cou
from table1, table2
where table1.lvl = table2.lvl(+)
) where cou = 0 or t2_lvl is not null
PS: lvl во второй таблице ведь не может быть null? ну или если может, то это не считается "в привязке ко второй" или как?
21 апр 17, 17:49    [20423406]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
ora601
Member

Откуда:
Сообщений: 750
SqlDreamer,

with t2_cnt AS 

(SELECT COUNT(*) cnt FROM t2)

SELECT t1.* 
FROM t1 LEFT JOIN t2 ON t1.id=t2.id

WHERE t2.id IS NOT NULL OR (SELECT cnt FROM t2_cnt) = 0 
 
21 апр 17, 18:18    [20423465]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
MaximaXXL
Member

Откуда: Киев
Сообщений: 652
SqlDreamer,

ну извратиться конечно можно =)

select t1.*
from t1, (select nvl(t2.lvl,null) lvl from dual left join t2 on (t2.f= :param/*условие на t2*/)) t3
where t1.lvl = nvl(t3.lvl, t1.lvl)
24 апр 17, 14:10    [20429225]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
MaximaXXL
Member

Откуда: Киев
Сообщений: 652
MaximaXXL,

даже так, точнее:
select t1.*
from t1, (select t2.lvl from dual left join t2 on (t2.f= :param/*условие на t2*/)) t3
where t1.lvl = nvl(t3.lvl, t1.lvl)


ну в общем мысль понятна ...
24 апр 17, 14:16    [20429258]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
dbms_photoshop
Member

Откуда: sqlmdx.net
Сообщений: 5151
MaximaXXL
ну в общем мысль понятна ...
Непонятно только почему ты приплел :param.

Если цель решить задачу ТС с одним проходом каждой из таблиц и без всяких аналитических сортировок,
то это можно (но не нужно) сделать примерно так
select * from t1 join dual left join t2 on 0 = 0 on t1.id = nvl(t2.id, t1.id)

В 12с вместо нелепого left join можно было бы использовать lateral/outer apply.
24 апр 17, 14:48    [20429461]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
MaximaXXL
Member

Откуда: Киев
Сообщений: 652
dbms_photoshop
Непонятно только почему ты приплел :param.
......
В 12с вместо нелепого left join можно было бы использовать lateral/outer apply.


ну это я в шар хрустальный глянул и понял что SqlDreamer будет передавать условия во внутреннюю таблицу и если записей нет то выдать все (так и писал)

по 12с - мы еще на 11 посему outer join пока
24 апр 17, 16:31    [20430127]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
dbms_photoshop
Member

Откуда: sqlmdx.net
Сообщений: 5151
MaximaXXL,

Вроде ТС довольно четко объяснил, что если t2 пустая, то выдаются все записи t1, иначе фильтруются по t2.
24 апр 17, 16:40    [20430178]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
Неужели всё так просто?
Guest
SqlDreamer,

select * from t1, t2 where t1.lvl = nvl(t2.lvl,t1.lvl)
24 апр 17, 16:52    [20430251]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
Пардоньте
Guest
Неужели всё так просто?,

select t1.* from table1 t1, table2 t2 where t1.lvl = nvl(t2.lvl,t1.lvl)
24 апр 17, 16:53    [20430255]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
dbms_photoshop
Member

Откуда: sqlmdx.net
Сообщений: 5151
Пардоньте
Неужели всё так просто?,

select t1.* from table1 t1, table2 t2 where t1.lvl = nvl(t2.lvl,t1.lvl)
Еще раз для танкистов: если t2 пустая - должны быть возвращены все строки из t1.

Неужели так сложно осилить формулировку из одной строки да еще и при наличии решений?
24 апр 17, 16:59    [20430276]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
MaximaXXL
Member

Откуда: Киев
Сообщений: 652
dbms_photoshop,

:param - это переменная для условия on (t2.f = значение)
Это ни в коем случае не часть аналитической функции

т.е. я выделил место где задавать условие, отлаживался я так =)
24 апр 17, 17:16    [20430326]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
MaximaXXL
Member

Откуда: Киев
Сообщений: 652
dbms_photoshop
MaximaXXL,

Вроде ТС довольно четко объяснил, что если t2 пустая, то выдаются все записи t1, иначе фильтруются по t2.


так и было написано, основной момент был указан что делать dual left Join table2 чтоб в случае пустой table2 после наложения условий была хотя-бы одна строка на выходе, значением которой можно управлять посредством nvl(t2.lvl,значение_для_пустой_таблицы). Но посмотрев в условие и увидев что SqlDreamer подходит null я просто заменил nvl(t2.lvl,значение_для_пустой_таблицы) на t2.lvl.

Ваш вариант более предпочтителен в конкретно поставленной задаче, я не спорю
24 апр 17, 17:25    [20430352]     Ответить | Цитировать Сообщить модератору
 Re: Переписать запрос  [new]
dbms_photoshop
Member

Откуда: sqlmdx.net
Сообщений: 5151
MaximaXXL,

Более предпочтительна здесь скорее всего динамика, с генерацией in (list) вместо t2 по мере необходимости.
Но, я думаю, мы друг друга поняли.
24 апр 17, 17:34    [20430372]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить