Имя: Пароль:
1C
1С v8
Имющие(Having). Как реализовать виртуальную таблицу "СрезПоследних".
,
0 NikePopov
 
23.07.15
16:12
Добрый день!

Столкнулся с задачей:
Есть документ "Заявка", в котором указывается какой контрагент сколько продукции будет потреблять. При проведении документ пишет запись в регистр сведений "АктуальнаяЗаявка"(доступен СрезПоследних). Сделано это потому, что по умолчанию, завтра требуется поставить столько же продукции, сколько поставили вчера(если не было подано новой заявки).
Требуется определить, сколько материалов требуется для выпуска продукции за год. Остальные вещи описывать не буду(как устроен справочник "Спецификации", какие дополнительные реквизиты есть), так как к вопросу они не имеют отношения.

Сейчас код выглядит так:

Пока ТекущаяДата <= ДатаОкончания Цикл

    Выполняем запрос к регистру(срез последних)...
    ТекущаяДата = ТекущаяДата + День;
КонецЦикла;

Такой цикл проходит 365 или 366 раз подряд. Что вызывает 365 или 366 раз запрос, что довольно долго.

Пытаюсь составить запрос, в котором можно было бы выполнить аналогичные действия "СрезПоследних", но за один вызов.

Имея опыт работы с другими базами данных, запрос бы выглядел так:

select
dates.date, // Дата из таблицы, которую мы обрабатываем
max(requests.customer), // Измерение "Контрагент" регистра "АктуальнаяЗаявка"
max(requests.request) // Регистратор регистра "АктуальнаяЗаявка"
from
dates
  inner join requests
   on dates.date >= requests.date
group by
dates.date
having
requests.date = max(requests.date)

Проблема в том, что в конструкции "ГДЕ" нельзя использовать поля группировка "МАКСИМУМ", а в конструкции "ИМЕЮЩИЕ" нельзя использовать не группированные поля. То есть в языке запросов 1С не может ни в какой части запроса быть выражение "АктуальнаяЗаявка.Период = МАКСИМУМ(АктуальнаяЗаявка.Период)"

Кто-нибудь знает способ реализовать вариант как в обычном запросе?
1 Serginio1
 
23.07.15
16:17
2 Ёпрст
 
23.07.15
16:17
пользуй временную табличку для нахождения максимума и её пихай в имеющие
3 NikePopov
 
23.07.15
16:22
(1) У меня обратная ситуация. Я знаю, как написать запрос SQL, а вот как обратно?
(2) Есть идея для запроса? МАКСИМУМ надо взять для МоментВремени, а не для Дата! Потому что регистр по позиции регистратора! А максимум по МоментВремени взять нельзя! Уже пробовал.
4 Serginio1
 
23.07.15
16:27
(3) Можно использовать прямой запрос.
Можно использовать Top(1)
v8: Подзапросы с Выбрать Первые
Правда по сравнению с той платформой можно использовать только одно поле. Но в примере вмето

(РеализацияТоваровУслугТовары.Ссылка, РеализацияТоваровУслугТовары.НомерСтроки) В

нужно использовать просто РеализацияТоваровУслугТовары.НомерСтроки В
5 Vladal
 
23.07.15
16:28
(3) Есть такая идея. Ниже запрос. Если что лишнего - я просто выкинул шелуху, оставил только основное для понимания.

ВЫБРАТЬ
    ТоварыПТУ.Номенклатура КАК Номенклатура,
    ТоварыПТУ.Цена КАК Цена,
    ТоварыПТУ.Количество КАК Количество,
    НАЧАЛОПЕРИОДА(ТоварыПТУ.Ссылка.Дата, ДЕНЬ) КАК ДатаГТД
ПОМЕСТИТЬ ВТ_ОсновнаяВыборка
ИЗ
    Документ.ПоступлениеТоваровУслуг.Товары КАК ТоварыПТУ
ГДЕ
    ТоварыПТУ.Ссылка.Проведен
    И ТоварыПТУ.Номенклатура.КодУКТВЭД <> ЗНАЧЕНИЕ(Справочник.КлассификаторУКТВЭД.ПустаяСсылка)

ИНДЕКСИРОВАТЬ ПО
    Номенклатура
;

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

СГРУППИРОВАТЬ ПО
    ПоступлениеТоваровУслугТовары.Номенклатура
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_ОсновнаяВыборка.Номенклатура КАК Номенклатура,
    ВТ_ОсновнаяВыборка.Цена,
    ВТ_ОсновнаяВыборка.Количество,
    ВТ_ОсновнаяВыборка.ДатаГТД,
    ВТ_ПоследниеЦены.ДатаГТД КАК ДатаПоследнейЦены
ПОМЕСТИТЬ ВТ_ИтоговаяТаблица
ИЗ
    ВТ_ОсновнаяВыборка КАК ВТ_ОсновнаяВыборка
        ПОЛНОЕ СОЕДИНЕНИЕ ВТ_ПоследниеЦены КАК ВТ_ПоследниеЦены
        ПО ВТ_ОсновнаяВыборка.Номенклатура = ВТ_ПоследниеЦены.Номенклатура
            И ВТ_ОсновнаяВыборка.ДатаГТД = ВТ_ПоследниеЦены.ДатаГТД
        ПОЛНОЕ СОЕДИНЕНИЕ ВТ_СредниеЦены КАК ВТ_СредниеЦены
        ПО ВТ_ОсновнаяВыборка.Номенклатура = ВТ_СредниеЦены.Номенклатура

ИНДЕКСИРОВАТЬ ПО
    Номенклатура
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_ИтоговаяТаблица.Номенклатура КАК Номенклатура,
    ВТ_ИтоговаяТаблица.Цена,
    ВТ_ИтоговаяТаблица.Количество,
    ВТ_ИтоговаяТаблица.ДатаГТД КАК ДатаГТД,
    ВТ_ИтоговаяТаблица.ДатаПоследнейЦены
ИЗ
    ВТ_ИтоговаяТаблица КАК ВТ_ИтоговаяТаблица

УПОРЯДОЧИТЬ ПО
    Номенклатура,
    ДатаГТД
6 Serginio1
 
23.07.15
16:29
7 Vladal
 
23.07.15
16:32
(3) > У меня обратная ситуация. Я знаю, как написать запрос SQL, а вот как обратно?

Этот запрос к базе 1С или сторонней базе?
Если сторонней, то подключайся к той базе по АДО и выполняй свой запрос.

А как перевести - можешь и латинские литералы использовать, вроде select - 1С-ный язык запросов их понимает.
8 NikePopov
 
23.07.15
16:35
(7) У меня все данные в регистре сведений. Внешних данных нет. Я попытался перевести с "языка SQL" на язык запросов 1С, но либо я плохо перевел, либо у 1С не умеет работать с ИМЕЮЩИЕСЯ в полном объеме, как это возможнго с SQL.
(4) (5) (6) Пытаюсь вникнуть.
9 NikePopov
 
23.07.15
16:42
На простом примере(из головы):
Есть торги. Есть покупатели, есть номенклатуры. Победитель - тот кто предложил максимальную стоимость. Дано:

-----------------------------------------|
Клиент | Номенклатура | Предложенная цена|
-----------------------------------------|
Клиент1| Номенклатура1|10                |
Клиент2| Номенклатура1|20                |
Клиент1| Номенклатура2|30                |
Клиент2| Номенклатура2|40                |
------------------------------------------

Задача: запросом определить победителей по номенклатурам.

Ответ для SQL:
select
max(dano.client),
dano.nom AS nom ,
max(dano.price)
from
dano
group bu
nom
having
dano.client = max(dano.client)

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

-----------------------------------------|
Клиент | Номенклатура | Предложенная цена|
-----------------------------------------|
Клиент2| Номенклатура1|20                |
Клиент2| Номенклатура2|40                |
------------------------------------------

Нужен запрос для 1С...
10 Serginio1
 
23.07.15
16:47
11 DmitrO
 
23.07.15
16:55
(9)А в каком это SQL, в предложении HAVING можно использовать поля по которым не группировали?
Приведите пример с указанием конкретного сервера (языка запросов SQL). :)
12 itlikbez
 
23.07.15
17:04
(8) 1С прекрасно умеет работать с HAVING. Читайте документацию внимательно.
13 Vladal
 
23.07.15
17:17
(8) Чтобы использовать ИМЕЮЩИЕ в запросе, надо это поле сгруппировать.

Пример:
"ВЫБРАТЬ
|    ПартииТоваровНаСкладах.Склад,
|    ПартииТоваровНаСкладах.Номенклатура,
|    СУММА(ПартииТоваровНаСкладах.Количество) КАК Количество
|ИЗ
|    РегистрНакопления.ПартииТоваровНаСкладах КАК ПартииТоваровНаСкладах
|
|СГРУППИРОВАТЬ ПО
|    ПартииТоваровНаСкладах.Номенклатура,
|    ПартииТоваровНаСкладах.Склад
|
|ИМЕЮЩИЕ
|    СУММА(ПартииТоваровНаСкладах.Количество) < 0"
14 Vladal
 
23.07.15
17:19
(9) выбрать
максимум(dano.client),
dano.nom как nom,
максимум(dano.price)
из
dano
сортировать по
nom
имеющие
dano.client = максимум(dano.client)

так пройдет в твоей базе?
15 mistеr
 
