Имя: Пароль:
1C
1C 7.7
v7: SQL запрос к двум Таблицам Значений
,
0 evgpinsk_
 
29.05.21
22:55
Есть две таблицы значений.
Хотел бы через SQL запрос сделать выборку из эти двух таблиц.

примерно так:
SELECT Товары.Код, Товары.Наименование
FROM Разделы INNER JOIN Товары ON Разделы.Код = Товары.Код;

Сейчас я обе ТЗ через
базаДанных.уложитьТЗ()

укладываю в виртуальную таблицу. А дальше мне эти таблицы нужно объеденить в запросе и получить выборку.
Это реально?
1 ДенисЧ
 
30.05.21
04:03
А почему нет, если у тебя есть две таблицы, имена которых ты знаешь?
2 acanta
 
30.05.21
06:17
А что "уложитьТЗ" делает с именами полей?
3 evgpinsk_
 
30.05.21
08:38
(1) Не нашёл в гугле как
(2) Не понял вопрос. Ничего не делает, просто создаёт в памяти таблицу, к которой можно обращаться  через SQLiteBase
базаДанных.уложитьТЗ(ИсходнаяТЗ,"ПолучаемсяТаблицаДляSQL",0);    
и не нашёл что определяет 3й параметр
4 ДенисЧ
 
30.05.21
08:44
базаДанных.уложитьТЗ(ИсходнаяТЗ,"ПолучаемсяТаблицаДляSQL1",0);
базаДанных.уложитьТЗ(ИсходнаяТЗ,"ПолучаемсяТаблицаДляSQL2",0);

запрос = "
|SELECT т1.*. т2.* FROM ПолучаемсяТаблицаДляSQL1 AS т1
|FULL JOIN ПолучаемсяТаблицаДляSQL2 AS т2
|ON TRUE
";
5 evgpinsk_
 
30.05.21
10:05
(4) Спс
6 Sserj
 
30.05.21
11:23
(3)
Синтаксис: УложитьТЗ(ТЗ, ИмяТаблицы, [КакПостоянную])

Параметры:
ТЗ - тип: ТаблицаЗначений. Таблица, загружаемая в базу данных
ИмяТаблицы - тип: Строка. Имя создаваемой в базе данных таблицы.
КакПостоянную - тип: Число. 1 - создать обычную таблицу, 0 - создать временную таблицу. Необязательный параметр. По умолчанию 0.
Возвращает: нет

Описание: Загружает таблицу значений в базу данных, как таблицу базы данных.

Если таблица с указанным именем уже существует, она удаляется. Состав полей созданной таблицы соответствует составу колонок ТЗ. Имена полей созданной таблицы соответствуют идентификаторам колонок ТЗ. Формат в котором выгружаются значения из ТЗ, см в Преобразование значений 1С в значения базы данных (работа с параметрами)
7 evgpinsk_
 
30.05.21
13:41
Последний затык остался, на пути решения общей задачи

Есть две таблицы:
ХарактеристикиТМЦ три поля (ТМЦ, Характеристика, ЗначениеХарактеристики as Значение) - все характеристики всех товаров
и
ГруппыТМЦ и три поля (ГруппаТМЦ, Характеристика, ЗначениеХарактеристики as Значение) - на Группы товаров мы можем задать характеристики.

Задача - определить для Товара, в какую Группу его нужно перенести. Условие что Значения всех введённые характеристик Группы товаров
равны Значениям этих же характеристик у товара.
Ниже скрин ситуации:
https://prnt.sc/13l62xz

Через SQL запрос решается данная задача? /я так понимаю он не совсем тривиальный/
Либо проще эту задачу решать через ТаблицыЗначений и циклы к ним?
8 Garykom
 
гуру
30.05.21
13:54
(0) На 77 обычно быстрее ТЗ без sql запросов обрабатывать
Так что вперед с циклами, только правильными
Не надо удалять или изменять записи в текущих ТЗ, создай новую добавляй строки в неё
9 evgpinsk_
 
