Моделирование алгебраических типов данных с использованием реляционной базы данных

Допустим, вы пишете приложение на OCaml/F#/SML/Haskell и хотите сохранить данные в реляционной базе данных. Типы продуктов (записи и кортежи) легко сопоставить с отношениями, но как сопоставить типы вариантов с отношениями?

Чтобы быть конкретным, как бы вы сохранили тип, подобный следующему, в реляционной базе данных?

(* OCaml *)
type t = 
  | Foo
  | Bar of string
  | Baz of int * int * int

person Vladimir Keleshev    schedule 19.10.2015    source источник
comment
Не могли бы вы привести пример реальных данных, которые вы, возможно, захотите сохранить?   -  person Shnugo    schedule 19.10.2015
comment
Моей первой идеей будет XML. Вы можете хранить любые иерархически структурированные данные вместе с описательными метаданными (атрибутами). Но вам понадобится высокая логика, чтобы интерпретировать это...   -  person Shnugo    schedule 19.10.2015
comment
@shnugo Как я уже упоминал, меня интересуют реляционные базы данных.   -  person Vladimir Keleshev    schedule 02.11.2015
comment
Привет, вы не упомянули, какую СУБД вы хотели бы использовать. Я использую SQL Server. Существуют невероятные возможности использования XML внутри реляционной схемы базы данных. Просто определите столбец XML как часть таблицы и поместите туда буквально любые данные, которые вы хотите. При этом вы можете сочетать сильные стороны СУБД с гибкостью XML. Это была просто мысль...   -  person Shnugo    schedule 02.11.2015
comment
blog.typeable.io/posts/2019-11- 21-sql-sum-types.html   -  person A-Developer-Has-No-Name    schedule 26.10.2020


Ответы (1)


Это кажется утомительным, но я бы создал таблицу для каждого продукта в сумме.

CREATE TABLE foo (id uuid PRIMARY KEY);

CREATE TABLE bar (id uuid PRIMARY KEY,
                  s  text NOT NULL);

CREATE TABLE baz (id uuid PRIMARY KEY,
                  a  integer NOT NULL,
                  b  integer NOT NULL,
                  c  integer NOT NULL);

Вероятно, вы захотите хранить некоторые метаданные вместе с записями каждого типа:

CREATE TABLE envelope (id uuid PRIMARY KEY,
                       t  timestamptz NOT NULL DEFAULT now(),
                       by text NOT NULL DEFAULT sessions_user);

И это предполагает ограничение внешнего ключа:

CREATE TABLE foo (id uuid PRIMARY KEY REFERENCES envelope);

CREATE TABLE bar (id uuid PRIMARY KEY REFERENCES envelope,
                  s  text NOT NULL);

CREATE TABLE baz (id uuid PRIMARY KEY REFERENCES envelope,
                  a  integer NOT NULL,
                  b  integer NOT NULL,
                  c  integer NOT NULL);

И если вы еще более строги, вы можете представить себе сохранение столбца ty с именем типа и использование его для создания составного внешнего ключа. (Как описано в разделе Где не следует использовать наследование таблиц в блоге LedgerSMB.)

person solidsnack    schedule 07.02.2016
comment
В последнее время я больше думал об этом, и у меня есть схема, включающая промежуточную таблицу, которая служит целью внешнего ключа. Некоторый пример кода можно найти здесь: github.com/solidsnack/pg-sql-variants - person solidsnack; 13.05.2016
comment
Как мне сохранить ссылку на t? - person nafg; 17.07.2017
comment
Сохраните ссылку на конверт. - person solidsnack; 17.07.2017
comment
Что-нибудь редактировалось? Я не могу понять свой собственный вопрос ;) - person nafg; 26.07.2017