Spec-Zone.ru › DuckDB

Тип объединения

Тип объединения (не путать с оператором SQL UNION) — это вложенный тип, способный хранить одно из нескольких «альтернативных» значений, подобно типу union в C. Основное отличие состоит в том, что эти UNION типы являются «мечеными объединениями» и, следовательно, всегда содержат дискриминатор — «метку», которая указывает, какую альтернативу он в данный момент хранит, даже если само внутреннее значение равно NULL. UNION типы, таким образом, более похожи на std::variant в C++17, Enum в Rust или «тип суммы», присутствующий в большинстве функциональных языков.

UNION типы всегда должны иметь хотя бы один член, и хотя они могут содержать несколько членов одного и того же типа, имена меток должны быть уникальными. UNION типы могут иметь не более 256 членов.

Внутри UNION типы реализованы на основе STRUCT типов и просто сохраняют «метку» как первый элемент.

UNION значения можно создать с помощью функции union_value(tag := expr) или путем приведения типа из члена.

Пример

Создайте таблицу со столбцом UNION:

CREATE TABLE tbl1 (u UNION(num INTEGER, str VARCHAR));
INSERT INTO tbl1 values (1), ('two'), (union_value(str := 'three'));

Любой тип может быть неявно приведён к типу объединения, содержащему этот тип. Любое UNION также может быть неявно приведено к другому типу объединения, если члены исходного UNION являются подмножеством членов целевого (если приведение однозначно).

UNION использует функции приведения типов-членов VARCHAR при приведении к VARCHAR:

SELECT u FROM tbl1;
u
1
два
три

Выберите все члены str:

SELECT union_extract(u, 'str') AS str
FROM tbl1;
str
NULL
два
три

В качестве альтернативы можно использовать «точечную запись», аналогично STRUCT.

SELECT u.str
FROM tbl1;
str
NULL
два
три

Выберите текущую активную метку из UNION как ENUM.

SELECT union_tag(u) AS t
FROM tbl1;
t
число
строка
строка

Приведения типов объединений

По сравнению с другими вложенными типами, UNION позволяют набор неявных приведений для удобного и естественного использования при работе с их членами как «подтипами». Однако эти приведения были разработаны с учетом двух принципов: избежание неоднозначности и избежание приведений, которые могут привести к потере информации. Это предотвращает, чтобы UNION были полностью «прозрачными», но все ещё позволяет UNION типам иметь «супертипное» отношение к их членам.

Таким образом, UNION типы не могут быть неявно приведены к какому-либо типу-члену в общем случае, так как информация в других членах, не соответствующих целевому типу, будет «потеряна». Если вы хотите принудительно привести UNION к одному из его членов, вы должны использовать функцию union_extract явно.

Исключением из этого правила является приведение UNION к VARCHAR, в этом случае члены будут использовать соответствующие VARCHAR приведения. Так как всё может быть приведено к VARCHAR, это «безопасно» в некотором смысле.

Приведение к типам объединений

Тип всегда можно неявно привести к типу объединения, если его можно неявно привести к одному из типов-членов UNION.

  • Если существует несколько кандидатов, встроенные правила приоритета неявных приведений определяют целевой тип. Например, приведение FLOAT → UNION(i INTEGER, v VARCHAR) всегда приводит FLOAT к члену INTEGER перед VARCHAR.
  • Если приведение по-прежнему неоднозначно, т. е. существует несколько кандидатов с одинаковым приоритетом неявного приведения, возникает ошибка. Это обычно происходит, когда UNION содержит несколько членов одного и того же типа, например, приведение FLOAT → UNION(i INTEGER, num INTEGER) всегда неоднозначно.

Итак, как мы можем устранить неоднозначность, если хотим создать UNION с несколькими членами одного и того же типа? Используя функцию union_value, которая принимает ключевой аргумент, определяющий метку. Например, union_value(num := 2::INTEGER) создаст UNION с одним членом типа INTEGER с меткой num. Это затем может быть использовано для устранения неоднозначности при явном (или неявном, см. ниже!) приведении UNION к UNION, например, CAST(union_value(b := 2) AS UNION(a INTEGER, b INTEGER)).

Приведение между типами объединений

UNION типы могут быть приведены друг к другу, если исходный тип является «подмножеством» целевого типа. Другими словами, все метки в исходном UNION должны быть присутствовать в целевом UNION, и все типы соответствующих меток должны быть неявно приводимы между исходным и целевым типами. По сути, это означает, что UNION типы являются ковариантными относительно своих членов.

Ok Исходный тип Целевой тип Комментарии
✅ UNION(a A, b B) UNION(a A, b B, c C)
✅ UNION(a A, b B) UNION(a A, b C) если B можно неявно привести к C
❌ UNION(a A, b B, c C) UNION(a A, b B)
❌ UNION(a A, b B) UNION(a A, b C) если B нельзя неявно привести к C
❌ UNION(A, B, D) UNION(A, B, C)

Сравнение и сортировка

Поскольку UNION типы реализуются на основе STRUCT типов внутри, они могут использоваться со всеми операторами сравнения, а также в предложениях `WHERE` и `ORDER BY` с той же семантикой, что и у STRUCT. «Метка» всегда хранится в качестве первого элемента структуры, что гарантирует, что UNION типы сравниваются и упорядочиваются по «метке» в первую очередь.

Функции

См. Функции объединения.

© Copyright 2018–2024 Stichting DuckDB Foundation
Licensed under the MIT License.
https://duckdb.org/docs/sql/data_types/union.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API