23.07.15
17:47
(0) Ссылку на "срез последних на каждый день уже дали". Но для твоей задачи
> Требуется определить, сколько материалов требуется для выпуска продукции за год.

лучше использовать регистр накопления и не иметь этих проблем.
16 NikePopov
 
24.07.15
08:31
(14) в конструкции "ИМЕЮЩИЕ" недопустимо использовать поля, не входящие в группировку (для этого примера - "dano.client") (15) (15) Это вопрос архитектуры конфигурации, на которое я повлиять не могу. Я только пишу внешнюю обработку. говорить "надо снимать конфигурацию с поддержки" не имеет смысла. Ведь можно выполнять запрос в цикле на каждый день.
Ну и регистром накопления встает вопрос: кто будет туда писать данные?
Заявка - тогда вопрос, до какого периода писать туда данные? На месяц? А если завтра поменяются данные? В общем, в конфигурации сделано довольно разумно.
17 mistеr
 
24.07.15
09:01
(16) Если конфа на поддержке, тогда другое дело. Я полагал, что архитектура в твоих руках.

> Заявка - тогда вопрос, до какого периода писать туда данные? На месяц?

Ну заявка ведь на какой-то период делается?
18 NikePopov
 
24.07.15
09:10
(17) Нет. Звонит клиент и говорит, что с сегодняшнего дня мне надо 15 шт/день. Потом позвонит через два с половиной месяца скажет, что привози 18 шт/день
19 NikePopov
 
24.07.15
09:11
(17) Договор на год. Но заявка будет действовать неопределенный период.
20 Simod
 
24.07.15
10:10
(0) Пример запроса получения курса валюты на дату каждого документа выборки:

ВЫБРАТЬ
   ПоступлениеТоваровУслугТовары.Ссылка.Дата КАК Дата,
   ПоступлениеТоваровУслугТовары.Номенклатура КАК Номенклатура,
   ПоступлениеТоваровУслугТовары.Ссылка,
   ПоступлениеТоваровУслугТовары.Цена,
   КурсыВалют.Курс,
   КурсыВалют.Кратность
ИЗ
   Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
      ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
      ПО (КурсыВалют.Валюта = &Валюта)
         И (КурсыВалют.Период В
            (ВЫБРАТЬ ПЕРВЫЕ 1
               МАКСИМУМ(Т.Период)
            ИЗ
               РегистрСведений.КурсыВалют КАК Т
            ГДЕ
               Т.Валюта = &Валюта
               И Т.Период <= ПоступлениеТоваровУслугТовары.Ссылка.Дата))
21 NikePopov
 
24.07.15
10:17
(20) Отличный вариант! Я его уже пробовал, но у меня " МАКСИМУМ(Т.Период)" надо заменить на  МАКСИМУМ(Т.МоментВремени) , и тут платформа возмутилась на невозможность сравнения "строк неограниченной длинны и составных значений). Вероятнее всего, Момент времени является "составным значением"(структура Дата+НомерЗаписи). У меня регистр сведений по позиции регистратора (3) , так что использовать дату не совсем корректно. Вероятность ошибки, конечно, довольно мала. Но если вдруг получится, что этим воспользуются, то в результате будет 2 записи на одну дату.
22 Simod
 
24.07.15
10:32
(21) Т.е. надо на момент времени каждого документа?
23 Simod
 
24.07.15
10:37
(21) Какая периодичность у РС "АктуальнаяЗаявка"?
24 Serginio1
 
24.07.15
10:37
(21) Момент времени это Дата+Ссылка. То есть В
   (ВЫБРАТЬ последние 1
               Т.Период
            ИЗ
               РегистрСведений.КурсыВалют КАК Т
            ГДЕ
               Т.Валюта = &Валюта
               И Т.Период <= ПоступлениеТоваровУслугТовары.Ссылка.Дата
Сортировать По Т.Период))

Но у регистра сведений нет регистра сведений.
И ты можешь получить несколько документов на одну дату.

Опять можешь применить выбрать первые или максимум.
25 NikePopov
 
24.07.15
10:39
(22) Неа. Для каждой даты.
Пример:
Мне нужен срез последних на даты:
01.01.2015 00:00:00
02.01.2015 00:00:00
03.01.2015 00:00:00
...
29.12.2015 00:00:00
30.12.2015 00:00:00
31.12.2015 00:00:00

Возможна ситуация, при которой
Есть 2 документа:
Документ Заявка №00-00125 от 01.01.2015 15:32:15(была создана первой)
Документ Заявка №00-00126 от 01.01.2015 15:32:15(была создана второй)
При этом количество продукции на 02.01.2015 00:00:00 надо взять из "Документ Заявка №00-00126 от 01.01.2015 15:32:15", так как именно его выберет срез последних.
26 NikePopov
 
