docs(map): уточнены заголовки и добавлены образцы легенды
This commit is contained in:
1 parent
b9bcfe7230
commit
6be0442838
4 files changed
+116
-41
No files matched your search
@@ -53,11 +53,9 @@
|
|||||||
outline: 3px solid #d79078;
|
outline: 3px solid #d79078;
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
.legend { display: flex; flex-wrap: wrap; gap: 15px; color: var(--muted); }
|
.legend { display: flex; flex-wrap: wrap; gap: 8px 20px; color: var(--muted); }
|
||||||
.legend-item { display: inline-flex; align-items: center; gap: 7px; }
|
.legend-item { display: inline-flex; align-items: center; gap: 7px; }
|
||||||
.legend-line { width: 34px; border-top: 2px solid var(--line); }
|
.legend-icon { display: block; width: 50px; height: 20px; flex: none; }
|
||||||
.legend-line.dashed { border-top-style: dashed; }
|
|
||||||
.legend-line.dotted { border-top-style: dotted; }
|
|
||||||
main {
|
main {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) 370px;
|
grid-template-columns: minmax(0, 1fr) 370px;
|
||||||
@@ -71,7 +69,7 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
svg { display: block; width: 100%; min-width: 1040px; height: auto; }
|
#map { display: block; width: 100%; min-width: 1040px; height: auto; }
|
||||||
.layer-title { font-size: 15px; font-weight: 700; text-anchor: middle; }
|
.layer-title { font-size: 15px; font-weight: 700; text-anchor: middle; }
|
||||||
.layer-caption { font-size: 11px; fill: var(--muted); text-anchor: middle; }
|
.layer-caption { font-size: 11px; fill: var(--muted); text-anchor: middle; }
|
||||||
.zone-caption { font-size: 12px; fill: var(--muted); }
|
.zone-caption { font-size: 12px; fill: var(--muted); }
|
||||||
@@ -87,7 +85,7 @@
|
|||||||
.edge-line.dotted { stroke-dasharray: 2 6; stroke-linecap: round; }
|
.edge-line.dotted { stroke-dasharray: 2 6; stroke-linecap: round; }
|
||||||
.edge-hit { fill: none; stroke: transparent; stroke-width: 14; cursor: pointer; }
|
.edge-hit { fill: none; stroke: transparent; stroke-width: 14; cursor: pointer; }
|
||||||
.node { cursor: pointer; transition: opacity .15s; }
|
.node { cursor: pointer; transition: opacity .15s; }
|
||||||
.node rect {
|
.node rect, .legend-node rect {
|
||||||
fill: #f1f2f2;
|
fill: #f1f2f2;
|
||||||
stroke: #858b90;
|
stroke: #858b90;
|
||||||
stroke-width: 1.2;
|
stroke-width: 1.2;
|
||||||
@@ -130,12 +128,12 @@
|
|||||||
a { color: #8a351e; text-underline-offset: 2px; }
|
a { color: #8a351e; text-underline-offset: 2px; }
|
||||||
.hint { color: var(--muted); font-size: 13px; }
|
.hint { color: var(--muted); font-size: 13px; }
|
||||||
.edge[hidden] { display: none; }
|
.edge[hidden] { display: none; }
|
||||||
.node.student rect { stroke-dasharray: 5 3; }
|
.node.student rect, .legend-node.student rect { stroke-dasharray: 5 3; }
|
||||||
.node.student .stream-mark { fill: #875a14; }
|
.node.student .stream-mark { fill: #875a14; }
|
||||||
.edge.expected .edge-line { stroke-dasharray: 5 4; }
|
.edge.expected .edge-line, .legend-arrow.expected .edge-line { stroke-dasharray: 5 4; }
|
||||||
.node.is-upstream rect { fill: #e3eff5; stroke: #307c9a; }
|
.node.is-upstream rect, .legend-node.is-upstream rect { fill: #e3eff5; stroke: #307c9a; }
|
||||||
.node.is-downstream rect { fill: #e7f1e5; stroke: #527a43; }
|
.node.is-downstream rect, .legend-node.is-downstream rect { fill: #e7f1e5; stroke: #527a43; }
|
||||||
.node.is-selected rect { fill: var(--accent-soft); stroke: var(--accent); }
|
.node.is-selected rect, .legend-node.is-selected rect { fill: var(--accent-soft); stroke: var(--accent); }
|
||||||
.relation-button { border-radius: 5px; padding: 5px 7px; text-align: left; width: 100%; margin-top: 5px; font-size: 13px; }
|
.relation-button { border-radius: 5px; padding: 5px 7px; text-align: left; width: 100%; margin-top: 5px; font-size: 13px; }
|
||||||
.badge { font-size: 13px; padding: 3px 8px; border-radius: 4px; background: #eef1ed; display: inline-block; }
|
.badge { font-size: 13px; padding: 3px 8px; border-radius: 4px; background: #eef1ed; display: inline-block; }
|
||||||
.badge.student { background: #fff1cf; color: #775018; }
|
.badge.student { background: #fff1cf; color: #775018; }
|
||||||
@@ -155,9 +153,41 @@
|
|||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div class="switcher" id="switcher" aria-label="Вид связей"></div>
|
<div class="switcher" id="switcher" aria-label="Вид связей"></div>
|
||||||
<p id="view-hint" class="hint"></p>
|
<p id="view-hint" class="hint"></p>
|
||||||
<div class="legend" aria-label="Обозначения">
|
<div class="legend" aria-label="Обозначения стрелок">
|
||||||
<span>Сплошная рамка: готово</span><span>Пунктирная рамка: задание</span>
|
<span class="legend-item">
|
||||||
<span id="upstream-legend">Синий: источники</span><span id="downstream-legend">Зеленый: потребители</span><span>Оранжевый: выбор</span>
|
<svg class="legend-icon legend-arrow" viewBox="0 0 50 20" aria-hidden="true"><path class="edge-line" d="M 2 10 H 43"/></svg>
|
||||||
|
<span id="ready-edge-legend">Готовая загрузка</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-arrow expected" viewBox="0 0 50 20" aria-hidden="true"><path class="edge-line" d="M 2 10 H 43"/></svg>
|
||||||
|
<span id="expected-edge-legend">Загрузка по ТЗ</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-arrow is-path" viewBox="0 0 50 20" aria-hidden="true"><path class="edge-line" d="M 2 10 H 43"/></svg>
|
||||||
|
<span>Выделенные связи</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="legend" aria-label="Обозначения таблиц">
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span>Готовая таблица</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node student" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span>Учебная заглушка</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node is-upstream" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span id="upstream-legend">Источники</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node is-downstream" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span id="downstream-legend">Потребители</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node is-selected" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span>Выбранная таблица</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main>
|
<main>
|
||||||
@@ -5142,9 +5172,11 @@
|
|||||||
}
|
}
|
||||||
function renderState(message = "") {
|
function renderState(message = "") {
|
||||||
document.querySelectorAll("[data-view]").forEach(b => b.setAttribute("aria-pressed",String(b.dataset.view === state.view)));
|
document.querySelectorAll("[data-view]").forEach(b => b.setAttribute("aria-pressed",String(b.dataset.view === state.view)));
|
||||||
document.getElementById("upstream-legend").textContent = state.view === "flow" ? "Синий: источники" : "Синий: связанные родители";
|
document.getElementById("upstream-legend").textContent = state.view === "flow" ? "Источники" : "Связанные родители";
|
||||||
document.getElementById("downstream-legend").textContent = state.view === "flow" ? "Зеленый: потребители" : "Зеленый: связанные потомки";
|
document.getElementById("downstream-legend").textContent = state.view === "flow" ? "Потребители" : "Связанные потомки";
|
||||||
document.getElementById("view-hint").textContent = state.view === "flow" ? "Стрелка: откуда загрузчик читает данные и куда записывает результат. Пунктир — ожидается по ТЗ. Календарь генерируется отдельно." : "Стрелка: от родительской строки к связанным строкам. Например, от бронирования к билетам. Это не порядок загрузки и не физические FK.";
|
document.getElementById("ready-edge-legend").textContent = state.view === "flow" ? "Готовая загрузка" : "Связь по ключам";
|
||||||
|
document.getElementById("expected-edge-legend").textContent = state.view === "flow" ? "Загрузка по ТЗ" : "Связь с учебной заглушкой";
|
||||||
|
document.getElementById("view-hint").textContent = state.view === "flow" ? "Стрелка: откуда загрузчик читает данные и куда записывает результат. Календарь генерируется отдельно." : "Стрелка: от родительской строки к связанным строкам. Например, от бронирования к билетам. Это не порядок загрузки и не физические FK.";
|
||||||
if (state.selected?.type === "node") renderNodeCard(nodeById.get(state.selected.id));
|
if (state.selected?.type === "node") renderNodeCard(nodeById.get(state.selected.id));
|
||||||
else if (state.selected?.type === "edge") renderEdgeCard(edgeById.get(state.selected.id));
|
else if (state.selected?.type === "edge") renderEdgeCard(edgeById.get(state.selected.id));
|
||||||
else renderIntro(message);
|
else renderIntro(message);
|
||||||
|
|||||||
@@ -52,11 +52,9 @@
|
|||||||
outline: 3px solid #d79078;
|
outline: 3px solid #d79078;
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
.legend { display: flex; flex-wrap: wrap; gap: 15px; color: var(--muted); }
|
.legend { display: flex; flex-wrap: wrap; gap: 8px 20px; color: var(--muted); }
|
||||||
.legend-item { display: inline-flex; align-items: center; gap: 7px; }
|
.legend-item { display: inline-flex; align-items: center; gap: 7px; }
|
||||||
.legend-line { width: 34px; border-top: 2px solid var(--line); }
|
.legend-icon { display: block; width: 50px; height: 20px; flex: none; }
|
||||||
.legend-line.dashed { border-top-style: dashed; }
|
|
||||||
.legend-line.dotted { border-top-style: dotted; }
|
|
||||||
main {
|
main {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) 370px;
|
grid-template-columns: minmax(0, 1fr) 370px;
|
||||||
@@ -70,7 +68,7 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
svg { display: block; width: 100%; min-width: 1040px; height: auto; }
|
#map { display: block; width: 100%; min-width: 1040px; height: auto; }
|
||||||
.layer-title { font-size: 15px; font-weight: 700; text-anchor: middle; }
|
.layer-title { font-size: 15px; font-weight: 700; text-anchor: middle; }
|
||||||
.layer-caption { font-size: 11px; fill: var(--muted); text-anchor: middle; }
|
.layer-caption { font-size: 11px; fill: var(--muted); text-anchor: middle; }
|
||||||
.zone-caption { font-size: 12px; fill: var(--muted); }
|
.zone-caption { font-size: 12px; fill: var(--muted); }
|
||||||
@@ -86,7 +84,7 @@
|
|||||||
.edge-line.dotted { stroke-dasharray: 2 6; stroke-linecap: round; }
|
.edge-line.dotted { stroke-dasharray: 2 6; stroke-linecap: round; }
|
||||||
.edge-hit { fill: none; stroke: transparent; stroke-width: 14; cursor: pointer; }
|
.edge-hit { fill: none; stroke: transparent; stroke-width: 14; cursor: pointer; }
|
||||||
.node { cursor: pointer; transition: opacity .15s; }
|
.node { cursor: pointer; transition: opacity .15s; }
|
||||||
.node rect {
|
.node rect, .legend-node rect {
|
||||||
fill: #f1f2f2;
|
fill: #f1f2f2;
|
||||||
stroke: #858b90;
|
stroke: #858b90;
|
||||||
stroke-width: 1.2;
|
stroke-width: 1.2;
|
||||||
@@ -129,12 +127,12 @@
|
|||||||
a { color: #8a351e; text-underline-offset: 2px; }
|
a { color: #8a351e; text-underline-offset: 2px; }
|
||||||
.hint { color: var(--muted); font-size: 13px; }
|
.hint { color: var(--muted); font-size: 13px; }
|
||||||
.edge[hidden] { display: none; }
|
.edge[hidden] { display: none; }
|
||||||
.node.student rect { stroke-dasharray: 5 3; }
|
.node.student rect, .legend-node.student rect { stroke-dasharray: 5 3; }
|
||||||
.node.student .stream-mark { fill: #875a14; }
|
.node.student .stream-mark { fill: #875a14; }
|
||||||
.edge.expected .edge-line { stroke-dasharray: 5 4; }
|
.edge.expected .edge-line, .legend-arrow.expected .edge-line { stroke-dasharray: 5 4; }
|
||||||
.node.is-upstream rect { fill: #e3eff5; stroke: #307c9a; }
|
.node.is-upstream rect, .legend-node.is-upstream rect { fill: #e3eff5; stroke: #307c9a; }
|
||||||
.node.is-downstream rect { fill: #e7f1e5; stroke: #527a43; }
|
.node.is-downstream rect, .legend-node.is-downstream rect { fill: #e7f1e5; stroke: #527a43; }
|
||||||
.node.is-selected rect { fill: var(--accent-soft); stroke: var(--accent); }
|
.node.is-selected rect, .legend-node.is-selected rect { fill: var(--accent-soft); stroke: var(--accent); }
|
||||||
.relation-button { border-radius: 5px; padding: 5px 7px; text-align: left; width: 100%; margin-top: 5px; font-size: 13px; }
|
.relation-button { border-radius: 5px; padding: 5px 7px; text-align: left; width: 100%; margin-top: 5px; font-size: 13px; }
|
||||||
.badge { font-size: 13px; padding: 3px 8px; border-radius: 4px; background: #eef1ed; display: inline-block; }
|
.badge { font-size: 13px; padding: 3px 8px; border-radius: 4px; background: #eef1ed; display: inline-block; }
|
||||||
.badge.student { background: #fff1cf; color: #775018; }
|
.badge.student { background: #fff1cf; color: #775018; }
|
||||||
@@ -154,9 +152,41 @@
|
|||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div class="switcher" id="switcher" aria-label="Вид связей"></div>
|
<div class="switcher" id="switcher" aria-label="Вид связей"></div>
|
||||||
<p id="view-hint" class="hint"></p>
|
<p id="view-hint" class="hint"></p>
|
||||||
<div class="legend" aria-label="Обозначения">
|
<div class="legend" aria-label="Обозначения стрелок">
|
||||||
<span>Сплошная рамка: готово</span><span>Пунктирная рамка: задание</span>
|
<span class="legend-item">
|
||||||
<span id="upstream-legend">Синий: источники</span><span id="downstream-legend">Зеленый: потребители</span><span>Оранжевый: выбор</span>
|
<svg class="legend-icon legend-arrow" viewBox="0 0 50 20" aria-hidden="true"><path class="edge-line" d="M 2 10 H 43"/></svg>
|
||||||
|
<span id="ready-edge-legend">Готовая загрузка</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-arrow expected" viewBox="0 0 50 20" aria-hidden="true"><path class="edge-line" d="M 2 10 H 43"/></svg>
|
||||||
|
<span id="expected-edge-legend">Загрузка по ТЗ</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-arrow is-path" viewBox="0 0 50 20" aria-hidden="true"><path class="edge-line" d="M 2 10 H 43"/></svg>
|
||||||
|
<span>Выделенные связи</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="legend" aria-label="Обозначения таблиц">
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span>Готовая таблица</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node student" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span>Учебная заглушка</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node is-upstream" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span id="upstream-legend">Источники</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node is-downstream" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span id="downstream-legend">Потребители</span>
|
||||||
|
</span>
|
||||||
|
<span class="legend-item">
|
||||||
|
<svg class="legend-icon legend-node is-selected" viewBox="0 0 50 20" aria-hidden="true"><rect x="4" y="2" width="40" height="16"/></svg>
|
||||||
|
<span>Выбранная таблица</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main>
|
<main>
|
||||||
@@ -393,9 +423,11 @@
|
|||||||
}
|
}
|
||||||
function renderState(message = "") {
|
function renderState(message = "") {
|
||||||
document.querySelectorAll("[data-view]").forEach(b => b.setAttribute("aria-pressed",String(b.dataset.view === state.view)));
|
document.querySelectorAll("[data-view]").forEach(b => b.setAttribute("aria-pressed",String(b.dataset.view === state.view)));
|
||||||
document.getElementById("upstream-legend").textContent = state.view === "flow" ? "Синий: источники" : "Синий: связанные родители";
|
document.getElementById("upstream-legend").textContent = state.view === "flow" ? "Источники" : "Связанные родители";
|
||||||
document.getElementById("downstream-legend").textContent = state.view === "flow" ? "Зеленый: потребители" : "Зеленый: связанные потомки";
|
document.getElementById("downstream-legend").textContent = state.view === "flow" ? "Потребители" : "Связанные потомки";
|
||||||
document.getElementById("view-hint").textContent = state.view === "flow" ? "Стрелка: откуда загрузчик читает данные и куда записывает результат. Пунктир — ожидается по ТЗ. Календарь генерируется отдельно." : "Стрелка: от родительской строки к связанным строкам. Например, от бронирования к билетам. Это не порядок загрузки и не физические FK.";
|
document.getElementById("ready-edge-legend").textContent = state.view === "flow" ? "Готовая загрузка" : "Связь по ключам";
|
||||||
|
document.getElementById("expected-edge-legend").textContent = state.view === "flow" ? "Загрузка по ТЗ" : "Связь с учебной заглушкой";
|
||||||
|
document.getElementById("view-hint").textContent = state.view === "flow" ? "Стрелка: откуда загрузчик читает данные и куда записывает результат. Календарь генерируется отдельно." : "Стрелка: от родительской строки к связанным строкам. Например, от бронирования к билетам. Это не порядок загрузки и не физические FK.";
|
||||||
if (state.selected?.type === "node") renderNodeCard(nodeById.get(state.selected.id));
|
if (state.selected?.type === "node") renderNodeCard(nodeById.get(state.selected.id));
|
||||||
else if (state.selected?.type === "edge") renderEdgeCard(edgeById.get(state.selected.id));
|
else if (state.selected?.type === "edge") renderEdgeCard(edgeById.get(state.selected.id));
|
||||||
else renderIntro(message);
|
else renderIntro(message);
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ Docker для карты не нужны. Храните HTML рядом с ос
|
|||||||
Для связи сегмента с талоном понадобятся оба поля ключа, иначе талон
|
Для связи сегмента с талоном понадобятся оба поля ключа, иначе талон
|
||||||
первого рейса можно ошибочно присоединить ко второму.
|
первого рейса можно ошибочно присоединить ко второму.
|
||||||
|
|
||||||
## Как устроен поток целиком?
|
<a id="как-устроен-поток-целиком"></a>
|
||||||
|
|
||||||
|
## Путь данных от источника до витрин
|
||||||
|
|
||||||
Оставьте билет выбранным и переключитесь на **"Поток данных"**.
|
Оставьте билет выбранным и переключитесь на **"Поток данных"**.
|
||||||
Таблицы останутся на местах, выбранный билет сохранится; теперь стрелки
|
Таблицы останутся на местах, выбранный билет сохранится; теперь стрелки
|
||||||
@@ -86,7 +88,9 @@ Docker для карты не нужны. Храните HTML рядом с ос
|
|||||||
проверки календаря. Порядок выполнения смотрите по ссылке **"DAG · порядок задач"**
|
проверки календаря. Порядок выполнения смотрите по ссылке **"DAG · порядок задач"**
|
||||||
в карточке. Поля, SQL и проверки раскрываются там же, после выбора таблицы.
|
в карточке. Поля, SQL и проверки раскрываются там же, после выбора таблицы.
|
||||||
|
|
||||||
## Как собирается факт?
|
<a id="как-собирается-факт"></a>
|
||||||
|
|
||||||
|
## Сборка факта продаж
|
||||||
|
|
||||||
Откройте [dds.fact_flight_sales](architecture-map.html#node=dds.fact_flight_sales).
|
Откройте [dds.fact_flight_sales](architecture-map.html#node=dds.fact_flight_sales).
|
||||||
В нашем примере в нем будет **три строки**, по одной на каждый сегмент.
|
В нашем примере в нем будет **три строки**, по одной на каждый сегмент.
|
||||||
@@ -111,7 +115,9 @@ SK здесь обозначены словами: конкретные числ
|
|||||||
Нет талона - сегмент сохраняется, `seat_no` остается `NULL`, `is_boarded = false`.
|
Нет талона - сегмент сохраняется, `seat_no` остается `NULL`, `is_boarded = false`.
|
||||||
В этом стенде признак посадки означает именно наличие талона.
|
В этом стенде признак посадки означает именно наличие талона.
|
||||||
|
|
||||||
### Откуда берутся два аэропорта
|
<a id="откуда-берутся-два-аэропорта"></a>
|
||||||
|
|
||||||
|
### Аэропорты вылета и прилета
|
||||||
|
|
||||||
В карточке факта откройте связи **"Коды двух аэропортов"**,
|
В карточке факта откройте связи **"Коды двух аэропортов"**,
|
||||||
**"Аэропорт вылета"** и **"Аэропорт прилета"**:
|
**"Аэропорт вылета"** и **"Аэропорт прилета"**:
|
||||||
@@ -128,7 +134,9 @@ SK здесь обозначены словами: конкретные числ
|
|||||||
SQL использует `LEFT JOIN`, поэтому строка с таким пропуском сохранится;
|
SQL использует `LEFT JOIN`, поэтому строка с таким пропуском сохранится;
|
||||||
допустимость пропуска отдельно оценивает [DQ факта](../../sql/dds/fact_flight_sales_dq.sql).
|
допустимость пропуска отдельно оценивает [DQ факта](../../sql/dds/fact_flight_sales_dq.sql).
|
||||||
|
|
||||||
### Какая версия маршрута нужна рейсу
|
<a id="какая-версия-маршрута-нужна-рейсу"></a>
|
||||||
|
|
||||||
|
### Версия маршрута на дату рейса
|
||||||
|
|
||||||
Связь **"Версия на дату рейса"** ведет к `dds.dim_routes` по `route_bk = route_no`
|
Связь **"Версия на дату рейса"** ведет к `dds.dim_routes` по `route_bk = route_no`
|
||||||
и дате `scheduled_departure::DATE`. Дата должна попасть в полуоткрытый
|
и дате `scheduled_departure::DATE`. Дата должна попасть в полуоткрытый
|
||||||
@@ -139,7 +147,9 @@ SQL использует `LEFT JOIN`, поэтому строка с таким
|
|||||||
поиска `airplane_sk` в `dim_airplanes`. Поэтому одного заполненного справочника
|
поиска `airplane_sk` в `dim_airplanes`. Поэтому одного заполненного справочника
|
||||||
моделей недостаточно: без подходящей версии маршрута `airplane_sk` не появится.
|
моделей недостаточно: без подходящей версии маршрута `airplane_sk` не появится.
|
||||||
|
|
||||||
## Что кормит витрины?
|
<a id="что-кормит-витрины"></a>
|
||||||
|
|
||||||
|
## Агрегация фактов в витрине продаж
|
||||||
|
|
||||||
Перейдите к [dm.sales_report](architecture-map.html#node=dm.sales_report).
|
Перейдите к [dm.sales_report](architecture-map.html#node=dm.sales_report).
|
||||||
Зерно меняется: день вылета × два аэропорта × класс обслуживания.
|
Зерно меняется: день вылета × два аэропорта × класс обслуживания.
|
||||||
|
|||||||
@@ -43,8 +43,9 @@
|
|||||||
11. `LEFT JOIN dds.dim_passengers` даёт `passenger_sk`.
|
11. `LEFT JOIN dds.dim_passengers` даёт `passenger_sk`.
|
||||||
12. `LEFT JOIN ods.boarding_passes` даёт `seat_no` и признак `is_boarded`.
|
12. `LEFT JOIN ods.boarding_passes` даёт `seat_no` и признак `is_boarded`.
|
||||||
|
|
||||||
Так список связей превращается в [схему «Как собирается факт?»](db_schema.md#как-собирается-факт):
|
Этот путь разобран в разделе [«Сборка факта продаж»](db_schema.md#сборка-факта-продаж).
|
||||||
четыре обязательных входа рисуются сплошными стрелками, а остальные пунктирными.
|
На карте сплошные стрелки показывают готовые загрузки, пунктирные — ожидаемые
|
||||||
|
по ТЗ. Тип соединения и поведение при отсутствии строки описаны в карточке связи.
|
||||||
|
|
||||||
## Как проверить свой слой
|
## Как проверить свой слой
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user