Имя: Пароль:
1C
 
Запрос. Помогите с простым запросом на выбор последних непустых значений
0 SerGa
 
07.10.24
17:38
Есть таблица вида:

----------------------------------
Дата        |value1|value2|value3|
----------------------------------
01/01/24    |a     |      |      |
01/02/24    |      |c     |      |
01/04/24    |      |d     |g     |
01/08/24    |b     |e     |z     |


таблица может иметь миллионы записей


нужно получить срез последних непустых значений из нескольких колонок, т.е.


результат запроса:

a  c  g


Как написать оптимальный запрос?
(при этом очень высока вероятность что подобные непустые значения будут уже в нескольких последних записях)
1 Галахад
 
07.10.24
17:39
Группировка по макс дата.
2 SerGa
 
07.10.24
17:42
(1) не понял как?
3 СвинТуз
 
07.10.24
17:42
Смотря что нужно
Может это и не совсем запрос.
4 СвинТуз
 
07.10.24
17:42
(0)
За 18 лет не научились с кодом извращаться?
5 СвинТуз
 
07.10.24
17:44
Если нет уникальности по полю ключа (Дата)
Это не запрос.
Если есть, то все просто.
6 СвинТуз
 
07.10.24
17:45
Вернее не только пакет запросов. Если нет уникальности.
7 SerGa
 
07.10.24
17:47
(4) нет.
(5) уникальности нет - это таблица документов. ищем среди последних документов последние значения определенных полей.
8 СвинТуз
 
07.10.24
17:47
Хотя ... и запросом можно даже в случае отсутствия уникальности по ключевому полю.
9 СвинТуз
 
07.10.24
17:49
(7)
уникальности нет - это таблица документов

Обмануть решили? )

Нужен порядок следования?

ВЫБРАТЬ
    Тест.Ссылка КАК Ссылка,
    АВТОНОМЕРЗАПИСИ() КАК Номер
ПОМЕСТИТЬ ВТ
ИЗ
    Справочник.Тест КАК Тест
;
10 СвинТуз
 
07.10.24
17:51
В таблице документов есть МоментВремени()
Всегда разводит документы в пределах одной секунды.

Обманывать не хорошо ...
11 SerGa
 
07.10.24
17:56
(10) по условию - в таблице могут быть миллионы записей.  Вероятно запихивать их все в виртуальную таблицу, а потом автонумерацию делать - не самое оптимальное решение?
12 SerGa
 
07.10.24
18:02
Я честно говоря, пришел к выводу, что средствами запроса 1С - оптимально для больших данных это не сделать. Только циклом в обратном порядке порциями считывая.. и прирывать цикл когда все последние найдены.  Но подумал, может групповой разум сможет подсказать решение
13 Галахад
 
07.10.24
18:14
ВЫБРАТЬ
    ДАТАВРЕМЯ(2024, 1, 1) КАК Дата,
    "А" КАК П1,
    "Б" КАК П2
ПОМЕСТИТЬ Таб

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДАТАВРЕМЯ(2024, 2, 1),
    "А",
    "Б"
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    МАКСИМУМ(Таб.Дата) КАК Дата,
    Таб.П1,
    Таб.П2
ИЗ
    Таб КАК Таб

СГРУППИРОВАТЬ ПО
    Таб.П1,
    Таб.П2
14 xenos
 
07.10.24
18:14
(0) Количество колонок фиксировано?
15 SerGa
 
07.10.24
18:19
(14) да изначально известно
16 SerGa
 
07.10.24
18:20
(13) почему так? мне нужны последние непустые
17 RomanYS
 
07.10.24
18:29
(12) "Выбрать ПЕРВЫЕ 1" для каждой колонки отдельный подзапрос
18 RomanYS
 
07.10.24
18:30
(0) пишешь срез последних, а в примере у тебя срез первых
19 SerGa
 
07.10.24
18:30
(17) а в условии что?
20 SerGa
 
07.10.24
18:31
(18) да, я не точно написал.. я имел ввиду последние не пустые...  просто там я таблицу уже отсортировал по убыванию даты
21 RomanYS
 
07.10.24
18:44
(19) Очевидно, что нужная колонка заполнена
22 xenos
 
07.10.24
19:54
(15) Как-то так

ВЫБРАТЬ
    АвансовыйОтчет.Дата КАК Дата,
    АвансовыйОтчет.Кратность КАК Значение1,
    АвансовыйОтчет.Курс КАК Значение2,
    АвансовыйОтчет.СуммаДокумента КАК Значение3
ПОМЕСТИТЬ втДанные
ИЗ
    Документ.АвансовыйОтчет КАК АвансовыйОтчет
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    взНепустые.Дата КАК Дата,
    взНепустые.ИмяПоля КАК ИмяПоля,
    взНепустые.ЗначениеПоля КАК ЗначениеПоля
ПОМЕСТИТЬ втНепустые
ИЗ
    (ВЫБРАТЬ
        втДанные.Дата КАК Дата,
        "Первое" КАК ИмяПоля,
        втДанные.Значение1 КАК ЗначениеПоля
    ИЗ
        втДанные КАК втДанные
    ГДЕ
        втДанные.Значение1 <> НЕОПРЕДЕЛЕНО
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        втДанные.Дата,
        "Второе",
        втДанные.Значение2
    ИЗ
        втДанные КАК втДанные
    ГДЕ
        втДанные.Значение2 <> НЕОПРЕДЕЛЕНО
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        втДанные.Дата,
        "Третье",
        втДанные.Значение3
    ИЗ
        втДанные КАК втДанные
    ГДЕ
        втДанные.Значение3 <> НЕОПРЕДЕЛЕНО) КАК взНепустые

ИНДЕКСИРОВАТЬ ПО
    Дата,
    ИмяПоля
;

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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    взРезультат.Значение1 КАК Значение1,
    взРезультат.Значение2 КАК Значение2,
    взРезультат.Значение3 КАК Значение3
ИЗ
    (ВЫБРАТЬ
        ВЫБОР
            КОГДА втПоследниеЗначения.ИмяПоля = "Первое"
                ТОГДА втПоследниеЗначения.ЗначениеПоля
            ИНАЧЕ НЕОПРЕДЕЛЕНО
        КОНЕЦ КАК Значение1,
        ВЫБОР
            КОГДА втПоследниеЗначения.ИмяПоля = "Второе"
                ТОГДА втПоследниеЗначения.ЗначениеПоля
            ИНАЧЕ НЕОПРЕДЕЛЕНО
        КОНЕЦ КАК Значение2,
        ВЫБОР
            КОГДА втПоследниеЗначения.ИмяПоля = "Третье"
                ТОГДА втПоследниеЗначения.ЗначениеПоля
            ИНАЧЕ НЕОПРЕДЕЛЕНО
        КОНЕЦ КАК Значение3
    ИЗ
        втПоследниеЗначения КАК втПоследниеЗначения) КАК взРезультат
23 SerGa
 
08.10.24
11:03
(15) спасибо за вариант!  Но на больших таблицах в миллион записей это будет работать супер медленно т.е.

1. В ВТ считается практически вся исходная таблица
2. В условии используется  <>, т.е. будет перебор всех миллиона строк.
3 Этот перебор будет выполнен 3 раза! т.к. 3 запроса в объединении
4. т.к. используется объединить ВСЕ в этом огромном объеие будет еще выполнен поиск различных
5. после чего будет выполена цепочка группировок.

т.е. чтобы просто найти несколько непустых значений в последних документах приходится лопатить и ворочить миллион записей и по нескольку раз!
24 osa1C
 
08.10.24
13:19
(23) Ну так ограничь выборку. Не думаю, что тебе надо за 10 лет в документах искать. Да и почему ты вообще что-то в документах собираешься искать? Ищи по регистру
25 xenos
 
09.10.24
08:43
(23)
но на больших таблицах в миллион записей

И что "миллион записей"? Допустим одна запись — килобайт,  всего гигабайт. Гигабайт в памяти — ни о чем. Если надо постоянно пользоваться, то можно создать дополнительный регистр сведений с промежуточными результатами, например, с максимальными датами когда были значения, чтобы по ним отбирать.


