Имя: Пароль:
1C
1С v8
Сделать запрос по докам, отсутствующим в регистре сведений.
0 Target1025
 
28.04.22
04:48
Есть в бухии регистр "Дополнительные сведения", где измерение "Объект" - это ссылка на некий док. Вопрос. Как сделать запрос, который отберет документы за период, на которые _отсутствует_ ссылка в данном регистре сведений?
Заготовка запроса:

        Свойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Возврат документа");
        Запрос = Новый Запрос;
        ЗАпрос.Текст = "ВЫБРАТЬ
        |    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка
        |ИЗ
        |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
        |        Левое СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
        |        ПО АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
        |ГДЕ
        |    АктСверкиВзаиморасчетов.Организация = &Организация
        |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
        |    И ДополнительныеСведения.Свойство = &Свойство";
        Запрос.УстановитьПараметр("Организация",ЭтотОбъект.Организация);
        Запрос.УстановитьПараметр("ДатаНачала",ЭтотОбъект.ДатаНачала);
        Запрос.УстановитьПараметр("ДатаКонца",ЭтотОбъект.ДатаКонца+86400);
        Запрос.УстановитьПараметр("Свойство",Свойство);
1 Индиго
 
28.04.22
05:29
"Выбрать * Из (ВЫБРАТЬ
|    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка,
|    ЕстьNULL(ДополнительныеСведения.Объект,"нет" ) КАК ОБъект
...
)Зап
ГДЕ Зап.Объект="нет"
2 Target1025
 
28.04.22
06:36
(1) спасиб
3 Target1025
 
28.04.22
06:44
(0)(1) Более точный запрос, исключающий двойную выборку:

        ЗАпрос.Текст = "ВЫБРАТЬ
                       |    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка
                       |ИЗ
                       |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
                       |        ПО АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
                       |ГДЕ
                       |    АктСверкиВзаиморасчетов.Организация = &Организация
                       |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
                       |    И ДополнительныеСведения.Значение ЕСТЬ NULL";
4 Мимохожий Однако
 
28.04.22
07:30
Можно в первом пакете собрать документы, которые есть в регистре сведений. А во втором запросе собрать документы, которые не вошли в первый пакет.
5 Target1025
 
28.04.22
14:52
(4) а это и есть то, что предложил (1). Двойной запрос. Вложенным запросом собирает все документы, потом внешним запросом отбирает то, что нужно. Решение, как (3) делает выборку за один проход.
6 1Сергей
 
28.04.22
15:07
(1) Расстрелять
7 Target1025
 
28.04.22
15:13
(4) подумал, это другое, не то, что в (1). Это другой вложенный запрос:
        ЗАпрос.Текст = "ВЫБРАТЬ
                       |    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка,
                       |    ДополнительныеСведения.Значение КАК Значение
                       |ИЗ
                       |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
                       |        ПО АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
                       |ГДЕ
                       |    АктСверкиВзаиморасчетов.Организация = &Организация
                       |    И НЕ АктСверкиВзаиморасчетов.Ссылка В
                       |                (ВЫБРАТЬ
                       |                    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка
                       |                ИЗ
                       |                    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |                        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
                       |                        ПО
                       |                            АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
                       |                ГДЕ
                       |                    АктСверкиВзаиморасчетов.Организация = &Организация
                       |                    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца)
                       |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца";


Замер скорости показал, что вложенный запрос выполняется ровно в два раза медленней, чем однопроходной в (3).
8 ИУБиПовиц
 
28.04.22
15:24
(7) Ну дык ДополнительныеСведения.Объект поди составной? а вы внутреннее пуляете без выражения
9 Target1025
 
28.04.22
15:33
(8) ДополнительныеСведения.Объект есть измерение регистра ДополнительныеСведения, где хранятся ссылки на документы. Не понимаю ваших намеков =)
10 Мимохожий Однако
 
28.04.22
15:39
(9) Используй Выразить
11 Курцвейл
 
28.04.22
15:45
(7) Однопроходные это птицы и рептилии. А млекопитающие это двупроходные.
12 Курцвейл
 
28.04.22
15:47
(7) Вместо вложенного запроса правильнее использовать Временную таблицы + Выразить + Индексировать
13 Target1025
 
