
- Главная
- Каталог
- Интернет технологии
- Data analysis | Анализ данных | DA
Data analysis | Анализ данных | DA
Свежая аудитория IT-специалистов, высокая вовлеченность. Обучающий авторский контент.
Аналитика Data analysis базы данных (БД), программирование, Frontend, JavaScript, HTML, CSS, Python, Java, PHP, C++, SQL, BackEnd, Windows/Linux/MacOS, DevOps, Информационная Безопасность, нейросети, QA, GameDev
Статистика канала
Допустим, что активный пользователь - это тот, кто заходит в приложение 3 и более раз в неделю.
Также у нас есть заготовленный датасет (недельный срез) с колонками:
▶️user_id - id пользователя
▶️logins_per_week - число заходов в неделю
▶️converted - поле, принимающее значение 1 или 0. 1 - совершил целевое действие за неделю, 0 - нет
🟠Что с этим делать? Можно разделить пользователей на 2 группы: активные (3+ захода в неделю) и неактивные. Потом для каждой группы найти среднее значение поля converted (процент конверсии) и сравнить проценты конверсий между собой.
В коде это будет выглядеть так:
import pandas as pd
######
#ИСТОЧНИК ДАННЫХ + СОЗДАНИЕ DF
######
df['is_active'] = df['logins_per_week'] >= 3
conv_active = df[df['is_active']]['converted'].mean()
conv_inactive = df[~df['is_active']]['converted'].mean()
print(f"Конверсия активных: {conv_active:.1%}")
print(f"Конверсия неактивных: {conv_inactive:.1%}")
print(f"{conv_active/conv_inactive:.2f}")
Предположим, что конверсия активных пользователей = 10%, неактивных = 7.5%. Отношение = 10%/7.5% = 1.33
🟠Но что дальше делать с полученным числом? Какие выводы и бизнес рекомендации можно сформулировать? Достаточно ли проведенных расчетов, чтобы доказать гипотезу? Откуда брать эту границу в "3 и более раз в неделю"? Как подготовить данные для анализа, чтобы получился такой же удобный датасет?
На эти и многие другие вопросы на примере реальных кейсов я отвечаю в курсе "Практический анализ данных на SQL и Python" - https://stepik.org/a/269469
Проконсультирую по материалам курса, помогу решить и объяснить сложные задачи и отвечу на все вопросы. Можете связаться со мной через обратную связь на Stepik или же написать напрямую в тг - @connection_07
Метод Монте-Карло используется тогда, когда нужно численно изучать случайные процессы. Представляет собой генерацию случайных величин для достижения определенных аналитических целей.
Довольно часто применяется в практической аналитике при оценке рисков, финансовом моделировании и прогнозировании.
🟠Допустим, нужно оценить квартальную выручку. У нас есть три фактора с неопределённостью: количество клиентов, процент конверсии и средний чек.
Самый простой и наглядный вариант рандомизации будет выглядеть так:
import numpy as np
np.random.seed(42)
N_SIM = 100000
traffic = np.random.normal(loc=100000, scale=15000, size=N_SIM)
conversion = np.random.normal(loc=0.02, scale=0.005, size=N_SIM)
avg_check = np.random.normal(loc=2000, scale=300, size=N_SIM)
revenue = traffic * conversion * avg_check
print(f"Прогноз выручки: {revenue.mean():,.0f} ₽")
То есть мы ожидаем, что клиентов будет в среднем 100 тыс., конверсия будет в среднем 2%, а чек будет в среднем 2 тыс. (параметр loc). Это всё устанавливается вручную, так же как и величина разброса от среднего (scale) и количество повторений (N_SIM = 100000).
Также в этом варианте задаётся, что случайные числа в установленных пределах будут генерироваться по нормальному распределению.
В конце эти 3 показателя перемножаются между собой, и среднее из всех этих 100 000 произведений и есть прогноз выручки на следующий квартал.
🟠Но вообще вся эта рандомизация используется не для того, чтобы найти среднее значение n-ого кол-ва воспроизведений. Это нужно для того, чтобы оценивать вероятности.
В нашем случае можно задать порог выручки, например, 4 млн:
print(f"{(revenue < 4000000).mean():.1%}")
и получить вероятность того, что она окажется в итоге меньше 4 млн, в 53.6%. Если поставить порог в 5 млн, то можно получить вероятность 78.9%, и т.д.
🟠Также еще будет полезно узнать доверительный интервал прогноза:
print(f"[{np.percentile(revenue, 5):,.0f}, {np.percentile(revenue, 95):,.0f}]")
Для примера возьмем 5-ый и 95-ый перцентили. Это будет говорить о том, что в 90% случаев выручка будет находится в таком-то диапазоне значений.
🟠Но откуда нам знать, сколько именно повторений проводить, какое должно быть распределение и какие устанавливать параметры loc и scale?
Число повторений должно быть как можно больше, от этого результаты становятся более точнее. Но также нужно учитывать вычислительные мощности и не брать слишком уж большие числа. Обычно выбирают 100 000, т.к. оно считается за секунду и достаточно точно определяет все остальные значения.
Значения loc и scale можно брать из прошлых данных или, если таковых нет, то можно использовать сторонние наиболее релевантные источники.
Что касательно типа распределения, то оно выбирается в зависимости от контекста значения.
Нормальное распределение используется в случаях, когда данные распределены симметрично, в форме колокола. Это легко проверить визуально, просто построив гистограмму. В нашем случае под нормальное распределение скорее всего попадет значение кол-ва посетителей, т.к. это большое число и скорее всего имеет симметричный разброс вокруг среднего.
Помимо нормального распределения используются еще:
▶️Логнормальное распределение. Используется для тех данных, которые скошены вправо. Например, в нашем случае под логнормальное распределение хорошо попадает сумма чека, т.к. часто они небольшие, но есть редкие крупные заказы.
▶️Бета распределение. Используется для процентов и долей. Например, значение конверсии (%) в нашем случае лучше было бы считать по бета распределению.
▶️Равномерное распределение. Используется по умолчанию, когда нет возможности получить информацию о форме распределения.
Один из довольно часто встречающихся на практике кейсов - сегментация пользователей (или RFM-анализ). Цель анализа - разделить клиентов на группы (сегменты), чтобы понять, кто из них самый ценный, кто требует внимания, а кого, возможно, уже не вернуть.
Осуществляется на основе:
▶️Recency — когда последний раз покупал?
▶️Frequency — сколько раз покупал?
▶️Monetary — сколько потратил?
Базовый запрос выглядит так:
WITH clients as (
SELECT
customer_id,
CURRENT_DATE - MAX(order_date) AS recency_days,
COUNT(order_id) AS frequency,
SUM(price) AS monetary_value
FROM orders
GROUP BY customer_id)
Из таблицы заказов считается разница между сегодняшним числом (или отчетной датой) и датой последнего заказа, а также считается число заказов и их сумма в разрезе каждого клиента.
Далее подключается скоринговая модель. Основной смысл таков: разбить клиентов на 5 квантилей и на основании этих 3 показателей присвоить им рейтинги. Для Recency ценятся наиболее свежие даты, а для Frequency и Monetary - чем больше, тем лучше.
Используем оконную функцию NTILE(5), которая делит клиентов на 5 равных частей:
SELECT
customer_id,
NTILE(5) OVER (ORDER BY recency_days) AS r_score,
NTILE(5) OVER (ORDER BY frequency DESC) AS f_score,
NTILE(5) OVER (ORDER BY monetary_value DESC) AS m_score
FROM clients
На выходе получится сгруппированная ранее таблица клиентов, к которой добавится 3 столбца, в каждом из которых будет число от 1 до 5 - это будет рейтинг клиента.
С этими рейтингами можно поступать по-разному. Можно всё агрегировать в единый итоговый 15-балльный рейтинг, а можно оставить как есть и смотреть рейтинги в разрезе 3 показателей - тут зависит от целей.
Допустим, у нас есть данные из бухгалтерского баланса, представленные иерархически:
▶️Активы ➡️ Дебиторская задолженность
▶️Активы ➡️ Денежные средства ➡️ Касса
▶️Активы ➡️ Денежные средства ➡️ Расчётные счета
🟠Если представлять это в виде таблицы, то такая таблица имела бы поля:
— account_id - id статьи
— name - наименование статьи (активы, ден. ср-ва, касса и т.д.)
— parent_id - id родительской статьи. Например, если у статьи "Активы" account_id = 1, то у статьи "Денежные средства":
parent_id = account_id ("Активы") = 1
потому что "Денежные средства" - это вид статьи "Активы", стоящий на 1 ступень ниже.
Аналогично будет и со статьей "Касса". Если у "Денежные средства" account_id = 2, то у статьи "Касса":
parent_id = account_id ("Денежные средства") = 2
Вообще, если брать в расчет банковский контекст, то для таких данных, связанных с фин. отчетностью, наиболее часто пишутся иерархические скрипты.
🟠На примере этих данных разберемся, как можно работать с иерархиями. Строятся они в оркале с помощью такого синтаксиса:
SELECT
account_id,
name,
parent_id,
LEVEL
FROM accounts
START WITH parent_id IS NULL
CONNECT BY PRIOR account_id = parent_id
ORDER SIBLINGS BY name
где:
▶️LEVEL - уровень иерархии. Для статьи "Активы" он = 1, для статьи "Денежные средства" он = 2 и т.д.
▶️START WITH parent_id IS NULL. Говорит о том, что бы иерархия начинала строиться с той статьи, у которой parent_id IS NULL. То есть выбирается статья "Активы", т.к. у нее нет родительского id, потому что это самая "старшая" статья. И далее идет parent_id =1, потом 2 и т.д.
▶️CONNECT BY PRIOR account_id = parent_id - строка, с которой начинается именно само построение иерархии. Она берет account_id из родителя и ищет строки, где parent_id равен этому значению.
Возвращаясь к нашему примеру, начинается всё со статьи "Активы", которая была выбрана в прошлом шаге. У нее account_id = 1. И потом ищутся те статьи, у которых parent_id тоже равен 1.
▶️ORDER SIBLINGS BY name. Обычный ORDER BY не работает в иерархических запросах - только ORDER SIBLINGS BY. Это означает, что внутри каждой родительской группы дочерние значения сортируются по порядку/алфавиту.
То есть, если брать группу "Денежные средства", то дочерние значения в ней - "Касса" и "Расчётные счета". И именно они сортируются по алфавиту.
🟠На выходе после такого скрипта получится таблица, упорядоченная по иерархии сверху-вниз + с доп. полем LEVEL
🟠Дополнительно к запросу можно добавить еще:
CONNECT BY NOCYCLE PRIOR
account_id = parent_id
С помощью этого можно избежать зацикливания, если, например, по ошибке было указано, что "Расчётные счета" являются подкатегорией "Денежных средств", а потом "Денежные средства" - подкатегорией "Расчётных счетов".
В этом случае NOCYCLE пометит такие записи и пойдет дальше. Чтобы увидеть помеченные строки, в SELECT нужно дополнительно прописать поле CONNECT_BY_ISCYCLE.
Если же NOCYCLE не писать, оракл выдаст ошибку.
SELECT
LPAD(' ', (LEVEL - 1) * 2) || name
AS tree_name,
Добавление этой строки в селект позволит визуализировать иерархическое дерево, а не выводить его в виде обычной таблицы.
Допустим, у нас есть гипотеза: "Клиенты, получающие зарплату на счёт в банке, в n раз чаще открывают вклады, чем остальные".
И есть собранная из БД аналитическая витрина с полями:
▶️client_id - айди клиента
▶️salary_client - был ли клиент когда-либо зарплатным (да/нет)?
▶️any_deposit - открывал ли клиент хотя бы 1 вклад (да/нет)?
▶️during_salary - открыт ли хотя бы 1 вклад в то время, когда клиент был зарплатным (да/нет)? NULL - если клиент не был зарплатным.
Проверяются подобные гипотезы через сравнение пропорций (z-тест).
Алгоритм таков:
1️⃣Сначала надо разделить клиентов на 2 группы (зарплатные и незарплатные). То есть просто считаем кол-во да/нет в поле salary_client:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from statsmodels.stats.proportion import proportions_ztest
######
#ИСТОЧНИК ДАННЫХ + СОЗДАНИЕ DF
######
group_counts = df['salary_client'].value_counts()
print(group_counts)
2️⃣Затем найти процент тех, кто открыл вклад в каждой группе. Для зарплатных клиентов надо найти соотношение
during_salary (да) /salary_client (да)
Для незарплатных:
any_deposit (да) / salary_client (нет)
На питоне это выглядит так:
salary_group = df[df['salary_client'] == 'да']
non_salary_group = df[df['salary_client'] == 'нет']
salary_deposit_rate = (salary_group['during_salary']
== 'да').mean()
non_salary_deposit_rate = (non_salary_group['any_deposit']
== 'да').mean()
print(salary_deposit_rate)
print(non_salary_deposit_rate)
3️⃣И далее уже подключается статистика: нужно посчитать P-value, чтобы убедиться в стат значимости.
salary_count = len(salary_group)
salary_deposit_count = (salary_group['during_salary']
== 'да').sum()
non_salary_count = len(non_salary_group)
non_salary_deposit_count = (non_salary_group['any_deposit']
== 'да').sum()
c1 = np.array([salary_deposit_count, non_salary_deposit_count])
c2 = np.array([salary_count, non_salary_count])
stat, pval = proportions_ztest(c1, c2, alternative='larger')
print(f"p-value: {pval}")
🟠Теперь что касательно интерпретации результатов. Если мы выяснили в п.2, что доля клиентов как-то заметно отличается (например, 55% против 25%), то имеет смысл считать p-value, потому что разница ощутима и надо проверить, не случайность ли это.
Если p-value > 0.05, то такая разница может быть случайной и нет смысла на этом заострять внимание. Если p-value < 0.05, то, следовательно, всё наоборот.
Вспомнил про недавно проведенный корреляционный анализ и подумал, что уместно было бы раскрыть тему причинно-следственных связей. Ведь на первый взгляд это всё взаимосвязано и одно вытекает из другого, но на деле не всё так просто.
Та гипотеза звучала так: "Чем больше средний баланс клиента, тем больше его суммарные расходы". И действительно, проведя корреляционный анализ, мы могли обнаружить эту связь. Но по факту это просто 2 "сухих" показателя, которые могут двигаться в одном направлении с примерно одинаковой скоростью.
И не понятно, действительно ли из-за роста баланса люди начинают тратить больше? Или увеличивающиеся траты - предвестник увеличения баланса? Или же вообще есть сторонние факторы, которые если исчезнут, то эта корреляционная связь пропадёт?
🟠И раз возникает столько вопросов, то зачем тогда нужен корреляционный анализ?
▶️Его в основном используют как один из этапов разведочного анализа, что бы показать, что связь в принципе существует и что надо копать глубже.
▶️Еще он бывает полезен при прогнозировании, потому что в прогнозах само наличие какой-то устойчивой связи ценится высоко.
▶️Бывает, что корреляции помогают замечать аномалии. Если вдруг связь нарушается, то это может означать какое-то неприятное событие: сбой, мошенничество, изменение поведения и т.д.
🟠Теперь о том, как проверить причинно-следственные связи. Несколько самых релевантных способов:
▶️Самый простой и интуитивный способ - это посмотреть на даты в датасете. Если баланс вырос до того, как увеличились траты - значит, баланс влияет на траты. Если наоборот - значит, траты влияют на баланс.
Но есть одно но. Временная последовательность - это ещё не доказательство причинности. Оба события могли быть вызваны 3 фактором, который произошёл раньше.
Например, баланс мог вырасти из-за увеличения дохода. То есть по вполне естественным причинам. И клиент стал больше тратить. Но стал больше тратить не из-за роста баланса, а из-за роста своего дохода.
Если же убрать естественный фактор и заменить его искусственным, то есть просто начислить ни с того ни с сего бонусы на баланс, то увеличение баланса в этом случае может не гарантировать рост трат, потому что клиент может решить сэкономить деньги. В этом случае связь баланс - расходы нарушится, поэтому надо учитывать дополнительные факторы.
▶️И вот мы плавно подошли ко второму способу - эксперименты. Чтобы убедиться в том, что связь действительно устойчива и не зависит ни от чего еще, можно провести А/Б тесты - т.е. одной случайной группе бонусами баланс завысить, а другую оставить как есть, и сравнить результаты.
Если первая группа будет больше тратить, то связь и правда есть и не зависит ни от чего больше. Если же нет, то надо искать другие факторы.
▶️Но бывает, когда нет возможности проводить такие эксперименты. В этой ситуации помогает метод Difference-in-Differences. Он может использоваться и внутри А/Б теста, и как отдельный подход.
Суть в том, что сравниваются уже не случайные экспериментальные данные, а реальные кейсы. Например, одной группе клиентов банк по какой-то бизнесовой логике начислил бонусы на баланс (не из-за эксперимента), а другой - нет. И надо оценить, сравнив эти 2 группы, насколько это сильное влияние.
▶️Есть еще регрессия с контролем ковариат - это самый логичный шаг сразу после проведения корреляционного анализа. И хоть это не покажет причинность, но уже будет ближе к ней, чем простая корреляция.
Идея в следующем. Вот мы нашли связь баланс - траты. После этого нужно взять клиентов с одинаковыми признаками (пол, возраст, город, доход...), но с разным балансом. И внутри этой группы посмотреть, действительно ли клиенты, которые схожи по всему, кроме баланса, имеют тенденцию к увеличению трат по мере его роста?
Если связь между балансом и тратами еще есть, значит, баланс влияет на поведение. Если связь ослабла, значит, дело не в балансе, а в чем-то еще.
Но есть минус - регрессия контролирует только те факторы, которые уже есть в данных.
Data Mesh - относительно новое понятие в управлении данными, которое используется как альтернатива традиционным DWH.
🟠Главный акцент тут - на децентрализованности. В классическом подходе хранилища данных обслуживает какая-то конкретная специализированная на этом команда. Она, как правило, извлекает данные из источников, трансформирует их и загружает в DWH, которым потом пользуются разные отделы в компании.
При таком подходе существуют свои недостатки. Например, при увеличении объема данных нагрузка на команду DWH так же увеличивается, что приводит либо к росту издержек, либо к снижению скорости обработки, либо к снижению качества и т.д. Также инженеры могут находиться в отрыве от всех бизнесовых контекстов и тонкостей и заниматься только техническими вопросами, что может приводить к неточностям.
🟠Подход Data Mesh решает эти недостатки тем, что смещает фокус обслуживания только лишь с 1 команды на все отделы в компании. Условно, продуктовые отделы, отделы маркетинга и финансов теперь сами отвечают за размещение и поддержку тех данных, которыми они пользуются или которые они производят.
И хоть идея подхода звучит красиво, на деле имеет множество недостатков:
Во-первых, чтобы это было оправданно, компания должна быть реально большой, иначе затраты и усилия по созданию и поддержке такой архитектуры будут слишком велики.
Во-вторых, в разных отделах теперь будут нужны сотрудники, которые одновременно и технически подкованы, чтобы управлять данными своего отдела, и разбираются в бизнес-контексте своих данных.
В-третьих, нужна отличная согласованность между разными отделами в компании, чтобы данные в итоге получались едиными и чтоб не выходило так, что у каждой команды свой формат данных.
Ну и также, скорее всего, нужно будет возиться с доступами. И вероятнее всего могут возникнуть проблемы при миграции уже существующих данных с традиционного DWH в Data Mesh.
🟠Но а в целом, если решить все эти вопросы, то Data Mesh даст преимущества в виде:
▶️Масштабируемости, потому каждый новый домен добавляется автономно
▶️Качества, скорости и актуальности данных, потому что за каждыми данными будет стоять своя компетентная команда
▶️Гибкости, потому что под данные можно будет выбирать не только, например, традиционные СУБД, а перемешивать и NoSQL, и Data Lake, и колоночные СУБД и т.д. Главное, чтоб это было согласованно.
Эволюция схемы - это способность системы адаптировать структуру данных (таблицы, поля, типы) под новые требования без потери работоспособности всего того, что зависит от бд.
Применяется в случаях, когда:
▶️Нужно добавить или удалить столбцы
▶️Нужно изменить тип данных
▶️Меняется допустимость наличия NULL в полях
▶️Меняется значение по умолчанию
▶️Изменяются или добавляются ключи
▶️При денормализации / нормализации таблиц
▶️Нужно переименовывать поля и т.д.
🟠В чем суть Schema Evolution?
Главный принцип - в плавном изменении текущей версии БД под новые реалии таким образом, чтобы не было сбоев. Для этого могут применяться разные методы.
Например, если мы собираемся удалить поле из таблицы, то его нужно отметить, затем разорвать с ним все зависимости (например, в скриптах), всё протестировать и уже только потом удалить.
Если речь идет об изменении типа данных в отдельных столбцах, то нужно протестировать миграцию, перенести данные в столбцы с новым форматом, проверить связи и только потом удалить всё ненужное.
Еще как пример можно привести глобальную перестройку БД. В этом случае активно используются реплики. До тех пор, пока все процессы не перенесены на новую БД, старая поддерживается в рабочем состоянии.
🟠Технически эволюция схемы реализуется следующим образом:
1️⃣Сначала необходимо спроектировать изменения, а именно понять, какие запросы, процедуры, отчеты и т.п. затронет изменение, то есть выявить связи
2️⃣Затем непосредственно написать сам DML/DDL-скрипт с INSERT / UPDATE / ALTER / DELETE и т.п.
3️⃣Протестировать где-нибудь в безопасной среде, например, на реплике или в песочнице
4️⃣После теста уже применить скрипт для основных данных
5️⃣В конце нужно не забыть удалить временные объекты и обновить документацию
В SQL конструкция FILTER используется для условной агрегации. Она позволяет применять агрегатные функции (такие как SUM, COUNT, AVG, MAX и т.д.) только к тем строкам, которые удовлетворяют определенному условию, не затрагивая остальные строки в выборке.
И тут сразу вспоминаются функции HAVING и WHERE, которые на первый взгляд могут делать то же самое. Но всё же между ними есть отличия:
▶️WHERE: Фильтрует строки до группировки и агрегации. Если строка не прошла WHERE, она не участвует ни в одной агрегации в этом запросе.
▶️HAVING: Фильтрует результаты группировки. Используется после GROUP BY.
▶️FILTER: Фильтрует строки только для конкретной агрегатной функции. Другие агрегатные функции в том же SELECT видят все строки.
🟠Вообще, FILTER используется как более лаконичная и читаемая замена конструкции CASE WHEN.
Для примера представим, что необходимо посчитать общую сумму продаж и сумму только оплаченных заказов:
SELECT
user_id,
SUM(amount) AS total_amount,
SUM(amount) FILTER
(WHERE status = 'paid') AS paid_amount
FROM orders
GROUP BY user_id
Это то же самое, что и:
SELECT
user_id,
SUM(amount) AS total_amount,
SUM(CASE WHEN status = 'paid'
THEN amount ELSE 0 END)
AS paid_amount
FROM orders
GROUP BY user_id
То есть для обоих случаев выведутся 2 столбца в разрезе user_id: в первом будет содержаться общая сумма всех заказов, во втором - сумма заказов только со статусом 'paid'.
🟠В заключение стоит отметить, что FILTER поддерживается в PostgreSQL и постепенно начинает появляться в новых версиях в Microsoft и Oracle (но в MySQL её еще нет).
Data Vault - это один из видов архитектуры базы данных (альтернатива "звездочке", "снежинке" и т.п.). Включает в себя такие элементы, как:
▶️Hub - таблицы, содержащие бизнес ключи. Здесь хранятся разные id и номера.
▶️Satellite - таблицы, содержащие основную информацию по атрибутам.
▶️Link - таблицы, показывающие, как id и номера из хабов связаны между собой.
🟠Теперь о том, как это всё работает на практике. Предположим, у нас есть данные о транзакциях, которые надо организовать в виде Data Vault. Данные содержат информацию о том, кто что покупал? У кого покупал? Сколько покупал? И т.п.
1️⃣Начать можно с hub-таблиц. Там будет информация конкретно по каждому id.
То есть отдельно создается таблица под customer_id, которая помимо customer_id будет содержать разную техническую информацию: hash, дату загрузки, источник и т.п. И такие таблицы создаются отдельно для каждого вида id или номера: transaction_id, merchant_id, account_number и т.д.
2️⃣В satellite-таблицах раскрывается вся полезная информация, которая описывает сами сущности.
То есть, если брать информацию о клиентах, то в таких таблицах вместе с customer_id будут содержаться данные о e-mail, телефонах, ФИО, адресе, сегменте и т.п. Также там можно хранить историю изменений, введя дополнительные поля с датами.
Как и с hub-таблицами, отдельно под каждую сущность (клиенты, счета, транзакции...), как правило, создается своя satellite-таблица.
3️⃣Link-таблицы нужны для связи айдишников между собой. Например, вполне реальна ситуация, когда клиент может владеть несколькими счетами. Для правильного отображения этих множественных связей создается таблица с полями customer_id и account_number.
Если же нужно связать номер счета с номером транзакции, то создается таблица с полями account_number и transaction_id, и далее по аналогии.
Изредка возможен еще вариант link-таблицы, в которой есть связь более чем 2 атрибутов. Например, customer_id, account_number и transaction_id можно объединить в одну таблицу, потому что клиент может владеть несколькими счетами, а с каждого отдельного счета, в свою очередь, может совершаться множество транзакций.
🟠Также стоит отметить, что, говоря про разные айди в satellite-таблицах и в link-таблицах, я немного упрощаю. Эти таблицы для соблюдения всех правил data vault должны обязательно содержать информацию о хэше этих id, которые в конечном итоге приведут к hub-таблицам.
То есть link-таблицы связывают между собой не id, а hub-таблицы. Так же как и satellite-таблицы: они детально раскрывают информацию не по абстрактным id, а по сущностям именно из хабов.
Отзывы канала
всего 2 отзыва
- Добавлен: Сначала новые
- Добавлен: Сначала старые
- Оценка: По убыванию
- Оценка: По возрастанию
Каталог Телеграм-каналов для нативных размещений
Data analysis | Анализ данных | DA — это Telegam канал в категории «Интернет технологии», который предлагает эффективные форматы для размещения рекламных постов в Телеграмме. Количество подписчиков канала в 1.7K и качественный контент помогают брендам привлекать внимание аудитории и увеличивать охват. Рейтинг канала составляет 25.3, количество отзывов – 2, со средней оценкой 5.0.
Вы можете запустить рекламную кампанию через сервис Telega.in, выбрав удобный формат размещения. Платформа обеспечивает прозрачные условия сотрудничества и предоставляет детальную аналитику. Стоимость размещения составляет 3776.22 ₽, а за 12 выполненных заявок канал зарекомендовал себя как надежный партнер для рекламы в TG. Размещайте интеграции уже сегодня и привлекайте новых клиентов вместе с Telega.in!
Вы снова сможете добавить каналы в корзину из каталога
Комментарий