Форум на Kuban.ru (http://forums.kuban.ru/)
-   Территория 1С (http://forums.kuban.ru/f1040/)
-   -   1cpp NOT IN (SELECT (http://forums.kuban.ru/f1040/1cpp_not_select-3300712.html)

vovan519 13.11.2012 15:23

1cpp NOT IN (SELECT
 
Как наложить условие "кроме выбранной группы"

Если КромеНоменклатура = 0 Тогда
Если ВыбНоменклатура.ЭтоГруппа() = 1 Тогда
Рез = Рез + " AND $ДокС.Номенклатура IN (SELECT Val FROM #ВыбНоменклатура)";
RS.УложитьСписокОбъектов(ВыбНоменклатура, "#ВыбНоменклатура", "Номенклатура");
Иначе
Рез = Рез + " AND $ДокС.Номенклатура = :ВыбНоменклатура";
RS.УстановитьТекстовыйПараметр("ВыбНоменклатура",ВыбНоменклатура);
КонецЕсли
Иначе
Если ВыбНоменклатура.ЭтоГруппа() = 1 Тогда
Рез = Рез + " AND ($ДокС.Номенклатура NOT IN (SELECT Val FROM #ВыбНоменклатура))";
RS.УложитьСписокОбъектов(ВыбНоменклатура, "#ВыбНоменклатура", "Номенклатура");
Иначе
Рез = Рез + " AND ($ДокС.Номенклатура <> :ВыбНоменклатура)";
RS.УстановитьТекстовыйПараметр("ВыбНоменклатура",ВыбНоменклатура);
КонецЕсли;
КонецЕсли;

соответственно "IN (SELECT" работает как положенно, а при "NOT IN (SELECT" результат пустая таблица.

Buzz 13.11.2012 16:43

Закинь элементы из ВыбНоменклатура в список значений и по нему условие делать.

USSR 14.11.2012 04:45

По моему в Рез = Рез + " AND ($ДокС.Номенклатура <> :ВыбНоменклатура" надо писать #ВыбНоменклатура, а не с двоеточиес

Sasha 14.11.2012 06:58

NOT($ДокС.Номенклатура IN (SELECT Val FROM #ВыбНоменклатура))

vovan519 14.11.2012 07:38

1 В списке значений не работает
2 :ВыбНоменклатура правильно. = :ВыбНоменклатура - работает, <> :ВыбНоменклатура - выдает пустой результат.
3 NOT($ДокС.Номенклатура IN (SELECT Val FROM #ВыбНоменклатура)) выдает пустой результат.

sql 2008
сам запрос
|SELECT Итоги.Статус as [Статус],
| Итоги.ДатаДок as ДатаДок,
| Итоги.Док as [Док $Документ]
| ,Итоги.ДатаДок3 as [ДатаДок3],
| Итоги.Док_вид as Док_вид,
| Итоги.ДокОснование as [ДокОснование $Документы]
|FROM (
|SELECT CASE WHEN Жур.IsMark = 1 THEN 7 ELSE CASE WHEN Жур.Closed & 1 = 1 THEN 2 ELSE 1 END END as Статус,
| Жур.Date_Time_IDDoc as Дата,
| CAST(LEFT(Жур.Date_Time_IDDoc, 8) as DateTime) as ДатаДок,
| Жур.IDDoc as Док,
| Жур.IDDocDef as Док_вид
| ,$ДокС.Номенклатура as Номенклатура,
| $Док.ДокОснование as ДокОснование,
| (SELECT CAST(LEFT(Жур2.Date_Time_IDDoc, 8) as DateTime) as ДатаДок2
| FROM _1SJourn as Жур2
| WHERE Жур2.IDDoc = RIGHT($Док.ДокОснование,9)) as ДатаДок3
|FROM $Документ.ВозвратОтПокупателя as Док (NOLOCK)
|INNER JOIN _1SJourn as Жур (NOLOCK) ON Жур.IDDoc = Док.IDDoc
|INNER JOIN $ДокументСтроки.ВозвратОтПокупателя as ДокС (NOLOCK) ON ДокС.IDDoc = Док.IDDoc
|WHERE Жур.Date_Time_IDDoc BETWEEN :ДатаНачала AND :ДатаКонца~ "+УсловиеЗапросаИ(RS)+УсловиеСтатусаДокумента()+"
|) as Итоги
|WHERE Итоги.ДатаДок - Итоги.ДатаДок3 > "+КолвоДней+"
|ORDER BY Итоги.Дата

Может я что не доглядел?

Гена 14.11.2012 08:05

я не программист, но по моей логике операторы In и NotIn работают по булевой алгебре "Правда" <-> "Ложь"...

если Value [b]пустое[/b] или NULL(?), то рассматриваемые операторы могут не сработать...

я почему так думаю?
чудес не бывает... когда работает f и не работает обратная f^(-1), то [b]пустышка[/b] находится вне рассматриваемого интервала... в данном случае - вне выбранной группы...

если я не прав, то пусть старшие товарищи меня поправят (с) Топтыгин из к/ф "Ещё раз про любовь"

vovan519 14.11.2012 08:21

Гена, вполне логично, тем более что это подтверждает практика. Просто не нашел правильного примера.
Конечно можно запихнуть "все кроме" в список, но что-то пихать под миллион значений туда не хочется.
Тем более для обычных запросов Условие (НЕ(ПеремЗапроса в ИмяЭлемента)) работае так же бысто (точнее так же медленно). Не подскажет форум с гуглом, придется идти к админу вылавливать во что преобразуется "Условие (НЕ(ПеремЗапроса в ИмяЭлемента))"

Гена 14.11.2012 08:28

для правильного примера достаточно запустить свой отчёт в другой короткой базе, например, в демо...

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

Ёпрст 14.11.2012 09:26

(0)Покажи, что возвращает Запрос.Отладка(1)

и что в список пихаешь
ЗЫ: ВыбНоменклатура.Выбран() = ?

который не честный 14.11.2012 10:04

В 1С++ не силён, но что делает
SELECT Val FROM #ВыбНоменклатура?
По идее, надо селектить элементы, у которых родитель не равен выбранной группе, но это верно для 1 уровня, т.е. в группе нет вложенной группы, иначе придётся искать все вложенные группы..

Ёпрст 14.11.2012 10:35

(9) в #ВыбНоменклатура будут все элементы, принадлежащие выбранной группе на всех уровнях.. только и всего.


[url]http://www.1cpp.ru/docum/icpp/html/ODBC.html#putobjectlist[/url]

который не честный 14.11.2012 10:41

10 понятно.

vovan519 14.11.2012 10:53

Прошу прощения. Ступил. Давно не смотрел, что выводит Запрос.Отладка(1).
Просто в условия попадали два взаимоисключающих события. Спасибо Ёпрст. Все работает. Иду стреляться. Потратил 5 часов из-за своей невнимательности.
Еще раз прошу прощения.

USSR 14.11.2012 15:30

все не осилил, но обычно пишу :
1 - IN ()
2 - NOT IN ()
Без всяких не равно. Равно или не равно писать нельзя, надо писать IN - принадлежность к выборке

vovan519 14.11.2012 21:44

13 USSR
Если фильтр по одному элементу, то тоже IN
Можно обосновать или дать ссылку?

Billi 15.11.2012 08:11

14-vovan519 >без разницы: "=" или "IN".
Всё равно оптимизатор перведет IN в =.
Правда оптимизатор потратит на это ресурсы, но очень не значительные. :)

vovan519 15.11.2012 09:44

15 Заинтересовало.
Провел эксперемент. время - разница из _GetPerformanceCounter()
Фильтр - один элемент справочника
Режим 0 - "=" и УстановитьТекстовыйПараметр
Режим 1 - IN и УложитьСписокОбъектов
В базе активно работаю, поэтому и разброс показателей, разные режимы запускались по очереди "0,1,0,1", поэтому погрешность разного рода кэштрования не велика. Вот результат.
Режим 0 1068
Режим 1 1241
Режим 0 865
Режим 1 1232
Режим 0 858
Режим 1 1361
Режим 0 1244
Режим 1 1542
Режим 0 1147
Режим 1 5059
Режим 0 1596
Режим 1 1351
Режим 0 869
Режим 1 1496
Режим 0 2091
Режим 1 1327
Режим 0 840
Режим 1 1480
Режим 0 1128
Режим 1 1377
Режим 0 833
Режим 1 1360
Режим 0 860
Режим 1 1397
Конечно 0,8 сек или 1,3 сек разницы нет, но все же.

Billi 15.11.2012 14:32

16-vovan519 >Некорректное сравнение.
Ты сравнивал не IN и = ,
а УстановитьТекстовыйПараметр и УложитьСписокОбъектов.
УстановитьТекстовыйПараметр просто подставляет патаметр в текст запроса, если грубо, то время тратится только на приведение параметра к типу строка и замене в тексте запроса самого параметра на его строковое представление.
УложитьСписокОбъектов - формирует таблицу на сервере и заполняет её переданными данными, а затем сервер, при выполнении запроса произодит join с этой таблицей. Естественно эта операция стоит гораздо дороже.

Я думаю, USSR имел ввиду несколько другое.
Либо val IN (:Параметр), и, в этом случае, значение параметра передается с помощью УстановитьТекстовыйПараметр. В такой ситуации это равноценно val = :Параметр (сервер просто заменит IN на =).
Либо, если список возможных значений не очень большой, то вместо УложитьСписокОбъектов гораздо эффективней использовать конструкцию
val IN (:Параметр1, :Параметр2, ... , :ПараметрN).

Billi 15.11.2012 14:38

Но и в этом случае надо смотреть по ситуации на конкретных данных.
Короче, открываешь студию и эксперементируешь с разными вариантами на реальных данных с анализом плана выполнения запроса.


Текущее время: 09:32. Часовой пояс GMT +3.