28.04.22
15:47
(8)(10) шут его знает, что вы от меня хотите. Переписал вложенный отказавшись от внешнего левого соединия:
        ЗАпрос.Текст = "ВЫБРАТЬ
                       |    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка
                       |ИЗ
                       |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |ГДЕ
                       |    АктСверкиВзаиморасчетов.Организация = &Организация
                       |    И НЕ АктСверкиВзаиморасчетов.Ссылка В
                       |                (ВЫБРАТЬ
                       |                    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка
                       |                ИЗ
                       |                    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |                        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
                       |                        ПО
                       |                            АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
                       |                ГДЕ
                       |                    АктСверкиВзаиморасчетов.Организация = &Организация
                       |                    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца)
                       |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца";

Но все равно ,это на 70% медленней того, что в (3)
14 Курцвейл
 
28.04.22
15:49
(13) Т.к. во вложенном запросе нет приведения типа, то индекс по ссылке не работает.
15 Курцвейл
 
28.04.22
15:53
(13) И НЕ АктСверкиВзаиморасчетов.Ссылка В - это тоже бяка, нужно учиться писать запросы по возможности с соединениями, без вложенных запросов.
16 1Сергей
 
28.04.22
15:56
(13) чем (3) не устроил?
17 Target1025
 
28.04.22
15:58
(14)(15) хрен знает, что вы от меня хотите, попытка переписать запрос так:
        ЗАпрос.Текст = "ВЫБРАТЬ
                       |    АктСверкиВзаиморасчетов.Ссылка КАК Ссылка
                       |ИЗ
                       |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |ГДЕ
                       |    АктСверкиВзаиморасчетов.Организация = &Организация
                       |    И НЕ АктСверкиВзаиморасчетов.Ссылка В
                       |                (ВЫБРАТЬ
                       |                    ВЫРАЗИТЬ(АктСверкиВзаиморасчетов.Ссылка КАК Документ.АктСверкиВзаиморасчетов) КАК Ссылка
                       |                ИЗ
                       |                    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |                        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
                       |                        ПО
                       |                            АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
                       |                ГДЕ
                       |                    ДополнительныеСведения.Объект ССЫЛКА Документ.АктСверкиВзаиморасчетов
                       |                    И АктСверкиВзаиморасчетов.Организация = &Организация
                       |                    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца)
                       |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца";


только замедлила его процентов на 25.
18 Target1025
 
28.04.22
15:59
(16) запрос в (3) меня совершенно устраивает, то, что далее - это моя попытка научитсья писать более быстрые запросы, пусть они и более сложные. Но пока что никакой из вышеуказанных советов не ускоряет дело, только и только замедлет.
19 1Сергей
 
28.04.22
16:02
(18) бросай это гиблое дело. Всё гениальное просто
20 ИУБиПовиц
 
28.04.22
16:34
Попробуйте так. Ну правильно псевдонимы проставте.

Выбрать АктСверки.Ссылка как ссылка
из документ.АктСверки как АктСверки
левое соединение Регистрведений.ДопСведения как допСведения
по ((Выразить(ДОпСведения.Объект как Документ.АктСверки)) = АктСверки.Ссылка
Где
Выразить(ДОпСведения.Объект как Документ.АктСверки) Есть  Null
и АктСверки.Дата между ПериодС и По
21 ИУБиПовиц
 
28.04.22
16:35
(20) еще вроде вместо Есть null на ссылку можно проверять, но эт не точно:)
22 Eiffil123
 
28.04.22
17:14
(20) зачем у вас в условии ПО применяется ВЫРАЗИТЬ? там это не нужно
23 Target1025
 
28.04.22
17:53
(20) Сир! В общем, да, очень круто получилось!

Типа, мое, без "выразить":
        ЗАпрос.Текст = "ВЫБРАТЬ
                       |    АктСверкиВзаиморасчетов.Ссылка КАК ДокументСсылка
                       |ИЗ
                       |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
                       |        ПО АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
                       |ГДЕ
                       |    АктСверкиВзаиморасчетов.Организация = &Организация
                       |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
                       |    И ДополнительныеСведения.Объект ЕСТЬ NULL";


