[1] [2] |
Ошибка в запросе. Это так и должно быть?! 8.2.15 Имеем запрос: |ВЫБРАТЬ | ЗаказОконныйГотовыеИзделия.НомерСтроки, | ЗаказОконныйГотовыеИзделия.Конструкция, | ЗаказОконныйГотовыеИзделия.Номенклатура, | ЗаказОконныйГотовыеИзделия.Номенклатура.ПлощадьИзделия КАК Площадь, | ЗаказОконныйГотовыеИзделия.Количество, | ЗаказОконныйГотовыеИзделия.Сумма |ПОМЕСТИТЬ ИзделияВКонструкции |ИЗ | Документ.ЗаказОконный.ГотовыеИзделия КАК ЗаказОконныйГотовыеИзделия |ГДЕ | ЗаказОконныйГотовыеИзделия.Ссылка = &Заказ | И ЗаказОконныйГотовыеИзделия.Конструкция <> ЗНАЧЕНИЕ(Справочник.Конструкции.ПустаяСсылка) | И НЕ ЗаказОконныйГотовыеИзделия.Конструкция В | (ВЫБРАТЬ | ИзделияВКонструкции.Конструкция | ИЗ | ИзделияВКонструкции) Ругается "Таблица не найдена "ИзделияВКонструкции" Это у меня ошибка, или это "почти скулевский язык запросов" такое не понимает?! |
Ну ты и завернул... *ошарашено* "Классический" скуль (т.е. стандарт для всех реализаций: MS, IBM, PG...) такое точно кушает? |
2-VZ >Насчёт "классического" ничего не скажу, но все, с которыми я работал, очень даже неплохо справляются с этим. Что тут необычного, сверяться в insertе с данными из таблицы, в которую этот insert делается? Очень даже распрастранённый способ. |
Вот рабочий запрос из MS-SQL |if exists(select * from tempdb..sysobjects where id = object_id('tempdb..#Группы')) | drop table #Группы | create table #Группы (val char(9), primary key clustered (val)) |set nocount on |declare @Контр table(val char(9), isfolder tinyint, primary key clustered (val)) |insert @Контр values (:ВыбГруппа, 1) |while 1=1 |begin | insert into #Группы | select val | from @Контр | where isfolder = 1 and val not in ( select val from #Группы ) | if @@rowcount = 0 break | insert into @Контр | select id,isfolder | from sc133 (nolock) | where parentid in (select val from #Группы ) | and id not in ( select val from @Контр ) | and isfolder=1 | delete @Контр | where val in (select val from #Группы) |end |set nocount off |
Не, я конечно решил проблему из (0), это ни вопрос. Просто я не думал, что в этом может возникнуть проблема :) |
зациклено, выбрать из того, во что поместить. Пакетный запрос сделай |
6-Jimbo >Ну попробуй, сделай через пакет :) Я же сказал, что вопрос ни в том как это сделать, а в том, почему нельзя читать данные из временной таблицы во время записи в неё? |
потому что гладиолус. 1с только выбирать может, инсертить никак |
8-Jimbo >Я знал что многое запущено. Но ни думал, что настолько :) |
и как-то нехорошо: вначале идентификатор ИзделияВКонструкции объявляешь в ПОМЕСТИТЬ, а потом этот же идентификатор как динамический массив (в (Выбрать из...) |
пакет : 1-я выборка 2-я выборка то, что не входит в первую |
Да ещё, одно. Почему нельзя дописать данные в существующую временную таблицу? Мне это тоже не понятно. Или я ошибаюсь? |
рекомендую про запросы посмотреть видео от Павла Чистова. Как минимум 3 лекции |
+10 Но это потому так думаю, что такие кульбиты не исполнял ;( |
5-Billi > А как все-таки "правильно"? Для 1С, естественно :) |
10-VZ >И чего же в этом нехорошего? Посмотри пример из (4) | insert into #Группы | select val | from @Контр | where isfolder = 1 and val not in ( select val from #Группы ) Всё замечателно работает. |
15-VZ >Я сделал вот так: "ВЫБРАТЬ | Подзапрос.НомерСтроки, | Подзапрос.Конструкция, | ЗаказОконныйГотовыеИзделия.Номенклатура, | ЗаказОконныйГотовыеИзделия.Номенклатура.ПлощадьИзделия КАК Площадь, | ЗаказОконныйГотовыеИзделия.Количество, | ЗаказОконныйГотовыеИзделия.Сумма |ПОМЕСТИТЬ ИзделияВКонструкции |ИЗ | (ВЫБРАТЬ | ЗаказОконныйГотовыеИзделия.Конструкция КАК Конструкция, | МИНИМУМ(ЗаказОконныйГотовыеИзделия.НомерСтроки) КАК НомерСтроки | ИЗ | Документ.ЗаказОконный.ГотовыеИзделия КАК ЗаказОконныйГотовыеИзделия | ГДЕ | ЗаказОконныйГотовыеИзделия.Ссылка = &Заказ | И ЗаказОконныйГотовыеИзделия.Конструкция <> ЗНАЧЕНИЕ(Справочник.Конструкции.ПустаяСсылка) | | СГРУППИРОВАТЬ ПО | ЗаказОконныйГотовыеИзделия.Конструкция) КАК Подзапрос | ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказОконный.ГотовыеИзделия КАК ЗаказОконныйГотовыеИзделия | ПО (ЗаказОконныйГотовыеИзделия.Ссылка = &Заказ) | И (ЗаказОконныйГотовыеИзделия.НомерСтроки = Подзапрос.НомерСтроки) |
(16) - кто тебе сказал что 1с = полноценный SQL? в 1с очень упрощенный язык, читаем ЖКК. |
15-VZ >Но ты сам видишь, что элегантности в (17) маловато. Хотя можно было бы от соединения отказаться, всё в подзапросе сделать. |
18-Jimbo >я же написал "почти скулевский язык запросов" :) |
17-Billi > Спасибо. Да, исходное очень элегантно. Жаль, что не работает. |
21-VZ >Я примерно догадываюсь, почему не работает. 1с вообще не любит поручать работу скл-серверу. Наровит всё сама сделать. Поэтому функционал временных таблиц очень ограничен. Я думаю, что они его создали, только для того, чтобы ТЗ в запросах могли учавствовать. Ну и ещё чего-нибудь, по мелочи. Я полагаю, что мою ситуацию надо было решать так: вытащить тч документа в саму 1с (запросом или напрямую из объекта), обработать её в 1с-ке, и затем результат отправить запросом во временную таблицу. |
Приведенное сравнение, мягко говоря, некорректно. Конструкция из (4) не выполняет динамический анализ вставляемых данных. Именно поэтому ты используешь цикл. Ничего не мешает выполнять ровно такой же цикл в конструкциях временных таблиц 1С. (12) Потому что 1С вообще ничего не инсертит на уровне запросов. Все обработки по пополнению агрегатов выполняются на уровне сервера 1С, а не на уровне SQL сервера. Следовательно, ничего не инсертнешь и во временную таблицу. Кроме того, в приведенном тобой примере, инсертить - крайне низко производительно. Гораздо производительнее таблицу #Группы дропать каждый раз и генерировать заново. И тебя же там кластерный индекс, по которому системе приходится каждый раз перестравивать табличку. ЗЫ: За запрос в (4) вообще убивать хочется. |
(17) За этот запрос тоже по крайней мере побил бы. Накой тебе тут ЛЕВОЕ СОЕДИНЕНИЕ??? Оно ж тормознутее внутреннего, а смысла тут в нем никакого! Сделай через внутреннее, посмотри план выполнения на SQL и изумись четкости и однозначности прекрасной связки 1С + MS SQL. Она отработает просто идеально. (21) Исходное - полный бред и в рамках кучу ни имеет ничего общего с кокретной задачей из (17). (22) Опять непонимае механизмов взаимодействия трезвенки. Это твое предложение потягать таблицу туда-сюда-обратно выльется в большой объем трафика БД-сервер 1С - а может даже и на толстого клиента. Механизм временных таблиц позволяет радикально снизить объем передачи данных между серверами и клиентов, локализовав обработку бизнес-логики извлечения данных на уровне SQL. По причине необходимости содержания такого огромного и тяжелого встроенного языка в модулях проведения и обработчиках ПриЗаписи, 1С не дает нам ничего изменять в таблицах. Соответственно под этот каток попали и временные таблицы. Хотя в этом смысла, действительно, нет никакого. А так большего функционала с tt в SQL и нет, если смотреть на возможности работы 1С с таблицами SQL прикладных объектов. |
23-Lexusss >Ты хочешь сказать, что кусок кода в (16) не выполняет динамический анализ вставляемых данных? Посмотри ещё раз внимательно и подумай хорошенько. :) [quote=Lexusss;23567121]Потому что 1С вообще ничего не инсертит на уровне запросов. Все обработки по пополнению агрегатов выполняются на уровне сервера 1С, а не на уровне SQL сервера. Следовательно, ничего не инсертнешь и во временную таблицу. [/quote] Про агрегаты речи не было. Речь шла о временных таблицах, а туда инсерт идет на уровне скл. А твою реплипку насчет убийств за (4) я вообще без коммента оставлю :)))) |
В догонку еще один гвоздь в крышку - группы контрагентов в 95% случаев это большое зло. Нужно очень осторожно подходить к их созданию либо же использовать нестандартные механизмы работы со списками справочников. |
[quote=Lexusss;23567298](17) За этот запрос тоже по крайней мере побил бы. Накой тебе тут ЛЕВОЕ СОЕДИНЕНИЕ??? Оно ж тормознутее внутреннего, а смысла тут в нем никакого! Сделай через внутреннее, посмотри план выполнения на SQL и изумись четкости и однозначности прекрасной связки 1С + MS SQL. Она отработает просто идеально.[/quote] Ты ветку читай внимательно, прежде чем отвечать. :) [quote=Lexusss;23567298](21) Исходное - полный бред и в рамках кучу ни имеет ничего общего с кокретной задачей из (17).[/quote] Видать не вник ты в задачу :) [quote=Lexusss;23567298]...[/quote] Если у тебя есть понимание, то ответь на (12) |
26-Lexusss >Ну вот тут ты точно добил гвоздь в крышку :D |
(25) Не выполняется проверка. У тебя @Контр уникальна по id. Причина моего страстного желания убрать авторов подобных творений из IT (пусть и ценой убийства) - это стремление к идеалу. Вот скажи, зачем ты каждый раз в итерации выполняешь снова и снова обработку всех контрагентов по всем группам сгенерированной иерархии? Ведь достаточно сделать это ОДИН раз, а в итерации обрабатывать только новый сред иерархии. Так получается и код проще, да и вообще понять проще :) (27) [quote=Billi;23567391]Ты ветку читай внимательно[/quote] Для особо не понятливых. Ты из таблицы А выбираешь часть строк и после этого присоединяешь снова всю таблицу А. То есть множество строк первой соединяемой таблицы однозначно меньше множества строк второй соединяемой таблицы. В это случае ЛЕВОЕ и ВНУТРЕННЕЕ соединения дадут одинаковый результат. Но производительность второй конструкции намного выше производительности первой. Кроме того, такое соединение может повлечь оптимизатору построить кривой план выполнения. [quote=Billi;23567391]Видать не вник ты в задачу[/quote] Предположим такую гипотетическую интерпретацию запроса (1), что в куче Документ.ЗаказОконный.ГотовыеИзделия в выборку первой попадет строка с НомерСтроки = 2, а не строка с НомерСтроки = 1. В этом случае, твоя интерпретация запроса (1) не совпадет с результатом запроса (17). [quote=Billi;23567391]ответь на (12)[/quote] Смотри мой 23й пост. ПЫСЫ: Зачем ветку наверх пришпили? |
(28) Про потребность и необходимость иерархии можно спорить безумно долго. Но моя практика использования 7.7 толпами пользователей говорит, что существование папок в контрагентах ведет к их гарантированном задвоению. Чтобы добавить в 7.7 нового контрагента, нужно было включать иерархию. А вот отключить ее для поиска контрагента перед созданием новой карточки, многие пользователи забывают. Отсюда дубляжи с последующими проблемами. В 8.х это проблема понерфлена , но все еще актуальна. |
29-Lexusss >[quote=Lexusss;23568041]Вот скажи, зачем ты каждый раз в итерации выполняешь снова и снова обработку всех контрагентов по всем группам сгенерированной иерархии? Ведь достаточно сделать это ОДИН раз, а в итерации обрабатывать только новый сред иерархии. Так получается и код проще, да и вообще понять проще :)[/quote] Я не могу тебя понять. Поясни на примере. [quote=Lexusss;23568041]Для особо не понятливых[/quote] Для особо непонятлевых читай (19) внимательно, вторую строчку. [quote=Lexusss;23568041]Предположим такую гипотетическую интерпретацию запроса (1), что в куче Документ.ЗаказОконный.ГотовыеИзделия в выборку первой попадет строка с НомерСтроки = 2, а не строка с НомерСтроки = 1. В этом случае, твоя интерпретация запроса (1) не совпадет с результатом запроса (17).[/quote] Мне не важно какая строка будет. Мне надо по одной [b]любой[/b] строке на каждую Конструкцию. [quote=Lexusss;23568041]Смотри мой 23й пост.[/quote] Ещё раз повторю, про агрегаты речи не было. А во временные таблицы инсерт идёт именно на уровне скл. Тем более в пакете. И я не вижу никаких особых препятствий для того, чтобы сделать возможность дополнять временные таблицы. 30-Lexusss >Спорить не буду. Ибо предмета спора нет. Проблема решается элементарно. |
29-Lexusss >"Зачем ветку наверх пришпили?" Временно. Использую "служебное положение", что бы легче посматривать :) Извините. |
На счёт (0) скажу, что это действительно ерунда. При простом инсерте скл динамически не отслеживает новые записи в таблице. Решить задачу в (0) на скл без дополнительных группировок и соединений можно через уникальный индекс по полю "Конструкция". |
[quote=Billi;23568623]Поясни на примере.[/quote] Понеслась читать логику запроса. Исходные данные: таблицы sc133 справочника Контрагенты с индексами по id и parentid. Требуемый результат - все группы, входящие в иерархию группы с id ВыбГруппа. Используемые временные таблицы: #Группы - результирующая таблица #Контр - таблица текущего среза В ходе каждой итерации выполняются 3 запроса (insert into Группы, insert into Контр, delete Контр Первая итерация: Запрос 1: бессмысленная нагрузка на сервер. Можно добиться того же просто вставкой конкретного значения в Группы. Запрос 2: Берет срез групп, вложенных в ВыбГруппа и добавляет их в Контр. Обратим внимание, что в Контр id кластеризованый. То есть при такой вставке таблица будет жестко перестроена с потерей балансировки B-дерева кластерного индекса. Уникальность добавленных строк обеспечивается отдельной конструкцией "id not in ( select val from @Контр )" Запрос 3 опять же ничего не делает, лишь позря напрягает SQL. Итерация n+1: Запрос 1 добавляет в Группы НОВЫЕ значения из Контр. Там они так же уникальны по id, так что проверки в процессе добавления может и не происходить. Очень интересна проверка на isfolder, как будто там может быть что то другое :D Запрос 2 выбирает срез групп на уровне вложенности n. Опять выполняется какая то странная проверка " id not in ( select val from @Контр )". Конечно, это опять же гарантирует уникальность id в Контр, но зачем??? Разве, что у вас нарушена древовидность иерархии. Запрос 3, о чудо, удаляет из Контр данные итоговой таблицы, полученные на прошлой итерации!!! Опять же при этом портится чудесное b-дерево кластерного индекса. Именно из этого следует вопрос: Почему бы табличку текущего среза не прибить и не перегенрировать заново? Тогда не придется выполнять эти delete с просмотром всей Контр снова и снова. Итого, для простейшего случая без детей или с один уровнем вложенности, у тебя получается очень большая доля бессмысленных операций. Кроме того, над временной таблицей выполняется огромное количество операций insert и delete, при том что собственно кластерный индекс по id совершенно не используется. |
[quote=Billi;23568623]Для особо непонятлевых читай (19) внимательно, вторую строчку.[/quote] У тебя в (17) правильный запрос, кроме косяка с ЛЕВЫМ соединением. На SQL он будет отрабатывать оптимальным образом. Проверялось на огромных таблицах (миллионы строк). Никакие другие методы с временными таблицами, индексами и прочей лабудой и рядом не стоят. Вложенный запрос разворачивается оптимизатором SQL в такой же план выполнения (если мы говорим о грамотно написанном запросе). Время выполнения вообще не отличается. [quote=Billi;23568623]Мне надо по одной любой строке[/quote] Если уж выбираешь сумму и количество, как то странно такое слышать. Уж извини, не угадал... [quote=Billi;23568623]И я не вижу никаких особых препятствий [/quote] Я тож не прочь увидеть INSERT в 1С, хотя бы в каком то виде. Но пока что обхожусь без этого без особых потерь производительности. |
(33) Про уникальный индекс поподробнее. Неужели SQL не ругнется на DUPLICATED RECORD (или типа того)? Как то слабо верится. Я сейчас очень далек от серверов и не на чем экспериментировать. Тем не менее я рад, что мое предположение о невозможности динамического отслеживания добавления записей оправдалось :) Если оптимизатор SQL мог бы и такое, он вошел бы в пантеон моих богов. Как в таком случае строить план выполнения - это выше моих представлений о всем сущем. |
(32) Воскресенье, особой активности нет, следить за веткой очень просто. Так что, конечно же, извиняю. Обещаю в ветке не материться и не переводить в holly war "клюшки vs снеговик" :D))) |
37-Lexusss >Спасибо :D |
34-Lexusss >На всякий случай скажу, что это не моё произведение, я им просто пользуюсь :) Механизм работает исправно, 100 000 контров в 300-ах группах, тормозов в этом месте незамечено. А теоретически конечно интересно порассуждать. Если что, то я на стороне того парня :) Позже отпишусь по этому вопросу. 35-Lexusss >вобще-то в (17) левое соединение поставила сама одиныска в конструкторе :), я на автомате в форум и скопировал. А соединение я добавил потому как не люблю лишние группировки. А затем подумал, что соединение вообще не нужно, можно и все поля включать в подзапрос, там записей от силы 10 штук будет, так что группировка доп.полей сильно не навредит :) [quote=Lexusss;23569605]Если уж выбираешь сумму и количество, как то странно такое слышать. Уж извини, не угадал...[/quote] Там всё просто. В конструкции есть доп.элементы, которые не относятся ни к какому изделию (номенклатура), входящему в конструкцию, и сами по себе изделиями не являются. Вот их и надо в состав какой-нибудь номенклатуры воткнуть, не важно какой. Это делается один раз и записывается в РС сотав изделия, и они потом спокойно существуют в этом составе. |
36-Lexusss >Чуть позже отвечу. |
Текущее время: 20:29. Часовой пояс GMT +3. | [1] [2] |