Имя: Пароль:
1C
1С v8
Запросы в 1с
,
0 abask
 
06.12.22
15:29
есть справочник1
есть документ1
в документе есть реквизит со ссылкой на справочник1

задача вывести все элементы справочник1 которые не используются в документ1

есть запрос:

ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ИЗ
    Документ.Документ1 КАК Документ1
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Справочник1 КАК Справочник1
        ПО (Документ1.Реквизит1 <> Справочник1.Ссылка)


вроде все работает. указываю в одном из документов элемент справочник1 и выводятся все элементы справочник1 кроме указанного

но если не ни одного документа, то не выводится ничего, а должно выводиться все
т.е. при отсутствии документов Соединение как-то неправильно отрабатывает

одним запросом это можно сделать?
1 Ryzeman
 
06.12.22
15:31
ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ИЗ
    Справочник.Справочник1 КАК Справочник1 
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.Документ1 КАК Документ1
        ПО (Документ1.Реквизит1 = Справочник1.Ссылка)
ГДЕ
  Документ1.Ссылка ЕСТЬ NULL
4 Ryzeman
 
06.12.22
15:34
Либо от противного, должно быстрее работать.

ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_ИСключаемые
ИЗ
    Справочник.Справочник1 КАК Справочник1 
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Документ1 КАК Документ1
        ПО (Документ1.Реквизит1 = Справочник1.Ссылка);
////////////////////////

ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ИЗ
    Справочник.Справочник1 КАК Справочник1 
ГДЕ Справочник1.Ссылка НЕ В (ВЫБРАТЬ ВТ_ИСключаемые.Ссылка КАК Ссылка ИЗ ВТ_ИСключаемые КАК ВТ_ИСключаемые)
6 lodger
 
06.12.22
15:48
ВЫБРАТЬ
    Справочник1.Ссылка
ИЗ
    Справочник.Справочник1 КАК Справочник1
ГДЕ
    НЕ Справочник1.Ссылка В
                (ВЫБРАТЬ РАЗЛИЧНЫЕ
                    Документ1.Справочник1
                ИЗ
                    Документ.Документ1КАК Документ1
                ГДЕ
                    НЕ Документ1.ПометкаУдаления
                    И ПоступлениеТоваров.Проведен)
    И НЕ Справочник1.ПометкаУдаления
7 Kassern
 
06.12.22
15:50
(6) Зачем вы ТСу психику портите вложенными запросами?) Еще за правило возьмет так писать, потом сильно удивляться будет в быстродействии.
8 lodger
 
06.12.22
15:58
(7) а наркоманские связи в (0),(1) и (4) это будто нормально?
9 Kassern
 
06.12.22
16:03
(8) ага, нормально. По идее должно работать быстрее. В вашем случае так же создаются связи таблиц, только неявным способом и разные SQL могут по разному план запроса построить.
10 Курцвейл
 
06.12.22
16:24
(8) Признавайся, пил сегодня мухоморовый чай или нет?
11 Курцвейл
 
06.12.22
16:27
(4) Почти верно

ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_ИСключаемые
ИЗ
    Справочник.Справочник1 КАК Справочник1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Документ1 КАК Документ1
        ПО (Документ1.Реквизит1 = Справочник1.Ссылка)
ИНДЕКСИРОВАТЬ ПО Ссылка;
////////////////////////


ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ИЗ
    Справочник.Справочник1 КАК Справочник1
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИСключаемые КАК ВТ_ИСключаемые
        ПО (ВТ_ИСключаемые.Ссылка= Справочник1.Ссылка)
ГДЕ
  ВТ_ИСключаемые.Ссылка ЕСТЬ NULL
12 Kassern
 
06.12.22
16:43
(11) ПОМЕСТИТЬ ВТ_ИСключаемые - не бесплатная операция
13 Ryzeman
 
06.12.22
16:50
(8) Какой ты вредный) Да, нормально, так работают запросы. Если ты хочешь выбрать что то в одной таблице чего нет в другой - тебе в любом случае надо их связывать, ничего наркоманского в этом нет. (4) так вообще ровно то же самое что ты в (6) написал, только с учётом рекомендаций 1с из

https://its.1c.ru/db/metod8dev/content/2499/hdoc

/dooshneela mode off
14 1Сергей
 
06.12.22
17:15
(8) >>а наркоманские связи в (0),(1) и (4) это будто нормально?

стесняюсь спросить. А что в Вашем понимании ненаркоманские связи?
15 Said_We
 
06.12.22
18:15
(0) "но если не ни одного документа, то не выводится ничего, а должно выводиться все "

Неа - не должно. Вы прицепляете к пустому множеству что-то слева. Так как множество пустое, то на выходе будет пустое множество.
Если будет декартово перемножение, то эффект будет тот же, так как умножение любого множества с пустым множеством даёт пустое множество.

Правильный ответ в (6)
Только я не понял зачем там условие "И НЕ Справочник1.ПометкаУдаления". В задаче такого не было. Все так все.

Условие "IN (SELECT)" И "NOT IN (SELECT)" по скорости очень разные. Первое в разы быстрее, так как проверяется на первое вхождение, а во втором случае проверяются все элементы.
16 Курцвейл
 
