Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Альтернатива * / 24 сообщений из 24, страница 1 из 1
06.08.2001, 05:16
    #32011135
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Пример: при выборке задаем условие "WHERE table.code = @code", где @code - переменная. Очень неудобно, когда в значение переменной ничего не входит, т.е. условие не нужно. Неужели нету какого-нибудь "застолбленного" символа или обозначения, который бы помог решить эту проблему? А то IF-ами надоело уже строить логическое дерево до 5-го уровня...
...
Рейтинг: 0 / 0
06.08.2001, 05:18
    #32011136
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Пояснение: например, можно было бы условие задать как "WHERE table.code = * "
...
Рейтинг: 0 / 0
06.08.2001, 05:18
    #32011137
Garya
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
where table.code = @code or @code is Null
...
Рейтинг: 0 / 0
06.08.2001, 05:24
    #32011138
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
to Garya: нет, "or" не поможет, по специфике запроса переменная @code - is not null
...
Рейтинг: 0 / 0
06.08.2001, 06:06
    #32011140
Альтернатива *
Тогда поясни, чем определяется "когда в значение переменной ничего не входит, т.е. условие не нужно"?.

Я в отчетах использую такой прием: перед выводом отчета запрашивается какой-либо параметр раскрывающимся списком, который например, может принимать либо значение конкретного клиента (товара, валюты, etc), либо "ВСЕ", либо группу такого. После выбора пользователем из списка этого параметра, в процедуру возвращается соответственно целочисленное Id клиента, ноль или Id группы с отрицательным значением. А запрос в процедуре будет выглядеть соответственно:

... where @client in (Client.Id, 0, -ClientGroup.Id) ...

если без группы, а просто либо конкретный клиент, либо все, то
... where @client in (Client.Id, 0) ...

Соответственной, большой и сложный отчет с кучей параметров будет выглядеть как
...
where @client in (Client.Id, 0, -ClientGroup.Id)
and @tovar in (Tovar.Id, 0, - TovarCategory)
and @valut in (Valut.Id, 0)
and ...

Взяв себе это за практику, отчеты пишутся быстро и автоматически. На самом деле, это примерно тоже, что предложил Garya "where table.code = @code or @code is Null", только более систематизированный подход.

Меня могут упрекнуть, в том что обилие альтернатив (in раскрывается в or) затрудняет работу оптимизатора и запрос получается не самым эффективным. Согласен с этим. Однако, бухгалтера, финансисты, менеджеры, etc привыкшие получать отчеты из галактики за 20-30 минут, ждут мои отчеты за 1-2 мин и считают это молниеносным. Там же где ожидание такого отчета превращается в проблему, я применяю другой подход: формирую в процедуре запрос динамически и выполняю exec'ом. Например, в условие where попадет "Client.Id=@client" только когда будет выбран конкретный клиент, а когда будет выбран "все клиенты", никакого условия по клиентам добавлено не будет. Запрос получается всегда самым эффективным. Однако, этим методом отчеты пишутся медленно, поэтому я им не злоупотребляю.

Теперь ругайте:
...
Рейтинг: 0 / 0
06.08.2001, 06:22
    #32011143
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
to Глеб Уфимцев: ругать не буду, буду спрашивать. У меня в процедуру, предположим, передается переменная кода товара @code. Она может принимать либо конкретное значение кода товара, либо 0, если товар не выбран (то есть отчет по всем товарам). У меня сейчас стоит IF и проверяет на условие IF @code=0, и в зависимости от этого в запрос добавляется условие или нет. Вопрос в том, можно ли при @code=0 заменять @code на что-нибудь, чтоб запросов было не 2, а 1 - универсальный. Т.е. если провести аналогию с моим примером, условие "WHERE @code=0" интерпретировалось как по всем кодам.
З.Ы. Если ты и написал пример реализации подобного, попробуй тогда объяснить, как ты обходишь этот изъян, если у тебя товар не выбран и в процедуру, как и у меня, передается 0.
...
Рейтинг: 0 / 0
06.08.2001, 06:26
    #32011144
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
в догонку: интересно, а как у тебя условия в запросе добавляются динамически. Ты делаешь строковую переменную и потом кидаешь ее на выполнение?
...
Рейтинг: 0 / 0
06.08.2001, 06:31
    #32011145
Альтернатива *
Это как раз тот самый случай

WHERE @code in (table.code, 0)

