db: ClickHouse manar database — 11 analytical tables

This commit is contained in:
2026-05-06 15:42:03 +00:00
parent a8bc9d6d08
commit e633f41f61
+212
View File
@@ -0,0 +1,212 @@
-- ClickHouse: manar database + analytical tables
-- Run against existing ClickHouse container
-- All tables partitioned by brand_id for multi-tenant isolation
CREATE DATABASE IF NOT EXISTS manar;
-- ── Ad Metrics Hourly ────────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.ad_metrics_hourly (
brand_id String,
platform String,
account_id String,
campaign_id String,
campaign_name String,
adgroup_id String,
adgroup_name String,
hour DateTime,
date Date,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64,
conv_value Float64,
video_views UInt64,
ctr Float64 MATERIALIZED if(impressions > 0, clicks / impressions, 0),
cpc_micros UInt64 MATERIALIZED if(clicks > 0, cost_micros / clicks, 0),
roas Float64 MATERIALIZED if(cost_micros > 0, conv_value / (cost_micros / 1000000), 0)
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, platform, account_id, campaign_id, hour)
TTL date + INTERVAL 2 YEAR;
-- ── Search Term Performance ──────────────────────────────
CREATE TABLE IF NOT EXISTS manar.search_term_performance (
brand_id String,
platform String,
account_id String,
campaign_id String,
adgroup_id String,
date Date,
search_term String,
match_type String,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64,
quality_score UInt8
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, date, search_term)
TTL date + INTERVAL 1 YEAR;
-- ── Creative Performance ─────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.creative_performance (
brand_id String,
platform String,
account_id String,
ad_id String,
ad_name String,
ad_type String,
date Date,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64,
headline String,
description String
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, ad_id, date)
TTL date + INTERVAL 1 YEAR;
-- ── Device Performance ───────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.device_performance (
brand_id String,
platform String,
account_id String,
campaign_id String,
date Date,
device String,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, campaign_id, date, device)
TTL date + INTERVAL 1 YEAR;
-- ── Geo Performance ──────────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.geo_performance (
brand_id String,
platform String,
account_id String,
campaign_id String,
date Date,
country_code String,
region String,
city String,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, campaign_id, date, country_code)
TTL date + INTERVAL 1 YEAR;
-- ── Day Part Performance ─────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.day_part_performance (
brand_id String,
platform String,
account_id String,
campaign_id String,
date Date,
hour_of_day UInt8,
day_of_week UInt8,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, campaign_id, date, hour_of_day)
TTL date + INTERVAL 1 YEAR;
-- ── Placement Performance ────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.placement_performance (
brand_id String,
platform String,
account_id String,
campaign_id String,
date Date,
placement String,
placement_type String,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, campaign_id, date, placement)
TTL date + INTERVAL 1 YEAR;
-- ── Audience Segments ────────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.audience_segments (
brand_id String,
platform String,
account_id String,
campaign_id String,
date Date,
audience_id String,
audience_name String,
audience_type String,
impressions UInt64,
clicks UInt64,
cost_micros UInt64,
conversions Float64
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, campaign_id, date, audience_id)
TTL date + INTERVAL 1 YEAR;
-- ── Anomaly Events ───────────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.anomaly_events (
brand_id String,
platform String,
account_id String,
entity_type String,
entity_id String,
metric String,
detected_at DateTime DEFAULT now(),
date Date,
expected_value Float64,
actual_value Float64,
deviation_pct Float64,
severity String,
resolved UInt8 DEFAULT 0
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, detected_at)
TTL date + INTERVAL 6 MONTH;
-- ── Competitor Signals ───────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.competitor_signals (
brand_id String,
platform String,
account_id String,
date Date,
keyword String,
competitor_domain String,
auction_insight_metric String,
value Float64
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, date, keyword, competitor_domain)
TTL date + INTERVAL 1 YEAR;
-- ── Conversion Path ──────────────────────────────────────
CREATE TABLE IF NOT EXISTS manar.conversion_path (
brand_id String,
platform String,
account_id String,
date Date,
conversion_name String,
path_length UInt8,
days_to_convert UInt16,
conversions Float64,
conv_value Float64
) ENGINE = MergeTree()
PARTITION BY (brand_id, toYYYYMM(date))
ORDER BY (brand_id, account_id, date, conversion_name)
TTL date + INTERVAL 1 YEAR;