06.12.22
18:15
(12) Все зависит от размера справочника. Если он большой, то (11) выгоднее. Если маленький то выгодно (1)
17 Курцвейл
 
06.12.22
18:17
(15) вложенные запросы это зло. Надо себя к этому приучать.
18 Said_We
 
06.12.22
18:17
(16) Предположу что (1) будет быстрее, так как не создается временная таблица. Она и не нужна.
19 Курцвейл
 
06.12.22
18:21
я тоже ошибся. правильнее так:

ВЫБРАТЬ
    Документ1.Реквизит1 КАК Ссылка
ПОМЕСТИТЬ ВТ_ИСключаемые
ИЗ
    Документ.Документ1 КАК Документ1
ИНДЕКСИРОВАТЬ ПО Ссылка;
////////////////////////
ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ИЗ
    Справочник.Справочник1 КАК Справочник1
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИСключаемые КАК ВТ_ИСключаемые
        ПО (ВТ_ИСключаемые.Ссылка= Справочник1.Ссылка)
ГДЕ
  ВТ_ИСключаемые.Ссылка ЕСТЬ NULL
20 Said_We
 
06.12.22
18:21
(17) Чем это зло вложенные запросы? Если вложенный запрос к большой физической таблице, то ...

(1) "ЛЕВОЕ СОЕДИНЕНИЕ Документ.Документ1 КАК Документ1" Как раз правильнее переписать на вложенный запрос, что бы JOIN с большой таблицей не делать.
(выбрать различные т.Реквизит1 ИЗ Документ.Документ1 КАК т)
21 Курцвейл
 
06.12.22
18:24
(20) От вложенных запросов может Оптимизатор забалдеть. Или по крайней мере долго думать.
22 Said_We
 
06.12.22
18:24
(19) Ага у тебя 100500 документов с 1000 строк в каждой, а в справочнике всего 1500 элементов. Представь сколько ты запихаешь строк во временную таблицу и потом это ещё джойнить будешь. Не верно.
23 Курцвейл
 
06.12.22
18:26
(22) Значит надо еще агрегировать временную таблицу. Зато я буду всегда с индексом. Сканить всю таблицу документов все равно придется.
А твоим вложенным мы еще будем сканить всю таблицу справочника
24 Said_We
 
06.12.22
18:27
(23) Правильный ответ в (6). Только условие на пометку удаления убрать - в условии задачи её нет.
25 Said_We
 
06.12.22
18:31
Почти правильный в (1) если свернуть предварительно таблицу как в (20) написано. Если так сделать то (1) и (6) дадут по скорости примерно одинаковый результат.
26 vis_tmp
 
06.12.22
18:41
Однозначно, вариант (6).
27 Said_We
 
06.12.22
18:41
(23) "А твоим вложенным мы еще будем сканить всю таблицу справочника" - с какого перепуга. первое что выполняется это FROM. Если во FROM вложенный запрос, то будет выполняться сначала он.

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

Сам по себе подзапрос "select ... from (select...)" достаточно недорого стоит по времени.
28 Курцвейл
 
07.12.22
15:50
(27) Это не так. Почитайте требование к запросу для динамического списка. Если станет понятно почему так рекомендовано не использовать подзапросы, то можно дальше копнуть, чтобы понять что подзапросы это зло. И чем лучше использование временных таблиц.
С другой стороны как ведь все происходит - вот тут подзапрос, там подзапрос и пошло поехало. Тем самым набивается рука на плохих практиках.
29 Said_We
 
07.12.22
15:52
(28) При чем тут динамический список и запрос?
30 Said_We
 
07.12.22
16:01
(29) "Тем самым набивается рука на плохих практиках." - главное определить, что есть плохо и что есть хорошо.
Когда подзапросы применять правильно, а когда нет я выше написал. Бывают ситуации, когда временные таблицы это зло. Так что и их не применять?

Конечным критерием является скорость работы и затрачиваемые ресурсы. В каждой конкретной задаче на каждой конечной базе можно получать совсем разные результаты.
Что оптимальнее тут и сейчас, то и применяют.

Как пример, если в задаче подобной задаче в (0) с 100500 документами по 1000 строк в каждом, то применять внутренние таблицы может оказаться злом.
Представьте что у вас справочник в 20 000 объектов и вам необходимо найти пяток элементов, которые не используются. т.е. во внутреннюю таблицу вам необходимо помещать почти весь справочник. Так зачем это делать, если вы его из физической таблицы и так почти весь достаёте?
31 lodger
 
07.12.22
16:01
(29) без него не получится оправдать наркотрип.
32 Said_We
 
07.12.22
16:23
(31) Не понятно только зачем оправдывать.

Берешь большую базу торговли и какой-нибудь документ или сразу регистр и номенклатуру. Делаешь запрос с временной таблицей и без. Смотришь результат по времени. Удивляешься почему пусть 50% времени уходит на создание временной таблицы. Берешь маленькую базу, или ту же базу, но не с номенклатурой, а с мелким справочником или таблицей, и видишь практически одинаковый результат. Долго думаешь.

Динамический список, СКД.... работают с запросом как с источником данных и делают они это как-то по своему. Там могут быть другие результаты.