При этом, если будет выбран конкретный товар, то условие выборки станет эквивалентно @code=table.code (или table.code=@code), а если будет выбран "все товары", то значение @code станет 0 и критерий будет эквивалентен where @code=0 ("0=0" = true), в выборку попадут все товары.
...
Рейтинг: 0 / 0
06.08.2001, 06:40
    #32011146
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
О, доперло до меня. Слушай, классно придумано, даже ругать нечего! Ты, небось, раз галактику хаишь, тоже 1С под SQL затачивал, тогда будем знакомы,я - Petrovich. Спасибо за ценный совет...
...
Рейтинг: 0 / 0
06.08.2001, 07:37
    #32011150
zamm
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Блин. А особенно классно придумано по поводу выбора группы. Этот минус просто генеален. Снимаю шляпу.
...
Рейтинг: 0 / 0
06.08.2001, 09:26
    #32011157
zamm
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
2:Глеб Уфимцев
Я хочу поразрабатывать тему с группами.
Предложенный метод (с минусом для группы) работает при 2-ух уровневом справочнике товаров: Группа->Товар
А если он будет 3, 4 и т.д. N-уровневый справочник каких то характеристик. Как в таком случае можно организовать дубовую схему условия выборки? А если иерархия справочника не жестко задана количеством уровней, а в виде дерева несбалансированного?
Мне кажется, что можно как то через строковые переменный, т.е. формировать строку из ID с каждого уровня, разделя их запятыми. Но что-то самую малость не сходится.
...
Рейтинг: 0 / 0
06.08.2001, 09:48
    #32011161
Альтернатива *
Лазание по дереву - это отдельная увлекательная задача. К сожалению, малопроизводительная. Поэтому я её избегаю всеми правдами и неправдами.
...
Рейтинг: 0 / 0
06.08.2001, 11:59
    #32011181
SergSuper
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
2 zamm
Для N-уровнего спрввочника еще проще

create table #t( id int, parent int, name varchar(99))

select * from #t
where @tovar in (id, parent)
...
Рейтинг: 0 / 0
06.08.2001, 15:52
    #32011214
zamm
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
2:SergSuper
А вот не проще. Твой примерчик выберет только два соседних уровня. А как выбрать 3 или 4.

Тут уже не раз обсуждался вопрос о деревьях и о выборе целой ветви дерева в том числе. Не будем сейчас ее трогать. А вот класическая организация 3-уровнего справочника - 3 таблицы со связью один-ко-многим.
Как должно выглядеть условие для отбора?
... where @client in (Client.Id, 0, -ClientGroup.Id) ...
в данном случае минус уже не удасться использовать для отделения уровней.
Можно например использовать заведомо большой мношитель, что-то типа
... where @client in (Client.Id, 0, ClientGroup1.Id*10000, ClientGroup2.Id*100) ...
Но множители вещь не надежная. Ведь никогда не знаешь какого размера у тебя будет справочник, особено с какой нибудь номенклатурой.
...
Рейтинг: 0 / 0
09.08.2001, 02:24
    #32011418
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Человеки, объясните, че-то въехать в гениальный минус перед группой не могу. Что дает конструкция "where @client = -ClientGroup.Id"? Ни разу с таким не сталкивался. Минус - это тоже какое-то фикс. значение типа "*"?
...
Рейтинг: 0 / 0
09.08.2001, 05:43
    #32011431
SergSuper
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Всё просто - если число положительное выбирается по коду клиента, если число отрицательное - по коду группы


Client
cln grp name
1 1 Vasya
2 1 Petya
3 2 Masha
4 2 Dusya

create proc SelectClients @cln int As
select * from Client where @cln in (cln,0,-grp)
go

exec SelectClients 2 -- выберется 2-й клиента
exec SelectClients 0 -- выберутся все
exec SelectClients -2 -- выберутся клиенты 3 и 4

Можно было бы настроить так, что номера групп и клиентов не пересекались бы(например задать identity для групп четные, а для и клиентов - нечетные ) и тогда можно передавать параметры и без минусов.
...
Рейтинг: 0 / 0
09.08.2001, 05:52
    #32011432
zamm
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Начинается все с формы, где оператор выбирает условия для фильтра - условно это комбобокс, где перечисленны наименования групп и товаров в этих группах. При формировании комбобокса ID товаров беруться простые числа, а ID групп с минусом что бы отличать товар от группы. Ведь группы и товары хранятся в разных таблицах и ID у них могут быть одинаковыми.
Следующий шаг. Пользователь выбрал что-то и вызывается процедура, которой передается выбранное значение. Далее следует запрос, типа
select *
from Client left join ClientGroup on ClientGroup.ID = Client.GroupID ...
where @client in (Client.Id, 0, -ClientGroup.Id) ...

