![]() |
|
v8: Выполнение под-запроса для каждой строки временной таблицы. | ☑ | ||
---|---|---|---|---|
0
Kiber
18.10.10
✎
08:45
|
Есть две таблицы - втНом вида (номенклатура, количество) и Регистр оборотов вида (номенклатура, стоимость, валюта, период).
Необходимо в запросе для каждой строки втНом получить из регистра одно-единственное значение, последнее на текущую дату. Предполагается использование ключевого слова ПЕРВЫЕ 1. Для тестирования и наглядности составил текст для консоли запросов: [ ВЫБРАТЬ * ПОМЕСТИТЬ втНом ИЗ (ВЫБРАТЬ "Ном1" КАК Номенклатура, 1 КАК Количество ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном3", 4) КАК Тмп ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ * ПОМЕСТИТЬ втРег ИЗ ( ВЫБРАТЬ "Ном1" КАК Номенклатура, 50 КАК Цена, "Рубли" КАК Валюта, ДАТАВРЕМЯ(2001,01,01,00,00,00) КАК Период ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном1", 30 , "Рубли", ДАТАВРЕМЯ(2002,01,01,00,00,00) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 15 , "Евро", ДАТАВРЕМЯ(2002,01,01,00,00,00) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 600 , "Рубли", ДАТАВРЕМЯ(2001,01,01,00,00,00) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном3", 70 , "Доллары", ДАТАВРЕМЯ(2001,01,01,00,00,00) ) КАК Тмп ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ табНом.Номенклатура КАК Номенклатура,табНом.Количество КАК Количество,0 КАК Цена,0 КАК Валюта,null КАК Период ИЗ втНом КАК табНом Объединить все ВЫБРАТЬ табРег.Номенклатура,0,табРег.Цена,табРег.Валюта,табРег.Период ИЗ втРег КАК табРег ] Сейчас обе виртуальные таблицы выбираются последовательно, без условий (исключительно для наглядности тестовых данных). Необходимо получить выборку вида: Номенклатура Количество Цена Валюта Период Ном1 1 30 Рубли 01.01.2002 0:00:00 Ном2 2 15 Евро 01.01.2002 0:00:00 Ном3 4 70 Доллары 01.01.2001 0:00:00 |
|||
1
Fragster
гуру
18.10.10
✎
08:48
|
СКД может. а иначе - получить остаток на каждую дату во временную таблицу и соединять по периоду
|
|||
2
Kiber
18.10.10
✎
08:50
|
>> получить остаток на каждую дату во временную таблицу и соединять по периоду
Если можно, измени пример запроса под приведенный пример. |
|||
3
Ненавижу 1С
гуру
18.10.10
✎
08:52
|
ты таблицы виртуальные с временными не путаешь?
|
|||
4
Kiber
18.10.10
✎
08:54
|
Прошу обратить внимание, что хотя в тестовом примере втРег небольшая, в реальности она громадная, а получить остаток было-бы в корне неверно для такого показателя как "Цена".
Поэтому предполагается наличие ключевого слова ПЕРВЫЕ 1, или того, чем можно максимально ограничить выборку. |
|||
5
Kiber
18.10.10
✎
08:54
|
(3) Путаю :)
|
|||
6
Kiber
18.10.10
✎
08:57
|
Если есть модераторы - перефразируйте пожалуйста все "виртуальные таблицы" во "временные", в том числе - в заголовке темы.
|
|||
7
Fragster
гуру
18.10.10
✎
08:57
|
ой,блин.
короче, Выбрать Втрег.Номенклатура, ВтРег.Цена, ВтРег.Валюта, ВтРег.Период Из ВтРег Внутреннее Соединение (Выбрать ВтРег.Номенклатура, Максимум(ВтРег.Период) Как ПенриодМаксимум Из ВтРег Группировать По ВтРег.Номенклатура) Как Вложенный По Втрег.Номенклатура = Вложенный.Номенклатура И ВтРег.Период = Вложенный.ПенриодМаксимум |
|||
8
Fragster
гуру
18.10.10
✎
08:57
|
а вообще - это типа как "срез последних"
|
|||
9
Kiber
18.10.10
✎
09:09
|
Мысль понял. Спасибо.
Задача решена, но, насколько я понял, выбираются все данные ВтРег. Хочу решить её самым оптимальным способом, без выборки всех данных втРег. Объясняя "на пальцах" - хочу для каждой строки втНом выполнить запрос к втРег, с условием вида ВЫБРАТЬ ПЕРВЫЕ 1 * ИЗ ВтРег КАК табРег ГДЕ табРег.Номенклатура = табНом.Номенклатура УПОРЯДОЧИТЬ ПО Период УБЫВ |
|||
10
Fragster
гуру
18.10.10
✎
09:11
|
(9) т.е. ты думаешь, что один запрос
Выбрать ВтРег.Номенклатура, Максимум(ВтРег.Период) Как ПенриодМаксимум Из ВтРег Группировать По ВтРег.Номенклатура медленнее, чем тысяча запросов (по количеству строк)? |
|||
11
Kiber
18.10.10
✎
09:13
|
Честно говоря, не знаю :)
Вообще, задачу можно решить таким образом? |
|||
12
Fragster
гуру
18.10.10
✎
09:14
|
(11) ну, написать хранимку в скуле - и вперед
|
|||
13
Fragster
гуру
18.10.10
✎
09:15
|
в 1с же - СКД может, но медленнее, чем (7), потому как как раз много запросов будет
|
|||
14
Kiber
18.10.10
✎
09:16
|
А что есть хранимка? :)
|
|||
15
Ksandr
18.10.10
✎
09:17
|
Кореллированный запрос в помощь!
|
|||
16
Fragster
гуру
18.10.10
✎
09:18
|
(14) вот: Хранимая Процедура
|
|||
17
Fragster
гуру
18.10.10
✎
09:19
|
(15) не во всяком скуле такое есть. в МС, например, только в 2005 появился. я даже, сломав мозг, сделал как-то вывод иерархии через 1с++ в стиле стандартных семерошных запросов
|
|||
18
Kiber
18.10.10
✎
09:21
|
2 Fragster: Понял, огромное спасибо!
2 Ksandr: буду гуглить, тоже спасибо. |
|||
19
Just4Fun
18.10.10
✎
09:22
|
(0) как вариант.
1. по регистру делаешь выборку возвращающую номенклатуру и максимальную дату. 2. выборку и п.1. соединяешь с своим регистром по номенклатуре и дате. в итоге полчишь значения для максимальной даты |
|||
20
Fragster
гуру
18.10.10
✎
09:23
|
||||
21
Just4Fun
18.10.10
✎
09:23
|
(7) так же
|
|||
22
Just4Fun
18.10.10
✎
09:24
|
(20) уважаемый, это оскорбительное ругательство
|
|||
23
Fragster
гуру
18.10.10
✎
09:27
|
(22) ???
«Слоупок — покемон водно-психического типа и является одним из первых покемонов («It first appeared in the Generation I games») Слоупок может эволюционировать либо в Slowbro, достигнув 37 уровня, либо в Slowking (который, к слову, известен как едва ли не умнейший из всех покемонов) с помощью специального предмета» |
|||
24
Fragster
гуру
18.10.10
✎
09:28
|
а вообще - я просто намекаю, что ветку неплохо бы читать
|
|||
25
Ksandr
18.10.10
✎
09:35
|
(17)(18)
Кстати да, не работает на файловом варианте |
|||
26
Kiber
18.10.10
✎
10:24
|
2 Ksandr: Я изначально пытался написать коррелированный запрос для решения этой задачи, но не смог понять как обратиться к значению Номенклатура.
Если использовать коррелированный запрос в условии - пожалуйста, все работает. Ты не мог-бы написать пример для (0) с учетом (9)? |
|||
27
73
18.10.10
✎
10:32
|
ВЫБРАТЬ
ВтНом.Номенклатура, ВтНом.Количество, ВтРег.Номенклатура КАК Номенклатура1, ВтРег.Цена, ВтРег.Валюта, ВтРег.Период ИЗ ВтНом КАК ВтНом ЛЕВОЕ СОЕДИНЕНИЕ ВтРег КАК ВтРег ПО ВтНом.Номенклатура = ВтРег.Номенклатура И (ВтРег.Период В (ВЫБРАТЬ ПЕРВЫЕ 1 ВтРег.Период ИЗ ВтРег ГДЕ ВтРег.Номенклатура = ВтНом.Номенклатура УПОРЯДОЧИТЬ ПО ВтРег.Период УБЫВ)) ЗЫ. В ВтРег дублей по Номенклатура,Период не должно быть... |
|||
28
Kiber
18.10.10
✎
11:04
|
Вот! Это оно! Значит в условии соединения... Спасибо :)).
|
|||
29
Fragster
гуру
18.10.10
✎
11:29
|
хм...
|
|||
30
Fragster
гуру
18.10.10
✎
11:31
|
сделал замер на приличной выборке:
ВЫБРАТЬ ЦеныНоменклатуры.Период, ЦеныНоменклатуры.Номенклатура, ЦеныНоменклатуры.Цена ПОМЕСТИТЬ Цены ИЗ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры ГДЕ ЦеныНоменклатуры.ТипЦен = &ТипЦен ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ Цены.Период, Цены.Номенклатура, Цены.Цена ПОМЕСТИТЬ Результат1 ИЗ Цены КАК Цены ГДЕ Цены.Период В (ВЫБРАТЬ ПЕРВЫЕ 1 ТЗЦены.Период ИЗ Цены КАК ТЗЦены ГДЕ ТЗЦены.Номенклатура = Цены.Номенклатура УПОРЯДОЧИТЬ ПО ТЗЦены.Период УБЫВ) ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ Цены.Период, Цены.Номенклатура, Цены.Цена ПОМЕСТИТЬ Результат2 ИЗ Цены КАК Цены ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ МАКСИМУМ(Цены.Период) КАК Период, Цены.Номенклатура КАК Номенклатура ИЗ Цены КАК Цены СГРУППИРОВАТЬ ПО Цены.Номенклатура) КАК ВложенныйЗапрос ПО Цены.Период = ВложенныйЗапрос.Период И Цены.Номенклатура = ВложенныйЗапрос.Номенклатура результаты: РезультатЗапроса Название таблицы Время подзапроса ТаблицаЗначений ЦЕНЫ 0,079 ТаблицаЗначений РЕЗУЛЬТАТ1 87,812 ТаблицаЗначений РЕЗУЛЬТАТ2 0,172 |
|||
31
Fragster
гуру
18.10.10
✎
11:34
|
а если добавить индекс в таблицу "цены":
ИНДЕКСИРОВАТЬ ПО Номенклатура, Период РезультатЗапроса Название таблицы Время подзапроса Количество строк ТаблицаЗначений ЦЕНЫ 0,094 6 930 ТаблицаЗначений РЕЗУЛЬТАТ1 0,375 2 084 ТаблицаЗначений РЕЗУЛЬТАТ2 0,125 2 084 |
|||
32
73
18.10.10
✎
11:46
|
(30)
Во-1х, никто и не спорил, что медленнее будет... Во-2х, в (27) вторая таблица не зря дважды указывается. Так что замерь вот это: ВЫБРАТЬ Цены.Период, Цены.Номенклатура, Цены.Цена ПОМЕСТИТЬ Результат1 ИЗ Цены КАК Цены Внутреннее Соединение Цены Как Цены1 По Цены1.Номенклатура = Цены.Номенклатура И Цены1.Период = Цены.Период И Цены1.Период В (ВЫБРАТЬ ПЕРВЫЕ 1 ТЗЦены.Период ИЗ Цены КАК ТЗЦены ГДЕ ТЗЦены.Номенклатура = Цены.Номенклатура УПОРЯДОЧИТЬ ПО ТЗЦены.Период УБЫВ) |
|||
33
Fragster
гуру
18.10.10
✎
11:52
|
однако, если сделать 2 поля ключевыми (номенклатура и тип цен), то индексы уже не помогают:
РезультатЗапроса Название таблицы Время подзапроса Количество строк ТаблицаЗначений ЦЕНЫ 0,61 24 895 ТаблицаЗначений РЕЗУЛЬТАТ1 375,203 10 851 ТаблицаЗначений ВЛОЖЕННЫЙЗАПРОС 0,594 10 849 ТаблицаЗначений РЕЗУЛЬТАТ2 0,406 10 851 |
|||
34
Fragster
гуру
18.10.10
✎
12:19
|
вариант (27) очень сильно зависит от индексов и порядка условий, добился результата (результат1 - вложенный подзапрос "Выбрать первые", результат2 - внутреннее соединение с ВложенныйЗапрос)
РезультатЗапроса Название таблицы Время подзапроса ТаблицаЗначений ЦЕНЫ 0,406 ТаблицаЗначений РЕЗУЛЬТАТ1 1,375 ТаблицаЗначений ВЛОЖЕННЫЙЗАПРОС 0,328 ТаблицаЗначений РЕЗУЛЬТАТ2 0,297 в общем случае - вариант (7) читается похуже, но при этом практически не зависит от индексов, порядка полей и прочего |
|||
35
73
18.10.10
✎
12:25
|
(34) Ещё раз: никто не спорил. Даже наоборот.
Но стОит изменить условие задачи, как всё санет не так очевидно: Допустим, нужна не только последняя, но и предпоследняя цена. В (27) это решается "Выбрать Первые 2", а в (7)? |
|||
36
Fragster
гуру
18.10.10
✎
12:40
|
(35) еще одно внутреннее соединение с условием Максимум(Период)...Где Период < ПериодМаксимум
да, к сожалению, не так элегантно, как хотелось бы, но влияние на скорость незначительно |
|||
37
Kiber
18.10.10
✎
13:47
|
Мой мозг плавает в океане блаженства...
Интересно, а если в таблицу добавить нумератор и использовать при отборе? Не будет-ли это быстрее чем индексирование периода? Fragster, если не секрет, какой инструмент используешь для замеров времени выполнения подзапросов? |
|||
38
Fragster
гуру
18.10.10
✎
13:52
|
(37) консоль запросов с доработками Чистова (для просмотра временных таблиц), Воробьева(для показа имен этих самых таблиц) и меня (для как раз замера времени)
|
|||
39
Kiber
20.10.10
✎
10:53
|
В итоге после получения выборки данных регистра, ограниченной нашим набором номенклатуры в втРег, я еще раз выбираю втРег примернос следующим образом:
[ Выбрать * ПОМЕСТИТЬ втРег2 ИЗ втРег как табРег ГДЕ (табРег.Номенклатура, табРег.Поле1, ... , табРег.ПолеN) В (ВЫБРАТЬ ПЕРВЫЕ 1 тмп.Номенклатура, тмп.Поле1, ... , тмп.ПолеN ИЗ втРег КАК тмп ГДЕ тмп.Номенклатура = табРег.Номенклатура) ] А затем уже использую втРег2 для объединения. Соответственно, дополнительные поля ограничивающие выборку должны быть расположены в порядке убывания скорости отбора по ним (насколько я понимаю, индексированное поле > числовое поле > текстовое поле). Поправьте, если не прав. |
|||
40
Kiber
20.10.10
✎
10:59
|
P.S. Поля 1-N нужны исключительно для уникальности строк выборки. Для достижения уникальности строк можно использовать ВЫБРАТЬ РАЗЛИЧНЫЕ при формировании первичной втРег.
|
|||
41
Kiber
20.10.10
✎
11:07
|
Правда есть одна проблема...
При тестировании часто вылетает 1с с ошибкой MSSQL. Возможно, недоработка платформы 8.1.15.14. Возможно, в файловом варианте такого не будет. |
|||
42
Fragster
гуру
20.10.10
✎
11:14
|
с какой ошибкой? подозреваю про 256 таблиц
|
|||
43
Kiber
20.10.10
✎
11:17
|
Хотя нет, в абсолютно пустой базе в файловом режиме (без конфигурации) на тестовом примере (который в начале темы) вот такая ошибка:
Ошибка СУБД: Ошибка SQL: Поле не найдено '#Td25d710822d34f418e974cc84069b5dc_Q_001_T_001._Q_006_F_000' по причине: Ошибка SQL: Поле не найдено '#Td25d710822d34f418e974cc84069b5dc_Q_001_T_001._Q_006_F_000' Щас проверю на 8.2 и наверное буду репортить %)) |
|||
44
Fragster
гуру
20.10.10
✎
11:37
|
(43) где-то накосячил. у меня на том же релизе работает
|
|||
45
Kiber
20.10.10
✎
11:42
|
На 8.2 вообще по другому отрабатывает...
Видимо, изменили язык запросов, либо получает NULL и в итоге при сравнении всегда получает Истина. В общем, вот текст запроса: [ ВЫБРАТЬ * ПОМЕСТИТЬ втНом ИЗ (ВЫБРАТЬ "Ном1" КАК Номенклатура, 1 КАК Количество ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном3", 4) КАК Тмп ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ * ПОМЕСТИТЬ втРег ИЗ ( ВЫБРАТЬ "Ном1" КАК Номенклатура, 50 КАК Цена, "Рубли" КАК Валюта, ДАТАВРЕМЯ(2001,01,01,00,00,00) КАК Период ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном1", 30 , "Рубли", ДАТАВРЕМЯ(2002,01,01,00,00,00) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 15 , "Евро", ДАТАВРЕМЯ(2002,01,01,00,00,00) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 600 , "Рубли", ДАТАВРЕМЯ(2001,01,01,00,00,00) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном3", 70 , "Доллары", ДАТАВРЕМЯ(2001,01,01,00,00,00) ) КАК Тмп ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ * ПОМЕСТИТЬ втРег2 ИЗ втРег КАК табРег ГДЕ (табРег.Номенклатура, табРег.Цена, табРег.Валюта, табРег.Период) В (ВЫБРАТЬ ПЕРВЫЕ 1 тмп.Номенклатура, тмп.Цена, тмп.Валюта,тмп.Период ИЗ втРег КАК тмп ГДЕ тмп.Номенклатура = табРег.Номенклатура) ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ * ИЗ втНом КАК ТабНом ПОЛНОЕ СОЕДИНЕНИЕ втРег2 КАК ТабРег2 ПО ТабНом.Номенклатура = ТабРег2.Номенклатура ] |
|||
46
Kiber
20.10.10
✎
11:47
|
Где накосячил? :)))))))
|
|||
47
Fragster
гуру
20.10.10
✎
11:51
|
(46) ...
ВЫБРАТЬ "Ном1" КАК Номенклатура, 1 КАК Количество ПОМЕСТИТЬ втНом ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном3", 4 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ "Ном1" КАК Номенклатура, 50 КАК Цена, "Рубли" КАК Валюта, ДАТАВРЕМЯ(2001, 1, 1, 0, 0, 0) КАК Период ПОМЕСТИТЬ втРег ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном1", 30, "Рубли", ДАТАВРЕМЯ(2002, 1, 1, 0, 0, 0) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 15, "Евро", ДАТАВРЕМЯ(2002, 1, 1, 0, 0, 0) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном2", 600, "Рубли", ДАТАВРЕМЯ(2001, 1, 1, 0, 0, 0) ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Ном3", 70, "Доллары", ДАТАВРЕМЯ(2001, 1, 1, 0, 0, 0) ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ втРег.Номенклатура, втРег.Цена, втРег.Валюта, втРег.Период ИЗ втРег КАК втРег ГДЕ втРег.Период В (ВЫБРАТЬ ПЕРВЫЕ 1 тмп.Период ИЗ втРег КАК тмп ГДЕ втРег.Номенклатура = тмп.Номенклатура УПОРЯДОЧИТЬ ПО тмп.Период УБЫВ) |
|||
48
Fragster
гуру
20.10.10
✎
11:51
|
правда так проще?
|
|||
49
Kiber
20.10.10
✎
12:08
|
Те-же яйца только в смятку :).
Для поставленной задачи - проще. И правильнее я-бы даже сказал. Но для скорости всеравно потребуется первичная выборка. Чтобы не обращаться к реальным данным каждый раз, когда проверяется условие. Номенклатура там лишняя конечно в условии, остальное может варьироваться в зависимости от измерений регистра, чтобы гарантировать уникальность записи. |
|||
50
Kiber
20.10.10
✎
12:11
|
Слушай, а как ты поля индексировал во временной таблице?
|
|||
51
Kiber
20.10.10
✎
12:11
|
Все, туплю, нашел. :)
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |