Запрос с проверкой существования

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
nicolas
Сообщения: 33
Зарегистрирован: 11 сен 2006, 21:37

Запрос с проверкой существования

Сообщение nicolas » 11 сен 2006, 21:55

Здравствуй, All!

Есть FB 1.5
Есть две таблицы:

Код: Выделить всё

TEST_PARAMS (
    PARAM_ID     INTEGER NOT NULL,
    PARAM_NAME VARCHAR(300)
);

PARAM_DESC (
    PARAM_ID     INTEGER NOT NULL,
    DESC_TYPE   INTEGER NOT NULL,
    DESCRIPTION  VARCHAR(300)
);
таблицы связаны соотношением 1:* по полю PARAM_ID

Можно ли написать запрос (без использования ХП), для получения такой выборки:

Код: Выделить всё

   PARAM_ID,
   PARAM_NAME,
   FLAG
где FLAG = 1 если во второй таблице есть записи, соотв. PARAM_ID
FLAG = 0 если во второй таблице нет записей соотв. PARAM_ID

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 11 сен 2006, 22:14

RTFM Left Join

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 11 сен 2006, 22:16

можно. Тебе чтобы проще понять было или чтобы быстрее работало? :-)

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 11 сен 2006, 22:17

Merlin писал(а):RTFM Left Join
маловато будет. Ыщщо либо DISTINCT либо GROUP BY, однако.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 11 сен 2006, 22:20

dimitr писал(а):можно. Тебе чтобы проще понять было или чтобы быстрее работало? :-)
Устраиваясь в креслице с блокнотиком - угумс, сейчас я узнаю

а) что таки быстрее в обчем случае, ибо сам сумлеваюсь
б) подробнее о твоём образе мыслей - что ты лично считаешь проще понять ;)

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 11 сен 2006, 22:30

dimitr писал(а):
Merlin писал(а):RTFM Left Join
маловато будет. Ыщщо либо DISTINCT либо GROUP BY, однако.
Таки да. Тогда ыщо интереснее насчёт того, что будет быстрее, понятное или это ;)

nicolas
Сообщения: 33
Зарегистрирован: 11 сен 2006, 21:37

Сообщение nicolas » 11 сен 2006, 22:44

Интересно будет и быстрее и понятнее :)

Написал так:

Код: Выделить всё

select
    T0.PARAM_ID,
    T0.PARAM_NAME,
    COUNT(T1.PARAM_ID) FLAG
from
    TEST_PARAMS T0
    left outer join PARAM_DESC T1 on (T0.PARAM_ID = T1.PARAM_ID)
все как бы работает, но в столбце FLAG либо 0, либо число.
А хотелось бы 0 или 1

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 11 сен 2006, 22:49

полагаю, что быстрее всего будет что-то вроде:

Код: Выделить всё

select P.PARAM_ID, P.PARAM_NAME,
  coalesce((select first 1 1 from PARAM_DESC PD where PD.PARAM_ID = P.PARAM_ID), 0)
from TEST_PARAMS P
а насчет понятнее сложно сказать - тут вроде везде потребуются производные от CASE...

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 11 сен 2006, 22:54

вариация на тему Merlin'а:

Код: Выделить всё

select distinct P.PARAM_ID, P.PARAM_NAME, case when PD.PARAM_ID is null then 0 else 1 end
from TEST_PARAMS P left join PARAM_DESC PD on PD.PARAM_ID = P.PARAM_ID

nicolas
Сообщения: 33
Зарегистрирован: 11 сен 2006, 21:37

Сообщение nicolas » 11 сен 2006, 22:59

И первый и второй вариант понятны и вполне устраивают по скорости...
Огромное спасибо.

ЗЫ. И надо бы почитать побольше про CASE, к своему стыду не подозревал о такой возможности использования в запросах :(

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 11 сен 2006, 23:03

dimitr писал(а):полагаю, что быстрее всего будет что-то вроде:

Код: Выделить всё

select P.PARAM_ID, P.PARAM_NAME,
  coalesce((select first 1 1 from PARAM_DESC PD where PD.PARAM_ID = P.PARAM_ID), 0)
from TEST_PARAMS P
Вообще-то мне тоже так думалось, но попрыгавши в последнее время с бубном вокруг exists и left join я чего-то засомневался по результатам. Тут выигрыш подзапроса из-за дистинкта в джойне, пожалуй, будет бесспорным, согласен.
dimitr писал(а): а насчет понятнее сложно сказать - тут вроде везде потребуются производные от CASE...
Обычно неофиты сразу бросаются жонглировать подзапросами, они им ближе и родней :) Может я поэтому и свернул сразу рефлекторно его на джойн, чтоб учился мыслить ширше :)

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 12 сен 2006, 12:12

Чтобы уж "ширше" мыслить, то надо ещё и про exists упомянуть, и такой вариант тоже имеет право на жисть:

Код: Выделить всё

select distinct P.PARAM_ID, P.PARAM_NAME,
  case when exists (select * from PARAM_DESC where PARAM_ID = P.PARAM_ID) then 1 else 0 end
from TEST_PARAMS P
Хотя join, конечно же, будет быстрее.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 12 сен 2006, 13:57

WildSery писал(а):Чтобы уж "ширше" мыслить, то надо ещё и про exists упомянуть, и такой вариант тоже имеет право на жисть:

Код: Выделить всё

select distinct P.PARAM_ID, P.PARAM_NAME,
  case when exists (select * from PARAM_DESC where PARAM_ID = P.PARAM_ID) then 1 else 0 end
from TEST_PARAMS P
Вапервых distinct здесь лишний (моя вера в людей таки простирается настолько, чтоб считать что ID - это PK). Вавтарых это по сути то же самое, о чём говорил dimitr.
WildSery писал(а):Хотя join, конечно же, будет быстрее.
А вот и нет. Именно из-за distinct. В отношениях 1:1 зависит от распределения данных.

nicolas
Сообщения: 33
Зарегистрирован: 11 сен 2006, 21:37

Сообщение nicolas » 12 сен 2006, 15:12

Merlin писал(а): Вапервых distinct здесь лишний (моя вера в людей таки простирается настолько, чтоб считать что ID - это PK). Вавтарых это по сути то же самое, о чём говорил dimitr.
Вера не подводит :) PARAM_ID в первой таблице действительно PK.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 12 сен 2006, 15:36

2 Merlin:
Distinct я скопировал из поста dimitr'а, изменив условие (выбираемые поля даже не смотрел, потому он и остался).
В каком посте он об этом говорил? Может, вы друг друга без слов понимаете, а я что-то не заметил.

Я этот вопрос пробовал, по моим данным (FB 1.0.3 dialect 1), exists работает быстрее на отсутствующих записях, а join быстрее, когда отсутствующих данных мало. Видимо, какие-то накладные расходы на "присоединение" несуществующих записей.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 12 сен 2006, 15:50

WildSery писал(а):2 Merlin:
Distinct я скопировал из поста dimitr'а, изменив условие (выбираемые поля даже не смотрел, потому он и остался).
В каком посте он об этом говорил? Может, вы друг друга без слов понимаете, а я что-то не заметил.
Я тоже не сразу обратил внимание, что отношение 1:N, там N замаскировано * ;) Соотвественно, если брать джойном, то в резалтсете будут дубликаты там, где во второй таблице несколько деталей. Их придётся снимать дистинктом, сиречь группировкой после получения резалтсета. Вот тут джойн и проиграет.

Ответить