Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Помогите упростить запрос  [new]
whitebeast
Member

Откуда:
Сообщений: 165
Приветствую,
есть вот такой запрос:
select RewardID
from @tReward r
where ( 
            ( 
                (       exists (
                            select 1
                            from    @tRewardTravelRegion rtr1
                            join    @tRegions reg1 
                                on  rtr1.RegionIDTo = reg1.RegionID 
                            where   rtr1.RegionIDFrom     != -1 
                                and rtr1.RegionIDTo       != -1
                                and rtr1.RegionExcludeBool = 0
                                and rtr1.RewardID = r.rewardID )
                    and not exists (
                            select 1
                            from    @tRewardTravelRegion rtr2
                            join    @tRegions reg2 
                                on  rtr2.RegionIDTo = reg2.RegionID 
                            where   rtr2.RegionIDFrom     != -1 
                                and rtr2.RegionIDTo       != -1
                                and rtr2.RegionExcludeBool = 1
                                and rtr2.RewardID = r.rewardID ) 
                 ) 
             or (       not exists (
                                select 1
                                from    @tRewardTravelRegion rtr3
                                join    @tRegions reg3 
                                    on  rtr3.RegionIDTo = reg3.RegionID 
                                where   rtr3.RegionIDFrom     != -1 
                                    and rtr3.RegionIDTo       != -1
                                    and rtr3.RewardID = r.RewardID )  
                    and not exists (
                                select 1
                                from    @tRewardTravelRegion rtr4
                                join    @tRegions reg4 
                                    on  rtr4.RegionIDTo <> reg4.RegionID 
                                where   rtr4.RegionExcludeBool = 0
                                    and rtr4.RewardID = r.RewardID ) 
                 ) 
             ) 
           ) 

Можно ли как то его сократить? К сожалению ничего лучшего я не придумал... Надеюсь на Вашу помощь.
Нужно чтобы вернулись ID 30206, 30207 и 30209

Некоторые пояснения:
Excluded = 1 - исключены
Excluded = 0 - не исключены
30206 - его нет в @tRegions - валидный
30207 - все записи этого ID помечены как Excluded, но их нет в @tRegions - валидный,
30208 - две записи совпадают с @tRegions, но помечены как Excluded - не валидный ,
30209 - две записи совпадают с @tRegions, но НЕ помечены как Excluded - валидный ,
30210 - все записи этого ID НЕ помечены как Excluded, и их нет в @tRegions - не валидный,
30211 - т.к. есть одна запись помеченная как Excluded, совпадающая с @tRegions - не валидный, несмотря на присутствие записей помеченных Excluded=0 и совпадений с @tRegions

Ниже есть код создания нужных данных и таблиц
+
declare @tRewardTravelRegion table (RewardID int, RegionIDTo int, RegionExcludeBool bit, RegionIDFrom int)
insert into @tRewardTravelRegion
select       30207,	101,	1, 0
union select 30207,	102,	1, 0
union select 30208,	100,	1, 0
union select 30208,	101,	1, 0
union select 30208,	200,	1, 0
union select 30209,	123,	0, 0
union select 30209,	200,	0, 0
union select 30209,	300,	0, 0
union select 30210,	123,	0, 0
union select 30210,	234,	0, 0
union select 30210,	345,	0, 0
union select 30211,	123,	1, 0
union select 30211,	200,	1, 0
union select 30211,	300,	0, 0
union select 30211,	345,	0, 0

declare @tReward table (RewardID int)
insert into @tReward
select       30206
union select 30207
union select 30208
union select 30209
union select 30210
union select 30211

declare @tRegions table (RegionID int)
insert into @tRegions
select 100
union select 200
union select 300

 


