Skip to content

Связи между таблицами ​

Когда таблицу добавляют на холст, связи по внешним ключам источника появляются сами: если в базе объявлено, что orders.customer_id ссылается на customers.customer_id, линия между таблицами уже будет. Остальные связи задаются вручную: перетащите мышью кружок рядом с полем одной таблицы на поле другой. На линии связи платформа покажет её тип — например, 1 : M.

Связи нужны, чтобы платформа знала, как соединять данные при построении виджета: например, подставить название товара из справочника к строке заказа.

Щёлкните по линии связи — в правой панели откроются её параметры:

  • Условие — какие поля сравниваются и каким оператором (=, ≠, <, >, ≤, ≥).
  • Способ связи — Relation или JOIN.
  • Кардинальность — 1 : 1, 1 : M или M : 1 (только для Relation).
  • Тип соединения — INNER JOIN, LEFT JOIN, RIGHT JOIN или FULL OUTER (только для JOIN).

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

Relation или JOIN ​

Разница не в том, какой SQL получится, а в том, проверяет ли платформа корректность агрегации.

RelationJOIN
Кардинальностьзадаётся и учитываетсяне задаётся
Проверка на задвоение сумместьнет
Когда виджет не построитсяесли связь размножает строкиникогда, ответственность на вас
Тип соединениявыбирает платформа по кардинальностизадаётся: INNER, LEFT, RIGHT, FULL OUTER

Relation — выбор по умолчанию: платформа знает, сколько строк соответствует строке, и не даст построить виджет, в котором суммы задвоятся. JOIN выполняет соединение как есть: проверки отключены целиком.

JOIN не защищает от задвоения сумм

Со связью Relation и кардинальностью 1 : M платформа отказывается строить виджет, а с тем же 1 : M, переключённым на JOIN, строит его без предупреждений. Совпали ли при этом цифры — зависит только от данных: если справочник действительно содержит дубли по ключу, выручка вырастет на пустом месте, и никакого предупреждения не будет.

Выбирайте JOIN, только если сами контролируете уровень детализации, — например, соединяете две таблицы фактов и знаете, что дублей по ключу в них нет.

Какую кардинальность выбрать ​

Кардинальность описывает, сколько строк одной таблицы соответствует строке другой, — а не то, как выглядят поля в условии. Для связи таблицы фактов со справочником (заказы → товары) правильное значение — M : 1: у одного товара много заказов, а у каждого заказа ровно один товар.

Платформа проставляет обратное значение

При перетаскивании от таблицы фактов к справочнику подставляется 1 : M. С такой настройкой виджет не построится:

Поля [products] нельзя показать вместе с мерами этого виджета: связь [orders] → [products] размножает строки — одной строке [orders] соответствует несколько строк [products], поэтому меры посчитались бы с задвоением. Проверьте кардинальность связи [orders] → [products] в схеме датасета: сейчас она говорит, что на стороне [products] несколько строк. Если строка там одна — поменяйте кардинальность. Другой вариант — убрать поля [products] из виджета.

Сообщение называет обе таблицы и предлагает два выхода: сменить кардинальность на M : 1 или убрать из виджета поля размножающей таблицы.

С 1 : 1 платформа виджет не блокирует — она считает, что строке соответствует ровно одна строка. Но не выбирайте её только ради того, чтобы виджет построился: если в справочнике окажутся дубли, суммы задвоятся, а предупреждения уже не будет.

Многие ко многим ​

Вариант M : M в интерфейсе не предлагается: одной связью такое отношение не выражается. Попытка задать его через API заканчивается отказом:

Связь many_to_many между [orders] и [products] на одном ребре не поддерживается; смоделируйте мост (две связи)

Мост — это промежуточная таблица, где каждая строка соединяет одну запись слева с одной справа. К ней ведут две обычные связи M : 1, и обе стороны остаются однозначными.

Сколько размножающих связей допускается ​

Группа мер — это набор таблиц, из которых виджет берёт меры, вместе со связями между ними: одна ветка дерева соединений. Если все меры виджета считаются по заказам, группа одна; если часть мер приходит из другой таблицы фактов, групп становится две, и платформа собирает их отдельно.

В одной группе мер допускается не более одной связи, размножающей строки. И только если её таблица служит мостом: нужна лишь для перехода и сама не участвует ни в измерениях, ни в мерах. Две такие связи и больше дадут отказ:

Обнаружено несколько связей-размножений (2) в одной группе мер (chasm trap); агрегация мер неоднозначна

Так возникает известная ошибка: две таблицы фактов, связанные с одним справочником, при соединении перемножают строки друг друга. Разносите такие меры по разным виджетам или сводите их заранее в SQL-блоке.

Таблицы из разных источников ​

Датасет собирается поверх нескольких источников, и они могут быть разных типов: таблица из PostgreSQL и таблица из ClickHouse связываются в одном датасете так же, как две таблицы одной базы. Платформа собирает такой запрос сама — в журнале обращений он помечен как федеративный.

Порядок обычный: подключите оба источника к датасету, добавьте таблицы на холст и свяжите их по общему полю.

Без связи второй источник в запрос не попадёт

Если связи нет, виджет отвечает «Нет связи между [таблица] и [таблица]», а в режиме прямого запроса поле второй таблицы вообще не находится: в план запроса попадает только главный объект. Это не особенность разных СУБД — так же ведёт себя пара таблиц одной базы.

Такой датасет работает: таблица PostgreSQL и таблица ClickHouse, связь по общему ключу, виджет с измерением из первой базы и мерой из второй — выборка строится и возвращает данные.

Что стоит помнить при таком датасете:

  • в режиме прямого запроса платформа читает обе базы и соединяет результаты у себя, поэтому объём и скорость зависят от обеих сторон;
  • в режиме извлечения обе таблицы выгружаются в витрину, и соединение выполняется уже внутри неё — материализация;
  • правила кардинальности те же: связь, размножающая строки, размножит их и здесь.

Что дальше ​

Связи определяют, как соберётся запрос. Что именно попадёт в виджеты — решает материализация и настройка полей.