30.05.21
14:11
(8) Сначала показалось, что запрос простой будет и потратил часов 5 на доизучение SQLiteBase.
И на последнем шаге затык )

А с циклами через ТЗ - тоже думаю подумать над алгоритмом придётся
10 Djelf
 
30.05.21
14:34
(7) Не понятно зачем сначала запихивать все это в тз, сразу к таблицам прицепится нельзя что-ли?
Ничего не понял из твоего описания ;)

(8) Да, 7ка хорошо работает с циклами на тз, только с итз все все равно быстрее будет, а с 1sqlite ни то, ни другое не нужно!
11 evgpinsk_
 
30.05.21
14:41
(10) >Не понятно зачем сначала запихивать все это в тз, сразу к таблицам прицепится нельзя что-ли?

Я запихивал в ТЗ для наглядности отладки. Пj факту через  SQlite я сразу обращаюсь к справочникам.
И сделал 85% всех движений. Предполагал что последний запрос будет лёгким.
А по факту он не тривиален
12 Djelf
 
30.05.21
14:55
(11) А вот так делать не надо!
sqlite это встраивая база данных, она никогда не сможет ни кэшировать гигабайты в оперативке, ни выполнять огромное количество совершенно ненужной работы...
Тем более что это все прилеплено к 1С 7.7 и статистики никакой нет и не будет.

Принцип эффективной работы на 1sqlite такой:
- сначала выбираем таблицу у которой получится с условием в where наименьшее количество записей (проверяем в консоли, получилось? ок, идем дальше).
- left join`ом клеим вторую, третью, четвертую таблицу. (проверяем последовательно).
- inner join использовать не стоит (нет статистики, только предположения, а они очень не точные). Лучше отфильтровать полученные данные после left join в where (в 90% случаев это быстрее).

И (8) Прав, только сказал по другому, тут фактически получается тот же перебор тз, но на более эффективном движке.
13 evgpinsk_
 
30.05.21
15:08
(12) Не совсем понял что не верно.
Тут вопрос не в скорости , а в том как решить задачу ). Мне показалось что решение будет простым через SQL запросы.
Поэтому и пошёл этим путём
Через:
    запрос.ВыполнитьЗапрос("create virtual table ХарактеристикиГрупп using dbeng(Справочник.ХарактеристикиГрупп)");
    запрос.ВыполнитьЗапрос("create virtual table Товары using dbeng(Справочник.ТМЦ)");

читаю нужные мне справочники в память, и дальше через SQL запросы думал получить нужный результат
14 Djelf
 
30.05.21
15:15
(13) create virtual table не нужно - читай документацию, там 2 варианта автоподключения таблиц 1С есть.
SQL работает не так! Тебе не надо все тащить из базы... Только необходимое!
И одним запросом в 1sqlite это должно работать. Путь действий я в (12) написал.
15 evgpinsk_
 
30.05.21
15:17
(14) > create virtual table не нужно - читай документацию

если бы ещё иметь эту документацию )
16 Djelf
 
30.05.21
15:25
(15) Скачай уже... https://snegopat.ru/1sqlite/index Ой! Нету ;)
Но ты отважный, парень! Без документации это... ххх... Забирай: https://cloud.mail.ru/public/aceG/K247Dds3o
17 Garykom
 
гуру
30.05.21
15:33
(12) >но на более эффективном движке

а время на передачу данных и назад?
18 Djelf
 
30.05.21
15:35
(17) Это время ничтожно. Это не 8ка с ее NativeAPI, все через память передается.
19 evgpinsk_
 
30.05.21
15:36
Но ведь /как мне казалось/ 1с и их ТЗ не имеют мощный функционал выборки данных через Select.
Там только циклы
20 trdm
 
30.05.21
15:38
(16) Сам chm-ку делал?
21 Djelf
 
30.05.21
15:40
(20) Спер! Честно, спер! У Орефкова... Но копирайты там все есть...
22 trdm
 
30.05.21
15:43
(21) Нет, я к тому что до сих пор не разобрался как вот эти элементы в нее пихать:
https://prnt.sc/13lb6hg
красным обвел.
Моя скомпилированная справа.
23 Djelf
 
30.05.21
16:57
(22) Прости, я не помню откуда у меня эта chm, экспериментировал с ними, но эта точно не от туда...
24 evgpinsk_
 
30.05.21
19:47
Есть ли возможность в 1sqlite работать с составными запросами? т.е. описать сначала один простой запрос
и потом во втором запросе обратится к нему как к таблице.

п.с. (16) по ссылке chm не открывает содержимое разделов:
https://prnt.sc/13ljllr
25 Злопчинский
 
30.05.21
20:49
вычитать и складывать тз можно через 1с++ итз
26 evgpinsk_
 
30.05.21
20:54
(24) > Есть ли возможность в 1sqlite работать с составными запросами? т.е. описать сначала один простой запрос
и потом во втором запросе обратится к нему как к таблице.

Отвечаю сам себе, нашёл такой способ решения /хотя не нравится он мне/:
    Результат=Запрос.ВыполнитьЗапрос(ТекстЗапроса);
    Результат.выгрузить(ТЗ1с);            
    базаДанных.уложитьТЗ(ТЗ1с,"с1",0);    

Выполняю запрос, затем выгружаю его в таблицу значений, а затем эту таблицу значений укладываю в новую таблицу.
Правильно или есть другой способ?
27 evgpinsk_
 
30.05.21
21:18
Поздравляю сам себя, решил задачу через SQL запросы.
Теперь при оприходовании товара импортом из екселя все новые товары падают изначально в нужную группу 1го уровня.
Затем парсятся характеристики товаров.
И затем на основании этих характеристик они разносятся по правильным подгруппам многоуровнего справочника номенклатуры.
На скрине ниже каждая ТЗ - это промежуточный какойто результат
https://prnt.sc/13lmj8c
28 Злопчинский
 
30.05.21
21:42
Молодец, возьми с полки пирожок! ;-)
29 Sserj
 
31.05.21
03:11
(26) 1sqlite умеет CTE:

with НужноеИмя as (
select
  спр.id as Элемент
  , спр.descr as Наименование
from
  Справочник_Номенклатура as спр
)

select
  товары.Элемент as [Товар $Справочник.Номенклатура]
  , товары.Наименование as [Наименование $Строка]
  ....
from
  НужноеИмя as товары
  join .... on товары.Элемент = ....
30 DrZombi
 
гуру
31.05.21
06:15
(0) Реально.
31 Mikeware
 
31.05.21
07:40
32 evgpinsk_
 
31.05.21
09:37
(29) Да, то что в одном запросе можно использовать подзапросы, это понятно. Но так сложнее писать.
Проще когда создал подзапрос, увидел его отработку, и потом обращаешься к нему из другого запроса. Пример из Access:

SELECT Таблица1.Поле1, Таблица1.Поле2 FROM Таблица1; (Этот запрос сохранён под именем Запрос)
SELECT Запрос.Поле1 FROM Запрос GROUP BY Запрос.Поле1;
33 Djelf
 
31.05.21
10:11
(32) Сделай вьюшку и обращайся к ней https://sqlite.org/lang_createview.html Будет то же самое.
34 Mikeware
 
31.05.21
10:41
(33) ты, конечно, учишь хорошему. Но как в анекдоте про попа и бизнесмена "но зря".
у чувака _уже_ есть ТЗ, ему надо их обработать. зачем выгружатьв бд-вычислять-загружать из бд, если эти же действия можно сделать сразу над ТЗ?
(ну по меньшей мере, джойны и группировки)
35 evgpinsk_
 
31.05.21
10:48
(34) Мне казалось, что есть задачи, которые через SQL легче решаются чем через циклы в ТЗ
36 Mikeware
 
31.05.21
11:03
(35) а кто сказал про циклы?
не, SQL тоже преобразует все в циклы (можно посмотреть в плане исполнения запроса), но мы ж не об этом...
ты (31) пробовал прочитать? ну и там то, что рядом? (Правое..., Левое..., Полное...)
37 Salimbek
 
31.05.21
11:19
Голосую за Индексированную таблицу! С индексами, фильтрами, поиском по нескольким полям и прочими плюшками...
38 Mikeware
 
31.05.21
11:46
(37) как минимум в данном случае...
ну а вообще - "каждому овощу свой фрухт!"©, т.е. любой инструмент уместен в своем случае...
39 evgpinsk_
 
31.05.21
12:04
(36) увидел по ссылке иннерджоин и подумал что там про sql. Про итз узнал только сейчас
40 Злопчинский
 
31.05.21
12:54
(39) юзай, очень удобно и быстро
41 evgpinsk_
 
31.05.21
13:14
(33) Здесь не догоняю. Может есть пример, как сохранить запрос, чтобы потом к нему обращаться по имени?
42 Djelf
 
31.05.21
13:31
(41) Легко!

DROP VIEW IF EXISTS ВьюшкаТовары;
CREATE VIEW temp.ВьюшкаТовары AS SELECT ID as Товар FROM [Справочник.Номенклатура];
SELECT Товар [Товар :Справочник.Номенклатура] FROM ВьюшкаТовары;

Только навсегда запомни - типизация из внутреннего представления, в данном случае [Товар :Справочник.Номенклатура] должна быть только тогда, когда (верхний) запрос возвращает данные в тз или итз, или в ТабличноеПоле. Все внутренние запросы, в том числе и все VIEW должны быть без типизации!
43 Mikeware
 
31.05.21
13:40
(42) он же без типизации результат "в читаемом виде" не увидит... :-) а ему именно для этого надо...
в принципе, пофиг... 100500 вариантов ему дали, пущай кувыркаиццо....
44 Djelf
 
31.05.21
13:42
(37) Я интенсивно использовал ИТЗ, до тех пока не изучил 1sqlite ;)
Кое-где все равно ИТЗ использую. Когда в таблицу нужно добавить через* вычисляемую колонку и по ней отфильтровать.
Напрягает что ИТЗ нельзя выгрузить в таблицу sqlite! Приходится прогонять через ТЗ.
Могу сделать эту выгрузку, но не понятно как попроще преобразовывать не типизированные значений ИТЗ в сокращенные/типизированные в sqlite ;(
45 Djelf
 
31.05.21
13:44
(43) Ты забыл уже наверное! Он при внутренней типизации все значения перекорёжит и поубивает! Т.е. этот вопрос все равно возникнет ;)
46 Злопчинский
 
31.05.21
13:55
(44) "Когда в таблицу нужно добавить через* вычисляемую колонку "
- это как?
47 Djelf
 
31.05.21
14:05
(46) Ну, это такая гадость бывает, которую очередной креативный менеджер захотел, а как оформить как оно работает забыл!
Типа вычисления Торгового по каждому документу, когда Торгового нет в ПКО, или их там два или три, эксклюзивных, не эксклюзивных и паразитирующих.
Ну... я не всегда прав, но из-за придурка, который мне всю базу, при нормальном подходе, переломает под свои фантазии, а потом свалит через пару месяцев...
Пускай тратит на это свое время, а не мое ;)
48 Mikeware
 
31.05.21
15:36
(45) не, я-то помню, когда надо типизировать, и когда не надо... собственно, поэтому и порекомендовал работать с ИТЗ - ему проще
(47) "паразитирующий ТП" - хорошее определение!
49 evgpinsk_
 
31.05.21
22:39
(42) Застрял на VIEW
вот этот код отрабатывает хорошо:
Текстзапрос="DROP VIEW IF EXISTS ТЗГруппыТМЦ_2";    тз=запрос.ВыполнитьЗапрос(Текстзапрос);
Представление= "    
    |CREATE VIEW temp.ТЗГруппыТМЦ_2 AS SELECT Count(ТЗГруппыТМЦ_.Хар) AS Колич, ТЗГруппыТМЦ_.ГруппаУр1 as [ГруппаУр1_ $Справочник.ТМЦ], ТЗГруппыТМЦ_.Группа as [Группа $Справочник.ТМЦ]
    |FROM ТЗГруппыТМЦ_
    |GROUP BY ТЗГруппыТМЦ_.ГруппаУр1, ТЗГруппыТМЦ_.Группа;";    
Текстзапрос="Select * from ТЗГруппыТМЦ_2;";                   // Вот в этой строке если ставим * то всё ок
тз=запрос.ВыполнитьЗапрос(Текстзапрос);
тз.Выгрузить(ТЗРез);    
результат: https://prnt.sc/13n6vqd


Но я не пойму, как напрямую обратиться к полям VIEW /к тем, которые справочники/, выбивает на любых вариантах ошибку:
Текстзапрос="Select Колич from ТЗГруппыТМЦ_2;";     -   РАБОТАЕТ
Текстзапрос="Select ГруппаУр1_ from ТЗГруппыТМЦ_2;";     -   ошибка     "no such column: ГруппаУр1_"
Текстзапрос="Select ТЗГруппыТМЦ_2.ГруппаУр1_ from ТЗГруппыТМЦ_2;";     -   ошибка     "no such column: ГруппаУр1_"
Текстзапрос="Select ГруппаУр1_ [ГруппаУр1_ :Справочник.ТМЦ] from ТЗГруппыТМЦ_2;";     -   ошибка     "no such column: ГруппаУр1_"
Текстзапрос="Select ГруппаУр1_ [ГруппаУр1_ &Справочник.ТМЦ] from ТЗГруппыТМЦ_2;";     -   ошибка     "no such column: ГруппаУр1_"
50 Salimbek
 
31.05.21
23:38
(49) Вот это вот: "ТЗГруппыТМЦ_.ГруппаУр1 as [ГруппаУр1_ $Справочник.ТМЦ]" - это именно то, что тебе прямо запрещали делать в (42)

Правильно так: "ТЗГруппыТМЦ_.ГруппаУр1 as ГруппаУр1_"

Дело в том, что в квадратных скобках - это имя столбца (если в ней есть пробел или другие спец.символы, если ничего такого нет, то можно и без квадратных, как у меня выше). И поэтому в первом случае у тебя создается колонка с именем "ГруппаУр1_ $Справочник.ТМЦ". И именно поэтому у тебя запрос ругается, что нет такой колонки "ГруппаУр1_".

А далее - когда 1С-ка получает данные из запроса, то компонента находит такое дурацкое имя колонки (с наличием " $Справочник.ТМЦ"), понимает, что тут ты хочешь получить данные из этого Справочника и производит подмену. При этом она сама отрезает в имени колонки лишнее. И поэтому в итоге мы видим уже правильное имя колонки "ГруппаУр1_" в которой лежат элементы этого справочника.
51 evgpinsk_
 
31.05.21
23:57
(50) > Правильно так: "ТЗГруппыТМЦ_.ГруппаУр1 as ГруппаУр1_"
Да, прошло.  Просто странно, почему в моём варианте вьюшки

запрос вида:
Текстзапрос="Select * from ТЗГруппыТМЦ_2;";   -    Работает.   (в (49) виден скрин результата)

И раз он работает, то я предполагала что в запросе както можно обратиться напрямую к его полям, а не только через *
52 Mikeware
 
01.06.21
06:25
(45) Ну вот, я ж говорил в (48)...
53 evgpinsk_
 
01.06.21
08:23
(52) просто не понятно почему select * работало
54 Mikeware
 
01.06.21
08:58
(53) понятно. Но объяснять не буду. Используй работу с ИТЗ
55 Arbuz
 
01.06.21
15:15
(50) Ну вот. Я использовал это (название колонки с типизацией) как какую-то магию, а ты взял и все кишки популярно объяснил. (:
56 Djelf
 
01.06.21
15:47
(53) Ну отлично же (50) все написал! Понятнее объяснить это было бы сложно.
Выполни запрос
SELECT name FROM pragma_table_info('ТЗГруппыТМЦ_2');
Для обоих вариантах создания представления, и (53) должно стать понятно...
57 Mikeware
 
01.06.21
15:53
(56) <тут должен быть анекдот про негра и молоко>
58 Djelf
 
01.06.21
16:01
+(56) Но если нужно и так и сяк делать запросы (т.е. использовать в других запросах и выборку по Полю и через Звездочку), то и это не проблема!

DROP VIEW IF EXISTS ВьюшкаТовары;
CREATE VIEW temp.ВьюшкаТовары AS SELECT ID AS Товар, ID [РасшифровкаТовара :Справочник.Номенклатура] FROM [Справочник.Номенклатура];

Но учти такую штуку: sqlite проталкивает условия в WHERE внешнего запроса представлению внутрь VIEW!
Т.е. количество записей в таких запросах будет уменьшаться, а вот выкидывать из запроса лишние поля, к которым нет обращения (пока?) не умеет. Т.е. РасшифровкаТовара в финальной версии не нужна, это лишние колонки на больших объемах может вызвать замедление.

(57) Да ладно тебе, во первых он писал что не программист, во вторых рисует в конструкторе Access. Может когда сам научится другим поможет... А упорство уже есть ;)
59 Mikeware
 
01.06.21
16:05
(58) ну пределы некомпетентности тоже надо осознавать. я понимаю, что плох тот чайник, который не мечтает стать самоваром, но всё-таки...
60 Djelf
 
01.06.21
16:12
(59) Ну, в Необходим быстрый поиск информации в больших CSV файлах он заставил и меня мозгами поскрипеть ;)
61 Salimbek
 
01.06.21
16:44
(53) Дык, в чем проблема то?
Ты делаешь запрос "Выбрать все поля из таблицы". SQLite без проблем выполняет этот запрос, возвращает тебе ответ с колонкой с именем "ГруппаУр1_ $Справочник.ТМЦ", 1С-ка видит "волшебное поле", радостно хлопает в ладошки, применяет свою магию и ты получаешь в ответ табличку с полем "ГруппаУр1_" и содержимым внутри "Справочник.ТМЦ"
62 Djelf
 
01.06.21
19:40
(61) У него проблема в последовательных запросах к VIEW. т.е. хочется и звездочкой получить всю таблицу для отладки и просмотра, и одновременно использовать поле в коротком представлении, без типизации. Решается запросом в (58).
63 evgpinsk_
 
02.06.21
09:23
(59) Одно дело, когда всю жизнь заниматься программированием, и совсем другое когда учитель вьетнамского тебе 5й раз раз объясняет чем один тон отличается от другого (посмотрел бы я на тебя на скорость изучения данного языка и компетентность). Также и с синтаксисом SQL в 1с - в инете Хелпа толкового нет, приходится писать наугд.
64 evgpinsk_
 
02.06.21
09:33
(61) > Дык, в чем проблема то?

) неужели не понятно, почему у новичка случился в данном случае затык ??
Очень ведь легко: Бал запрос первый - это VIEW
и был запрос второй, "Select * from View;"

Который выполнялся и возвращал результат со всеми колонками. Естественно я предполагал что первый VIEW запрос написан верно, раз он обрабатывался. И естесвенно что я искал  ошибку во второй запросе, когда вместо * пытался обратится к полям первого запроса напрямую.

П.с. одно дело, когда на эту проблему смотрит или носитель языка или практикующий несколько лет, и совсем другое - когда ктото с опытом в несколько дней