З.Ы. MS SQL 2005 (скоро переходим на 2008, но пока такой)
З.Ы.Ы. Более ясно пока объяснить не могу. Буду рад любому совету
13 сен 11, 17:33    [11271219]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
aleks2
Guest
exists (
                            select 1
                            from    @tRewardTravelRegion rtr1
                            join    @tRegions reg1 
                                on  rtr1.RegionIDTo = reg1.RegionID 
                            where   rtr1.RegionIDFrom     != -1 
                                and rtr1.RegionIDTo       != -1
                                and rtr1.RegionExcludeBool = 0
                                and rtr1.RewardID = r.rewardID )

1. != -1 заменить > -1
2. join @tRegions reg1 on rtr1.RegionIDTo = reg1.RegionID
Может не нада?
3. or ( заменить UNION [ALL]
13 сен 11, 19:54    [11271950]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
whitebeast
Member

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

1. Это особо на скорость не повлияет :)
2. Почему же? Чем можно заменить?
3. Если можно подробней

Спасибо
13 сен 11, 21:22    [11272270]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
AHDP
Member

Откуда:
Сообщений: 1226
Select distinct Rew.RewardID
from @tRewardTravelRegion RTR
Right Join @tReward Rew on Rew.RewardID = RTR.RewardID
Where RTR.RewardID is Null
Union all
Select RTR.RewardID
from @tRewardTravelRegion RTR
Left Join @tRegions Reg on Reg.RegionID = RTR.RegionIDTo
Group By RTR.RewardID Having (Sum(1) = Sum(Cast(RTR.RegionExcludeBool As Int)) And Sum(isNull(Reg.RegionID, 0)) = 0)
Union all
Select RTR.RewardID
from @tRewardTravelRegion RTR
Left Join @tRegions Reg on Reg.RegionID = RTR.RegionIDTo
Where Reg.RegionID is not Null
Group By RTR.RewardID Having Sum(Cast(RTR.RegionExcludeBool As Int)) = 0
Под вашу постановку

Select distinct Rew.RewardID
from @tRewardTravelRegion RTR
Right Join @tReward Rew on Rew.RewardID = RTR.RewardID
Where RTR.RewardID is Null
Union all
Select RewardID
From
(
Select RTR.RewardID RewardID,Case When (RTR.RegionExcludeBool = 1 And Reg.RegionID Is Null) Then 1 Else 0 End Case1, Case When (RTR.RegionExcludeBool = 0 And Reg.RegionID Is Not Null) Then 1 Else 0 End Case2, Case When (RTR.RegionExcludeBool = 1 And Reg.RegionID Is Not Null) Then 1 Else 0 End Case3
from @tRewardTravelRegion RTR
Left Join @tRegions Reg on Reg.RegionID = RTR.RegionIDTo
) t
Group By RewardID Having Sum(1) = Sum(Case1) Or (Sum(Case2) > 0 And Sum(Case3) = 0)

Второй должен быть шустрее.

По Вашему запросу:
1) Не понятно зачем используется RegionIDFrom, т.к. противоречит постановке по 30209;
2) Не понятно зачем используется условие RegionIDTo != -1;
3) Вам лучше отказаться от where перенеся все условия в on.
14 сен 11, 04:19    [11272964]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
AHDP
Member

Откуда:
Сообщений: 1226
Упс.

"Под Вашу постаноку" в начало топика.
14 сен 11, 04:21    [11272966]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
aleks2
Guest
select r.RewardID
from 
@tReward r 
inner join
(select T.*
	from
	(select * FROM @tRewardTravelRegion WHERE RegionIDFrom>-1 and RegionIDTo>-1 and RegionExcludeBool=0) T
        LEFT OUTER JOIN
        (select * FROM @tRewardTravelRegion WHERE RegionIDFrom>-1 and RegionIDTo>-1 and RegionExcludeBool=1) TT
        ON T.RegionIDTo=TT.RegionIDTo AND T.RewardID=TT.RewardID
        WHERE TT.RegionIDTo IS NULL
) rtr1
ON rtr1.RewardID = r.rewardID
inner join    
@tRegions reg1 
on  rtr1.RegionIDTo = reg1.RegionID 
-- опосля  "or (       not exists (" сами уж напишите по образу и подобию...
14 сен 11, 07:38    [11273043]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
AHDP,