> 1. В ВТ считается практически вся исходная таблица

1. И это хорошо, будет в оперативной памяти.
2. Первая ВТ это просто основа, когда идет обращение к первой ВТ можно считать что напрямую к БД.

2. В условии используется  <>, т.е. будет перебор всех миллиона строк.
Альтернативы?

3 Этот перебор будет выполнен 3 раза! т.к. 3 запроса в объединении
4. т.к. используется объединить ВСЕ в этом огромном объеие будет еще выполнен поиск различных
Ну в принципе можно сделать 2 — для любого количества колонок.


5. после чего будет выполена цепочка группировок.


Бывает.
26 lEvGl
 
09.10.24
09:05
(25) похоже на собеседование, забейте
27 xenos
 
09.10.24
09:33
ВЫБРАТЬ
    АвансовыйОтчет.Дата КАК Дата,
    АвансовыйОтчет.Кратность КАК Знач1,
    АвансовыйОтчет.Курс КАК Знач2,
    АвансовыйОтчет.СуммаДокумента КАК Знач3
ПОМЕСТИТЬ втДанные
ИЗ
    Документ.АвансовыйОтчет КАК АвансовыйОтчет
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    МАКСИМУМ(ВложенныйЗапрос.ДатаЗнач1) КАК МаксДатаЗнач1,
    МАКСИМУМ(ВложенныйЗапрос.ДатаЗнач2) КАК МаксДатаЗнач2,
    МАКСИМУМ(ВложенныйЗапрос.ДатаЗнач3) КАК МаксДатаЗнач3
ПОМЕСТИТЬ втМаксДата
ИЗ
    (ВЫБРАТЬ
        ВЫБОР
            КОГДА втДанные.Знач1 = НЕОПРЕДЕЛЕНО
                ТОГДА ДАТАВРЕМЯ(1, 1, 1)
            ИНАЧЕ втДанные.Дата
        КОНЕЦ КАК ДатаЗнач1,
        ВЫБОР
            КОГДА втДанные.Знач2 = НЕОПРЕДЕЛЕНО
                ТОГДА ДАТАВРЕМЯ(1, 1, 1)
            ИНАЧЕ втДанные.Дата
        КОНЕЦ КАК ДатаЗнач2,
        ВЫБОР
            КОГДА втДанные.Знач3 = НЕОПРЕДЕЛЕНО
                ТОГДА ДАТАВРЕМЯ(1, 1, 1)
            ИНАЧЕ втДанные.Дата
        КОНЕЦ КАК ДатаЗнач3
    ИЗ
        втДанные КАК втДанные) КАК ВложенныйЗапрос
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    взДатыЗнач.МаксДатаЗнач КАК МаксДатаЗнач,
    взДатыЗнач.НомерЗначенияДаты КАК НомерЗначенияДаты
ПОМЕСТИТЬ втДатыЗнач
ИЗ
    (ВЫБРАТЬ
        втМаксДата.МаксДатаЗнач1 КАК МаксДатаЗнач,
        1 КАК НомерЗначенияДаты
    ИЗ
        втМаксДата КАК втМаксДата
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        втМаксДата.МаксДатаЗнач2,
        2
    ИЗ
        втМаксДата КАК втМаксДата
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        втМаксДата.МаксДатаЗнач3,
        3
    ИЗ
        втМаксДата КАК втМаксДата) КАК взДатыЗнач

ИНДЕКСИРОВАТЬ ПО
    МаксДатаЗнач
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    МАКСИМУМ(ВложенныйЗапрос.ПоследЗнач1) КАК ПоследЗнач1,
    МАКСИМУМ(ВложенныйЗапрос.ПоследЗнач2) КАК ПоследЗнач2,
    МАКСИМУМ(ВложенныйЗапрос.ПоследЗнач3) КАК ПоследЗнач3
