Шесть собственных значений получают составной тип Число/Строка после объединения двух уже созданных временных таблиц. Приведение оставляет значения нужного типа, а остальные возвращает как NULL; строка "12.50" не превращается в число.
Где и как запускать
Полный серверный общий модуль учебной базы 8.5.1.1343; свои явно типизированные источники и приватный менеджер временных таблиц. Здесь запросы в 1С не запускались; Python моделирует только фиксированные данные.
Подготовка
В отдельной учебной базе 8.5.1.1343 создайте общий модуль УчебныйЯзык: Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь. Клиентские и внешнее соединение отключены; ПовторноеИспользованиеВозвращаемыхЗначений=НеИспользовать.
Вставьте весь приведённый текст в этот общий модуль. ВыполнитьПример — экспортная точка входа; остальные процедуры и функции располагаются рядом, а не внутри неё.
В своей внешней учебной обработке создайте управляемую форму, команду Выполнить и кнопку. Клиентский обработчик Выполнить(Команда) вызывает свою процедуру ВыполнитьНаСервере(); она имеет директиву &НаСервереБезКонтекста и одну строку УчебныйЯзык.ВыполнитьПример();. Это серверный вызов общего модуля, а не разрешение клиенту прямо обращаться к серверной библиотеке.
Все товары, количества и строки придуманы в этом модуле. Запись документов, подключение к чужой базе, файлы, сеть и печать не используются. В рабочие общие модули текст не вставляйте.
HTML только показывает BSL. Код в 1С не запускался; перечисленные результаты и отрицательные опыты проверяйте самостоятельно в собственном стенде.
Полные функции создания обоих типизированных источников, проверка входов, Тип-отбора, одного значения и полного состава включены в модуль.
Никаких документов, справочников, регистров или настроек ссылок не требуется. Примитивные типы Число/Строка заданы только собственными источниками.
Процедура ВыполнитьПример() Экспорт
ЧисловойИсточник = СоздатьСвойЧисловойИсточник();
СтроковыйИсточник = СоздатьСвойСтроковыйИсточник();
ДобавитьСвоёЧисло(ЧисловойИсточник, 1, 12.50);
ДобавитьСвоёЧисло(ЧисловойИсточник, 3, 0);
ДобавитьСвоёЧисло(ЧисловойИсточник, 5, -2);
ДобавитьСвоюСтроку(СтроковыйИсточник, 2, "12.50");
ДобавитьСвоюСтроку(СтроковыйИсточник, 4, "Азбука");
ДобавитьСвоюСтроку(СтроковыйИсточник, 6, "");
ИскомыйТип = Тип("Строка");
ПроверитьСвойТипОтбора(ИскомыйТип);
Менеджер = Новый МенеджерВременныхТаблиц;
Попытка
Создание = Новый Запрос;
Создание.МенеджерВременныхТаблиц = Менеджер;
Создание.Текст = "ВЫБРАТЬ Числа.Код КАК Код, Числа.Значение КАК Значение
|ПОМЕСТИТЬ ВТСобственныеЧисла
|ИЗ &ЧисловойИсточник КАК Числа;
|ВЫБРАТЬ Строки.Код КАК Код, Строки.Значение КАК Значение
|ПОМЕСТИТЬ ВТСобственныеСтроки
|ИЗ &СтроковыйИсточник КАК Строки";
Создание.УстановитьПараметр("ЧисловойИсточник", ЧисловойИсточник);
Создание.УстановитьПараметр("СтроковыйИсточник", СтроковыйИсточник);
Создание.ВыполнитьПакет();
ОсновнойТекст = "ВЫБРАТЬ
| Смешанные.Код КАК Код,
| Смешанные.Значение КАК Значение,
| ТИПЗНАЧЕНИЯ(Смешанные.Значение) КАК ТипЗначения,
| ВЫРАЗИТЬ(Смешанные.Значение КАК ЧИСЛО(10, 2)) КАК ТолькоЧисло,
| ВЫРАЗИТЬ(Смешанные.Значение КАК СТРОКА(20)) КАК ТолькоСтрока
|ИЗ (
| ВЫБРАТЬ Числа.Код КАК Код, Числа.Значение КАК Значение
| ИЗ ВТСобственныеЧисла КАК Числа
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ Тексты.Код КАК Код, Тексты.Значение КАК Значение
| ИЗ ВТСобственныеСтроки КАК Тексты
|) КАК Смешанные";
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Менеджер;
Запрос.Текст = ОсновнойТекст + " УПОРЯДОЧИТЬ ПО Код";
ВсеЗначения = Запрос.Выполнить().Выгрузить();
Ожидание = Новый Массив;
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 1, 12.50, Тип("Число"), 12.50, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 2, "12.50", Тип("Строка"), Null, "12.50"));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 3, 0, Тип("Число"), 0, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 4, "Азбука", Тип("Строка"), Null, "Азбука"));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 5, -2, Тип("Число"), -2, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 6, "", Тип("Строка"), Null, ""));
ПроверитьПолныйСоставТипов(ВсеЗначения, Ожидание);
Запрос.Текст = ОсновнойТекст + " ГДЕ ТИПЗНАЧЕНИЯ(Смешанные.Значение) = ТИП(ЧИСЛО) УПОРЯДОЧИТЬ ПО Код";
ТолькоЧисловыеСтроки = Запрос.Выполнить().Выгрузить();
Ожидание = Новый Массив;
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 1, 12.50, Тип("Число"), 12.50, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 3, 0, Тип("Число"), 0, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 5, -2, Тип("Число"), -2, Null));
ПроверитьПолныйСоставТипов(ТолькоЧисловыеСтроки, Ожидание);
Запрос.Текст = ОсновнойТекст + " ГДЕ ТИПЗНАЧЕНИЯ(Смешанные.Значение) = &ИскомыйТип УПОРЯДОЧИТЬ ПО Код";
Запрос.УстановитьПараметр("ИскомыйТип", ИскомыйТип);
ТолькоСтроковыеСтроки = Запрос.Выполнить().Выгрузить();
Ожидание = Новый Массив;
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 2, "12.50", Тип("Строка"), Null, "12.50"));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 4, "Азбука", Тип("Строка"), Null, "Азбука"));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 6, "", Тип("Строка"), Null, ""));
ПроверитьПолныйСоставТипов(ТолькоСтроковыеСтроки, Ожидание);
НеверноеПриведение = Новый Запрос;
НеверноеПриведение.МенеджерВременныхТаблиц = Менеджер;
НеверноеПриведение.Текст = "ВЫБРАТЬ ВЫРАЗИТЬ(Смешанные.Значение КАК ДАТА) КАК НевозможнаяДата
|ИЗ (
| ВЫБРАТЬ Числа.Код КАК Код, Числа.Значение КАК Значение
| ИЗ ВТСобственныеЧисла КАК Числа
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ Тексты.Код КАК Код, Тексты.Значение КАК Значение
| ИЗ ВТСобственныеСтроки КАК Тексты
|) КАК Смешанные";
ОжидаемаяОшибкаПолучена = Ложь;
Попытка
НеверноеПриведение.Выполнить();
Исключение
ОжидаемаяОшибкаПолучена = Истина;
Сообщить("Ручной опыт: ожидаемая ошибка — ДАТА отсутствует в составе Число/Строка. " + ОписаниеОшибки());
КонецПопытки;
Если Не ОжидаемаяОшибкаПолучена Тогда
ВызватьИсключение "При ручном опыте ожидалась принципиальная невозможность приведения к ДАТА";
КонецЕсли;
Запрос.Текст = ОсновнойТекст + " УПОРЯДОЧИТЬ ПО Код";
ПослеПлохогоЗапроса = Запрос.Выполнить().Выгрузить();
Ожидание = Новый Массив;
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 1, 12.50, Тип("Число"), 12.50, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 2, "12.50", Тип("Строка"), Null, "12.50"));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 3, 0, Тип("Число"), 0, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 4, "Азбука", Тип("Строка"), Null, "Азбука"));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 5, -2, Тип("Число"), -2, Null));
Ожидание.Добавить(Новый Структура("Код,Значение,ТипЗначения,ТолькоЧисло,ТолькоСтрока", 6, "", Тип("Строка"), Null, ""));
ПроверитьПолныйСоставТипов(ПослеПлохогоЗапроса, Ожидание);
ПроверитьПолныйСоставТипов(ВсеЗначения, Ожидание);
Если ЧисловойИсточник.Количество() <> 3 Или СтроковыйИсточник.Количество() <> 3 Тогда
ВызватьИсключение "Собственные исходные таблицы изменились";
КонецЕсли;
Исключение
Менеджер.Закрыть();
ВызватьИсключение;
КонецПопытки;
Менеджер.Закрыть();
КонецПроцедуры
Функция СоздатьСвойЧисловойИсточник()
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Код", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2, 0, ДопустимыйЗнак.Неотрицательный)));
Таблица.Колонки.Добавить("Значение", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 2, ДопустимыйЗнак.Любой)));
Возврат Таблица;
КонецФункции
Функция СоздатьСвойСтроковыйИсточник()
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Код", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2, 0, ДопустимыйЗнак.Неотрицательный)));
Таблица.Колонки.Добавить("Значение", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20, ДопустимаяДлина.Переменная)));
Возврат Таблица;
КонецФункции
Процедура ПроверитьСвойКод(Код)
Если ТипЗнч(Код) <> Тип("Число") Тогда
ВызватьИсключение "Собственный код должен быть числом";
КонецЕсли;
Если Код < 1 Или Код > 6 Или Код <> Цел(Код) Тогда
ВызватьИсключение "Собственный код должен быть целым от 1 до 6";
КонецЕсли;
КонецПроцедуры
Процедура ДобавитьСвоёЧисло(Таблица, Код, Значение)
ПроверитьСвойКод(Код);
Если ТипЗнч(Значение) <> Тип("Число") Тогда
ВызватьИсключение "Числовой источник нашего опыта не принимает строки";
КонецЕсли;
Если Значение < -100 Или Значение > 100 Или Значение * 100 <> Цел(Значение * 100) Тогда
ВызватьИсключение "Собственное число должно быть от -100 до 100 с точностью до сотых";
КонецЕсли;
СтрокаИсточника = Таблица.Добавить();
СтрокаИсточника.Код = Код;
СтрокаИсточника.Значение = Значение;
КонецПроцедуры
Процедура ДобавитьСвоюСтроку(Таблица, Код, Значение)
ПроверитьСвойКод(Код);
Если ТипЗнч(Значение) <> Тип("Строка") Тогда
ВызватьИсключение "Строковый источник нашего опыта не принимает числа";
КонецЕсли;
Если СтрДлина(Значение) > 20 Тогда
ВызватьИсключение "Строка нашего источника должна быть не длиннее 20 символов";
КонецЕсли;
СтрокаИсточника = Таблица.Добавить();
СтрокаИсточника.Код = Код;
СтрокаИсточника.Значение = Значение;
КонецПроцедуры
Процедура ПроверитьСвойТипОтбора(ИскомыйТип)
Если ТипЗнч(ИскомыйТип) <> Тип("Тип") Тогда
ВызватьИсключение "Наш отбор принимает значение Тип, а не текстовое имя";
КонецЕсли;
Если ИскомыйТип <> Тип("Число") И ИскомыйТип <> Тип("Строка") Тогда
ВызватьИсключение "В нашем составном источнике предусмотрены только Число и Строка";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьОдноЗначение(Факт, Ожидание)
Если ТипЗнч(Ожидание) = Тип("Null") Тогда
Если ТипЗнч(Факт) <> Тип("Null") Тогда
ВызватьИсключение "Ожидался именно Null, а не ноль или пустая строка";
КонецЕсли;
Иначе
Если ТипЗнч(Факт) <> ТипЗнч(Ожидание) Тогда
ВызватьИсключение "Не совпал тип значения результата";
КонецЕсли;
Если Факт <> Ожидание Тогда
ВызватьИсключение "Не совпало само значение результата";
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьПолныйСоставТипов(Таблица, Ожидание)
Если Таблица.Колонки.Количество() <> 5 Или Таблица.Количество() <> Ожидание.Количество() Тогда
ВызватьИсключение "Размер своего типизированного результата не совпал";
КонецЕсли;
Если Ожидание.Количество() > 0 Тогда
Для Индекс = 0 По Ожидание.Количество() - 1 Цикл
ПроверитьОдноЗначение(Таблица[Индекс].Код, Ожидание[Индекс].Код);
ПроверитьОдноЗначение(Таблица[Индекс].Значение, Ожидание[Индекс].Значение);
ПроверитьОдноЗначение(Таблица[Индекс].ТипЗначения, Ожидание[Индекс].ТипЗначения);
ПроверитьОдноЗначение(Таблица[Индекс].ТолькоЧисло, Ожидание[Индекс].ТолькоЧисло);
ПроверитьОдноЗначение(Таблица[Индекс].ТолькоСтрока, Ожидание[Индекс].ТолькоСтрока);
КонецЦикла;
КонецЕсли;
Сообщить("Проверены пять полей, их типы и Null: строк " + Строка(Таблица.Количество()));
КонецПроцедурыРазбор по шагам
Создать отдельно типизированные внешние источники. Числа: 1/12.50,3/0,5/-2; строки: 2/"12.50",4/"Азбука",6/"". Каждый столбец каждого внешнего источника имеет только один заданный тип.
Подготовительные процедуры проверяют типы до добавления строк, коды 1..6, числовой диапазон -100..100 с точностью до сотых и строки до 20 символов. Пустая строка и числовой ноль здесь допустимые данные.
Поместить каждый внешний источник в отдельную временную таблицу собственного менеджера. В этих запросах нет объединений и соединений, как требует native INTO для внешнего источника.
Только после помещения объединить две существующие временные таблицы во вложенном источнике. Native UNIONSection прямо описывает составной тип результата при разных типах соответствующих полей.
Пара числовое 12.50 и строковое "12.50" отличается типом, хотя выглядит похожей. ТИПЗНАЧЕНИЯ возвращает значение Тип, которое проверяется наравне с остальными четырьмя полями каждой строки.
ВЫРАЗИТЬ(... КАК ЧИСЛО(10,2)) осуществим, потому что Число входит в состав исходного поля: для кодов 1,3,5 вернуть 12.50,0,-2; для строковых кодов 2,4,6 вернуть NULL.
ВЫРАЗИТЬ(... КАК СТРОКА(20)) аналогично оставляет только исходные строки. Числовое 12.50 не форматируется в строку этим приведением; для всех числовых кодов возвращается NULL.
Числовой фильтр сравнивает ТИПЗНАЧЕНИЯ с литералом ТИП(ЧИСЛО) и даёт полные строки кодов 1,3,5. Строковый фильтр передаёт значение Тип("Строка") параметром ИскомыйТип и даёт 2,4,6.
Отбор по типу не является проверкой заполненности. Ноль остаётся Числом, пустая строка остаётся Строкой; NULL результата приведения различается с ними проверкой ТипЗнч, а не сравнением с нулём.
Один отдельный намеренно плохой запрос приводит состав Число/Строка к отсутствующей ДАТА. По native query_cast это принципиально невозможное приведение, которое должно завершить выполнение ошибкой, а не вернуть всем строкам NULL.
Локальный обработчик исключения охватывает только Выполнить этого плохого запроса и показывает полученную ошибку. Создание источников, выполнение помещения и все нормальные проверки не скрываются этим обработчиком.
После ручного плохого опыта снова прочитать все шесть полных строк и прежний снимок; затем закрыть менеджер. При любой неожиданной ошибке внешний обработчик только закрывает менеджер и повторно вызывает исключение.
Как проверить результат
Для кодов 1..6 полные исходные значения и типы: 12.50/Число, "12.50"/Строка,0/Число,"Азбука"/Строка,-2/Число,""/Строка.
ТолькоЧисло по кодам 1..6: 12.50,NULL,0,NULL,-2,NULL. ТолькоСтрока: NULL,"12.50",NULL,"Азбука",NULL,"".
Числовой фильтр даёт полные строки 1,3,5; строковый 2,4,6. Каждый результат проверяется по пяти полям, типу каждого поля и точным местам NULL.
В будущей ручной 1С плохое приведение к ДАТА должно дать явную ошибку. Следующий нормальный запрос и прежний выгруженный снимок должны снова содержать весь исходный состав.
В своих дополнительных отрицательных опытах ДобавитьСвоёЧисло(...,"12.50") и ДобавитьСвоюСтроку(...,12.50) должны остановить подготовку до добавления; 0 и "" не должны отклоняться.
Ожидаемый результат
Составной результат построен способом, прямо описанным native, без предположения о загрузке внешней составной колонки. Полный состав, типы и NULL разобраны отдельно от преобразования текстовых чисел.
На что обратить внимание
Приведение к числовому типу не является парсером строк. Текст "12.50" даёт NULL в ТолькоЧисло по своему строковому типу, независимо от содержимого.
Если требуемый тип вообще отсутствует в составе выражения, native обещает ошибку, а не NULL. Эту отрицательную ветвь нельзя смешивать с несовпадающим типом одной строки допустимого составного поля.
Нативная длина СТРОКА при ВЫРАЗИТЬ ограничена максимумом 1024. Здесь задано 20 и все свои значения укладываются; усечение, округление и переполнение квалификаторов этим опытом не исследуются.
Параметр ИскомыйТип в этом модуле принимает только Число или Строка как значения Тип. Это узкий контракт нашего отбора; native допускает передачу значения ТИП параметром, а не произвольную подмену имени таблицы.
Поддержку составной колонки внешней ТаблицаЗначений этот урок не утверждает. Две внешние колонки имеют одиночные типы, состав возникает внутри объединённого результата уже существующих ВТ.
Предполагаемые ошибки и строки сообщений описывают будущий ручной опыт. Здесь запросы в 1С не запускались; Python-модель — только расчёт полностью заданных значений и типов.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.