Страница 1 из 1
Запрос с проверкой существования
Добавлено: 11 сен 2006, 21:55
nicolas
Здравствуй, 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
Можно ли написать запрос (без использования ХП), для получения такой выборки:
где FLAG = 1 если во второй таблице есть записи, соотв. PARAM_ID
FLAG = 0 если во второй таблице нет записей соотв. PARAM_ID
Добавлено: 11 сен 2006, 22:14
Merlin
RTFM Left Join
Добавлено: 11 сен 2006, 22:16
dimitr
можно. Тебе чтобы проще понять было или чтобы быстрее работало?

Добавлено: 11 сен 2006, 22:17
dimitr
Merlin писал(а):RTFM Left Join
маловато будет. Ыщщо либо DISTINCT либо GROUP BY, однако.
Добавлено: 11 сен 2006, 22:20
Merlin
dimitr писал(а):можно. Тебе чтобы проще понять было или чтобы быстрее работало?

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

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

Добавлено: 11 сен 2006, 22:44
nicolas
Интересно будет и быстрее и понятнее
Написал так:
Код: Выделить всё
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
Добавлено: 11 сен 2006, 22:49
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
а насчет понятнее сложно сказать - тут вроде везде потребуются производные от CASE...
Добавлено: 11 сен 2006, 22:54
dimitr
вариация на тему 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
Добавлено: 11 сен 2006, 22:59
nicolas
И первый и второй вариант понятны и вполне устраивают по скорости...
Огромное спасибо.
ЗЫ. И надо бы почитать побольше про CASE, к своему стыду не подозревал о такой возможности использования в запросах

Добавлено: 11 сен 2006, 23:03
Merlin
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...
Обычно неофиты сразу бросаются жонглировать подзапросами, они им ближе и родней

Может я поэтому и свернул сразу рефлекторно его на джойн, чтоб учился мыслить ширше

Добавлено: 12 сен 2006, 12:12
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
Хотя join, конечно же, будет быстрее.
Добавлено: 12 сен 2006, 13:57
Merlin
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 зависит от распределения данных.
Добавлено: 12 сен 2006, 15:12
nicolas
Merlin писал(а):
Вапервых distinct здесь лишний (моя вера в людей таки простирается настолько, чтоб считать что ID - это PK). Вавтарых это по сути то же самое, о чём говорил dimitr.
Вера не подводит

PARAM_ID в первой таблице действительно PK.
Добавлено: 12 сен 2006, 15:36
WildSery
2 Merlin:
Distinct я скопировал из поста dimitr'а, изменив условие (выбираемые поля даже не смотрел, потому он и остался).
В каком посте он об этом говорил? Может, вы друг друга без слов понимаете, а я что-то не заметил.
Я этот вопрос пробовал, по моим данным (FB 1.0.3 dialect 1), exists работает быстрее на отсутствующих записях, а join быстрее, когда отсутствующих данных мало. Видимо, какие-то накладные расходы на "присоединение" несуществующих записей.
Добавлено: 12 сен 2006, 15:50
Merlin
WildSery писал(а):2 Merlin:
Distinct я скопировал из поста dimitr'а, изменив условие (выбираемые поля даже не смотрел, потому он и остался).
В каком посте он об этом говорил? Может, вы друг друга без слов понимаете, а я что-то не заметил.
Я тоже не сразу обратил внимание, что отношение 1:N, там N замаскировано *

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