ИЗ
    (ВЫБРАТЬ
        ВЫБОР
            КОГДА втДатыЗнач.НомерЗначенияДаты = 1
                ТОГДА втДанные.Знач1
            ИНАЧЕ НЕОПРЕДЕЛЕНО
        КОНЕЦ КАК ПоследЗнач1,
        ВЫБОР
            КОГДА втДатыЗнач.НомерЗначенияДаты = 2
                ТОГДА втДанные.Знач2
            ИНАЧЕ НЕОПРЕДЕЛЕНО
        КОНЕЦ КАК ПоследЗнач2,
        ВЫБОР
            КОГДА втДатыЗнач.НомерЗначенияДаты = 3
                ТОГДА втДанные.Знач3
            ИНАЧЕ НЕОПРЕДЕЛЕНО
        КОНЕЦ КАК ПоследЗнач3
    ИЗ
        втДанные КАК втДанные
            ВНУТРЕННЕЕ СОЕДИНЕНИЕ втДатыЗнач КАК втДатыЗнач
            ПО втДанные.Дата = втДатыЗнач.МаксДатаЗнач) КАК ВложенныйЗапрос
28 SerGa
 
09.10.24
14:21
(26) не собеседование.

(25) в принципе, при допущении, что вопрос производительности и лаконичности кода мы оставляем в стороне, и гигабайтом больше, гигабайтом меньше... то со всеми вашими пунктами я согласен.

поэтому пока остался при своем мнении, что через 1С запрос нормально не сделать, т.к. нет аналитических оконных функций и т.п. и реализовал как описал в (12). работает очень быстро, никаких гигабайтов и код в 15 строк.
29 RomanYS
 
09.10.24
14:27
(28) проверял (17)? Должно быть быстро.
30 SerGa
 
09.10.24
14:29
(29) так там хоть и первые 1, но в условии будет  <> пусто, а раз <> значит перебор всех миллиона строк.
31 RomanYS
 
09.10.24
14:46
(30) Это теория или практика? SQL не умеет быстро взять первый по условию?
32 RomanYS
 
09.10.24
19:44
В базе 1.5 млн проводок. Запрос выполняется 5 мс, это медленно?

"ВЫБРАТЬ ПЕРВЫЕ 1
|	Хозрасчетный.Регистратор КАК Регистратор
|ИЗ
|	РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
|ГДЕ
|	Хозрасчетный.СчетДт <> &СчетДт
|
|УПОРЯДОЧИТЬ ПО
|	Хозрасчетный.Период";
33 SerGa
 
09.10.24
15:26
(32) действительно... быстро..   надо план запроса посмотреть
34 СвинТуз
 
09.10.24
15:44
"ВЫБРАТЬ ПЕРВЫЕ 1
|    Таблица.value1 КАК Регистратор
|ИЗ
|    Таблица КАК Таблица
|Где value1 <> """"
|УПОРЯДОЧИТЬ ПО
|    Таблица.Регистратор.МоментВремени";
35 СвинТуз
 
09.10.24
15:56
ВЫБРАТЬ ПЕРВЫЕ 1
    "Комментарий" КАК НаименованиеПоля,
    ВЫРАЗИТЬ(ПередачаТоваров.Комментарий КАК СТРОКА(200)) КАК ЗначениеПоля,
    ПередачаТоваров.МоментВремени КАК МоментВремени
ИЗ
    Документ.ПередачаТоваров КАК ПередачаТоваров
ГДЕ
    (ВЫРАЗИТЬ(ПередачаТоваров.Комментарий КАК СТРОКА(200))) <> ""

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ ПЕРВЫЕ 1
    "Адрес",
    ВЫРАЗИТЬ(ПередачаТоваров.АдресДоставки КАК СТРОКА(100)),
    ПередачаТоваров.МоментВремени
ИЗ
    Документ.ПередачаТоваров КАК ПередачаТоваров
ГДЕ
    (ВЫРАЗИТЬ(ПередачаТоваров.АдресДоставки КАК СТРОКА(100))) <> ""

УПОРЯДОЧИТЬ ПО
    МоментВремени
36 СвинТуз
 
09.10.24
16:01
Если внутри секунды не надо упорядочивать,
то еще проще.
Можно одной строчкой получить. Не списком.