Типа ваше, с "выразить":
        ЗАпрос.Текст = "ВЫБРАТЬ
                       |    АктСверкиВзаиморасчетов.Ссылка КАК ДокументСсылка
                       |ИЗ
                       |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
                       |        ПО (АктСверкиВзаиморасчетов.Ссылка = (ВЫРАЗИТЬ(ДополнительныеСведения.Объект КАК Документ.АктСверкиВзаиморасчетов)))
                       |ГДЕ
                       |    АктСверкиВзаиморасчетов.Организация = &Организация
                       |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
                       |    И ВЫРАЗИТЬ(ДополнительныеСведения.Объект КАК Документ.АктСверкиВзаиморасчетов) ЕСТЬ NULL ";


Результат тестов:
однопроходной 15 мс;
"выразить" 66 321 мс;

У вас крутой алгоритм! Он 4421 раз медленней моего!
24 Мимохожий Однако
 
28.04.22
18:07
Лучшее - враг хорошего ). Переходи на вариант (0)
25 ИУБиПовиц
 
29.04.22
09:15
(23) Чего то как то сильно медленнее получилось:)
Ради интереса запустил у себя (600 доков на выходе из 5000 доков по отборам)
1 запрос 78 мс
2 Запрос 266 мс
3 Запрос 46 мс (тут я убрал выразить из ПО, но оставил в ГДЕ)
Вообще всегда думал что когда в по не указываем выразить по составному типу - он сканирует все таблицы - которые есть в этом типе, почему он так отрабатывает?
26 banco
 
29.04.22
09:52
(25) Выразить надо, когда реквизит составного типа получаем, а то будут левые соединения по всем типам.
27 Said_We
 
29.04.22
11:22
(26) Выразить до соединения имеет смысл. Но в данном случае скорость 1С может дать ту же.

ЛЕВОЕ СОЕДИНЕНИЕ
(Выбрать т.* из РегистрСведений.ДополнительныеСведения как т
ГДЕ
НЕ ВЫРАЗИТЬ(ДополнительныеСведения.Объект КАК Документ.АктСверкиВзаиморасчетов) ЕСТЬ NULL
) КАК ДополнительныеСведения
28 Said_We
 
29.04.22
11:24
(27) Описался чуть...

ЛЕВОЕ СОЕДИНЕНИЕ
(Выбрать т.* из РегистрСведений.ДополнительныеСведения как т

ГДЕ
НЕ ВЫРАЗИТЬ(т.Объект КАК Документ.АктСверкиВзаиморасчетов) ЕСТЬ NULL
) КАК ДополнительныеСведения
29 Target1025
 
29.04.22
23:10
(27)(28)
однопроходной 5 033 мс
"выразить" 155 527 мс

Код, если что так:
        ЗАпрос.Текст = "ВЫБРАТЬ
                       |    АктСверкиВзаиморасчетов.Ссылка КАК ДокументСсылка
                       |ИЗ
                       |    Документ.АктСверкиВзаиморасчетов КАК АктСверкиВзаиморасчетов
                       |        ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
                       |            т.*
                       |        ИЗ
                       |            РегистрСведений.ДополнительныеСведения КАК т
                       |        ГДЕ
                       |            НЕ ВЫРАЗИТЬ(т.Объект КАК Документ.АктСверкиВзаиморасчетов) ЕСТЬ NULL) КАК ДополнительныеСведения
                       |        ПО АктСверкиВзаиморасчетов.Ссылка = ДополнительныеСведения.Объект
                       |ГДЕ
                       |    АктСверкиВзаиморасчетов.Организация = &Организация
                       |    И АктСверкиВзаиморасчетов.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
                       |    И ВЫРАЗИТЬ(ДополнительныеСведения.Объект КАК Документ.АктСверкиВзаиморасчетов) ЕСТЬ NULL";
30 Target1025
 
29.04.22
23:15
(28)(29)удаление выразить после ГДЕ не сильно меняет картину

однопроходной 4 593 мс
"выразить" 157 606 мс
31 ИУБиПовиц
 
30.04.22
23:19
А какая СУБД? в профайлере глянуть планы запросов можете?
32 Target1025
 
01.05.22
04:47
(31) файловая, релиз проги (8.3.18.1779)
33 Said_We
 
04.05.22
10:37
(32) В файловой может быть всё что угодно.
34 Said_We
 
04.05.22
10:39
Вместо "т.*" нарисуй те реквизиты, которые нужны и сразу с выразить.
Оптимист верит, что мы живем в лучшем из миров. Пессимист боится, что так оно и есть.