24.07.15
10:48
(23) По позиции регистратора. Прошу прощения, только заметил сообщение.
27 Simod
 
24.07.15
12:31
(26) Тогда можно заменить "Период" на "Регистрато.МоментВремени", но это не есть гуд..
28 NikePopov
 
31.07.15
09:15
(27) Нельзя. Уже определились в (21), что вариант сравнения "строк неограниченной длинны и составных значений" недопустимо.
29 Serginio1
 
31.07.15
10:47
(28) А какой у регистра курса валют МоментВремени?

Если он и есть то там не нужен максимум.
И (КурсыВалют.Регистратор В

  (ВЫБРАТЬ ПЕРВЫЕ 1
              Т.Регистратор
            ИЗ
               РегистрСведений.КурсыВалют КАК Т
            ГДЕ
               Т.Валюта = &Валюта
               И Т.Период <= ПоступлениеТоваровУслугТовары.Ссылка.Дата
УПОРЯДОЧИТЬ ПО
    Т.МоментВремени)
30 Serginio1
 
31.07.15
11:11
Или
УПОРЯДОЧИТЬ ПО
    Т.Период,Т.Регистратор
31 kittystark
 
31.07.15
12:31
может поможет ? как пример для анализа
для того, чтобы построить отчет на СКД по оборачиваемости
товаров мне нужны были конечные остатки на КАЖДЫЙ день,

идти надо не от документа, а от регистра, и обрати внимание какие регистры задействованы для ВТ Движения,
он там один, но один раз остатки, второй обороты


ВЫБРАТЬ
    0 КАК val
ПОМЕСТИТЬ tt1

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    1

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    2

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    3

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    4

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    5

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    6

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    7

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    8

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    9
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(&парамНачПериода, ДЕНЬ, tab1.val + 10 * tab2.val + 100 * tab3.val + 1000 * tab4.val) КАК Период
ПОМЕСТИТЬ ДНИ
ИЗ
    tt1 КАК tab1,
    tt1 КАК tab2,
    tt1 КАК tab3,
    tt1 КАК tab4
ГДЕ
    ДОБАВИТЬКДАТЕ(&парамНачПериода, ДЕНЬ, tab1.val + 10 * tab2.val + 100 * tab3.val + 1000 * tab4.val) <= &парамКонПериода

ИНДЕКСИРОВАТЬ ПО
    Период
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ТоварыОрганизацийОбороты.Период,
    ТоварыОрганизацийОбороты.Номенклатура,
    ТоварыОрганизацийОбороты.КоличествоОборот
ПОМЕСТИТЬ Движения
ИЗ
    РегистрНакопления.ТоварыОрганизаций.Обороты(&парамНачПериода, ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&парамКонПериода, ДЕНЬ), СЕКУНДА, 1), День, Склад В (&ОсновныеСклады)) КАК ТоварыОрганизацийОбороты

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

ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&парамНачПериода, ДЕНЬ), ДЕНЬ, -1),
    ТоварыОрганизацийОстатки.Номенклатура,
    ТоварыОрганизацийОстатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ТоварыОрганизаций.Остатки(&парамНачПериода, Склад В (&ОсновныеСклады)) КАК ТоварыОрганизацийОстатки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Дни.Период КАК Период,
    Движения.Номенклатура КАК Номенклатура,
    СУММА(Движения.КоличествоОборот) КАК КоличествоОстаток
ПОМЕСТИТЬ ОстаткиНаКонецДня
ИЗ
    ДНИ КАК Дни
        ЛЕВОЕ СОЕДИНЕНИЕ Движения КАК Движения
        ПО (Движения.Период <= Дни.Период)

СГРУППИРОВАТЬ ПО
    Дни.Период,
    Движения.Номенклатура
;
32 Serginio1
 
31.07.15
20:16
Вернее Выбрать Последние 1

или
УПОРЯДОЧИТЬ ПО
    Т.Период убыв,Т.Регистратор убыв
33 Aprobator
 
31.07.15
21:40
(0) СКД в помощь. 2 набора данных, один - требуемые даты (с производственного календаря их раз плюнуть получить). Второй - сам срез последних. Ну и связь между наборами по дате. Метода известная и довольно несложная.
34 kittystark
 
01.08.15
08:49
(33) да метода известная и один из первых отчетов на СКД по оборачиваемости сделал по ней, но отчет получился тормознутым на больших периодах, то что описано в (31) работает гораздо быстрее, а на выходе результат один и тот же
Требовать и эффективности, и гибкости от одной и той же программы — все равно, что искать очаровательную и скромную жену... по-видимому, нам следует остановиться на чем-то одном из двух. Фредерик Брукс-младший