И запись попадет в выборку, если она относится к группе с ID=5, а не если сам товар имеет ID=5.
...
Рейтинг: 0 / 0
09.08.2001, 09:08
    #32011474
KSergey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Преклоняясь перед идеей использования "-" в in хочется отметить, что OR работают часто медленно. Хотя и не везде, конечно. Лучше (по скорости, но не по синтаксису использовать UNION вроде такого

select *
from Table
where @code=0
union
select *
from Table
where code=@code

Сюда можно наворотить еще много чего.
...
Рейтинг: 0 / 0
09.08.2001, 09:10
    #32011476
KSergey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
В догонку к UNION: здесь же можно и "-" вполне приспособить
...
Рейтинг: 0 / 0
09.08.2001, 16:29
    #32011531
Павел
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Сейчас не на чем собрать пример. Если не трудно, поясните - почему Union быстрее? Просто из спортивного ингтереса .
...
Рейтинг: 0 / 0
10.08.2001, 00:45
    #32011536
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
to SergSuper и zamm: "Всё просто - если число положительное выбирается по коду клиента, если число отрицательное - по коду группы" - дык это мне программно отслеживать надо? Иначе не понимаю, как она найдет то поле, где хранится id группы, к которой относится товар (у меня и товар, и группы находятся в одном справочнике, и соответственно их id находятся в одной колонке)?
...
Рейтинг: 0 / 0
10.08.2001, 04:05
    #32011537
KSergey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
Почему Union быстрее? Ну видимо оптимизатор его лучше обкарнывает. Т.е. например в таком случае последовательные запросы/Union или IF будут работать значительно (в разы) быстрее. Может правда и не буквально в таком - но в подобном. А если еще и условий поднаворотить, тогда уж точно.

-- для ID исп. тип Uniqueidentifier - привычнее мне
-- задаем один из параметров, по которым идет отбор: @ID1 или @ID2 или @ID3, остальные
-- приравниваем NULL

SELECT *
FROM Table
WHERE (@ID1=ID1 AND @ID1 IS NOT NULL) OR (@ID2=ID2 AND @ID2 IS NOT NULL) OR (@ID3=ID3 AND @ID3 IS NOT NULL)
...
Рейтинг: 0 / 0
10.08.2001, 06:50
    #32011560
zamm
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
2:Petrovich
Я так понимаю, что у тебя что то типа 2-ух уровнего дерева
ID Name ParID IsGr
1 Ложки 0 Y
2 Вилки 0 Y
3 Ложка Арт1 1 N
4 Ложка Арт2 1 N
5 Вилка Арт5 2 N
6 Вилка Арт6 2 N

В данном случае тоже можно использовать минус.
Минус ставится у клиента в меню, когда он должен выбрать какой фильтр ему наложить.
некий условный код для формирвания формы пользователя
while not rs.eof
...
if rs.IsGr =Y then ' столо быть это группа
menu.add(rs.name,-rs.id)
else ' а это обычный товар в группе
menu.add(rs.name,rs.id)
end if
rs.movenext
end

А в процедуре которая выдает результирующий набор будет следующий запрос
select * from tovar
where @kodtovara in (0,tovar.id,-tovar.parid)

P/S/
Написал, а сам подумал о том, что в конкретном примере у первых двух записей ParID = 0 и это может както отразится на правильности условия in (0,...), но ведь 0 у нас обозначает "выбрать все", и поэтому,вроде бы, должно все правильно сработать.

P.P.S.
А то что UNION работает быстрее OR я тоже несколько раз убеждался, причем это "быстрее" измеряется в разы, бывали случаи что и на порядок.
...
Рейтинг: 0 / 0
10.08.2001, 08:00
    #32011566
Petrovich
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Альтернатива *
to zamm: спасибо за совет, до конца еще не въехал во всю красоту описанной реализации нужного мне алгоритма, но стараюсь изо всех сил. Добавлю насчет "or" или "in" - у меня выборка с or создавалась за 9 мин., перевел ее на in - 4 секунды! Как объяснить такую разительную разницу, не знаю...
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Альтернатива * / 24 сообщений из 24, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]