UNION ALL не всегда эквивалентен OR (конкретно разбираться надо)
UNION всегда эквивалентен. Но тяжелее, чем UNION ALL, в плане выполнения.

Ну, просто, OR ведь не приводит к появлению дубликатов, если относится к одной и той же записи.
А UNION ALL - может, если одна и та же строка появится в результате разных SELECTов.
14 сен 11, 09:31    [11273318]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
iap
UNION всегда эквивалентен.
Тоже не факт, ибо убирает дубликаты, которые могут появиться с OR
в результате специфмки связывания таблиц в запросе.
В любом случае смотреть надо.
14 сен 11, 09:36    [11273351]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
AHDP
Member

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

А я это где-то утверждал!? ;)

Написал же ведь, что это не переписанные запросы автора, а две реализации ДРУГОГО подхода к решению.
14 сен 11, 10:38    [11273645]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
whitebeast
Member

Откуда:
Сообщений: 165
AHDP, спасибо! Буду разбираться!

aleks2, ваш вариант запроса немного не верен, но спасибо за пинок :) Буду смотреть как это можно использовать.

Вчера еще посоветовали третий вариант:
select r.RewardID--,cnt,RegionExcludeBool
from Reward r
join (
    select RewardID,RegionExcludeBool,
    (case   
            when (RegionExcludeBool = 0 and RegionID is not null) then 0
            when (RegionExcludeBool = 1 and RegionID is null) then 0
            else 1 
     end) cnt    
    from @tRewardTravelRegion rtr
    left join @tRegions reg on reg.RegionID = rtr.RegionIDTo
    group by RewardID,RegionExcludeBool,
     
    (case   
            when (RegionExcludeBool = 0 and RegionID is not null) then 0
            when (RegionExcludeBool = 1 and RegionID is null) then 0
            else 1 
     end) 
    ) t on t.RewardID = r.RewardID
group by r.RewardId, cnt 
having max(cnt) = 0 or (min(cnt)=0 and min(convert(int,RegionExcludeBool))=0)
Но он мягко говоря "недопилен" :)

Спасибо еще раз!
14 сен 11, 11:49    [11274219]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
whitebeast
Member

Откуда:
Сообщений: 165
AHDP
По Вашему запросу:
1) Не понятно зачем используется RegionIDFrom, т.к. противоречит постановке по 30209;
2) Не понятно зачем используется условие RegionIDTo != -1;
3) Вам лучше отказаться от where перенеся все условия в on.

1. Чем противоречит? RegionIDFrom не особо влияет на результат, т.к. во всех полях он имеет значение 0
2. Есть такое гадкое слово "спека", т.н. Техническое Задание, в нем есть это условие
3. Спасибо, учту.
14 сен 11, 11:53    [11274252]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
whitebeast
Member

Откуда:
Сообщений: 165
Приглядевшись повнимательней к запросу AHDP я нашел много совпадений с предоженным мне третьим вариантом :)
Думаю проблема решится через несколько минут.

Спасибо!
14 сен 11, 12:54    [11274816]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
AHDP
Member

Откуда:
Сообщений: 1226
В тестовом наборе да, а в реальности? Такие вещи надо официально возвращать с требованием обоснования лишней нагрузки на сервер.
ХМ. Запросы совсем не похожи (не считая обработки приведённых значений), посмотрите планы. Ваш третий вариант потеряет первое валидное условие.
14 сен 11, 14:26    [11275626]     Ответить | Цитировать Сообщить модератору
 Re: Помогите упростить запрос  [new]
whitebeast
Member

Откуда:
Сообщений: 165
AHDP, я бы с радостью не делал таких процедур, но к сожалению надо...
Насчет третьего варианта, я имел ввиду похожесть в общих чертах. И тот запрос был еще не доделан.

Сейчас появилась другая проблема. Приведенный запрос - всего лишь малая часть процедуры. Сейчас пытаюсь все это склеить
14 сен 11, 16:23    [11276793]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить