CREATE EXTENSION IF NOT EXISTS postgis;

CREATE SCHEMA IF NOT EXISTS dmk;

-- =========================================================
-- 1. 通用维度与配置表
-- =========================================================

CREATE TABLE IF NOT EXISTS dmk.td_account_period (
    data_type integer NOT NULL,
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    is_current boolean NOT NULL DEFAULT false,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (data_type, year_month)
);

COMMENT ON TABLE dmk.td_account_period IS '可查询账期维表，支撑 /api/common/account-periods。';
COMMENT ON COLUMN dmk.td_account_period.data_type IS '数据来源类型，对应字典 data_type，区分 OTT/工参/用户等不同数据源';
COMMENT ON COLUMN dmk.td_account_period.year_month IS '账期，格式 YYYY-MM，统一月粒度';
COMMENT ON COLUMN dmk.td_account_period.year IS '账期年份，冗余于 year_month';
COMMENT ON COLUMN dmk.td_account_period.month IS '账期月份(1-12)，冗余于 year_month';
COMMENT ON COLUMN dmk.td_account_period.is_current IS '是否当前最新账期，true 表示该数据源当前默认账期';
COMMENT ON COLUMN dmk.td_account_period.is_valid IS '是否有效，1=有效 0=无效（逻辑删除）';
COMMENT ON COLUMN dmk.td_account_period.updated_time IS '记录更新时间';

CREATE TABLE IF NOT EXISTS dmk.td_region (
    region_code integer PRIMARY KEY,
    region_name varchar(64) NOT NULL,
    region_level varchar(16) NOT NULL,
    parent_region_code integer,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    bbox numeric(10, 6)[],
    region_wkt text,
    region_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN region_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(region_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    sort_no integer NOT NULL DEFAULT 0,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    CHECK (region_level IN ('nation', 'province', 'city', 'district'))
);

COMMENT ON TABLE dmk.td_region IS '行政区域维表，保留区域树、区域 WKT 和区域空间索引字段。';
COMMENT ON COLUMN dmk.td_region.region_code IS '区域编码，全国/省/市/区县统一主键';
COMMENT ON COLUMN dmk.td_region.region_name IS '区域名称';
COMMENT ON COLUMN dmk.td_region.region_level IS '区域级别：nation/province/city/district';
COMMENT ON COLUMN dmk.td_region.parent_region_code IS '父级区域编码，用于构造区域树';
COMMENT ON COLUMN dmk.td_region.provincecode IS '省编码（冗余）';
COMMENT ON COLUMN dmk.td_region.province_name IS '省名称（冗余）';
COMMENT ON COLUMN dmk.td_region.citycode IS '地市编码（冗余）';
COMMENT ON COLUMN dmk.td_region.city_name IS '地市名称（冗余）';
COMMENT ON COLUMN dmk.td_region.districtcode IS '区县编码（冗余）';
COMMENT ON COLUMN dmk.td_region.district_name IS '区县名称（冗余）';
COMMENT ON COLUMN dmk.td_region.center_lon IS '区域中心点经度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_region.center_lat IS '区域中心点纬度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_region.bbox IS '区域外接矩形 [minLon,minLat,maxLon,maxLat]，便于地图视野初始化';
COMMENT ON COLUMN dmk.td_region.region_wkt IS '区域多边形 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.td_region.region_geom IS '由 region_wkt 生成的 MultiPolygon 几何列，用于 GiST 空间索引和空间过滤';
COMMENT ON COLUMN dmk.td_region.sort_no IS '区域显示排序号';
COMMENT ON COLUMN dmk.td_region.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_region.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_td_region_parent ON dmk.td_region(parent_region_code, region_level, sort_no);
CREATE INDEX IF NOT EXISTS idx_td_region_geom ON dmk.td_region USING gist(region_geom) WHERE region_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.td_dict_item (
    dict_type varchar(64) NOT NULL,
    dict_code varchar(64) NOT NULL,
    dict_name varchar(128) NOT NULL,
    dict_desc text,
    sort_no integer NOT NULL DEFAULT 0,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (dict_type, dict_code)
);

COMMENT ON TABLE dmk.td_dict_item IS '通用字典维表，覆盖 data_type、operator_name、network_class、scene_type 等枚举。';
COMMENT ON COLUMN dmk.td_dict_item.dict_type IS '字典类型编码，如 data_type、operator_name、network_class、scene_type 等';
COMMENT ON COLUMN dmk.td_dict_item.dict_code IS '字典项编码';
COMMENT ON COLUMN dmk.td_dict_item.dict_name IS '字典项名称（用于前端展示）';
COMMENT ON COLUMN dmk.td_dict_item.dict_desc IS '字典项描述/补充说明；初始化字典中同类型记录可统一保存字典类型名称，供 /api/common/dict/types 返回';
COMMENT ON COLUMN dmk.td_dict_item.sort_no IS '同类型下的排序号';
COMMENT ON COLUMN dmk.td_dict_item.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_dict_item.updated_time IS '记录更新时间';

CREATE TABLE IF NOT EXISTS dmk.td_metric_definition (
    module_code varchar(64) NOT NULL,
    metric_code varchar(64) NOT NULL,
    threshold varchar(32) NOT NULL DEFAULT '',
    metric_group varchar(64),
    metric_name varchar(128) NOT NULL,
    metric_desc text,
    formula text,
    source_table varchar(128),
    unit varchar(32),
    is_default boolean NOT NULL DEFAULT false,
    sort_no integer NOT NULL DEFAULT 0,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (module_code, metric_code, threshold)
);

COMMENT ON TABLE dmk.td_metric_definition IS '指标口径维表，threshold 用于区分 -105/-110 等不同覆盖口径。';
COMMENT ON COLUMN dmk.td_metric_definition.module_code IS '指标所属模块编码（如 grid、building、scene、cluster、poor 等）';
COMMENT ON COLUMN dmk.td_metric_definition.metric_code IS '指标编码（如 mr_cover_rate、avgrsrp 等）';
COMMENT ON COLUMN dmk.td_metric_definition.threshold IS '阈值标识，如 -105/-110，用于区分同名指标的不同口径，无阈值时为空串';
COMMENT ON COLUMN dmk.td_metric_definition.metric_group IS '指标分组（如 coverage、user、quality 等）';
COMMENT ON COLUMN dmk.td_metric_definition.metric_name IS '指标显示名称';
COMMENT ON COLUMN dmk.td_metric_definition.metric_desc IS '指标说明/口径描述（用于报表口径弹窗）';
COMMENT ON COLUMN dmk.td_metric_definition.formula IS '计算公式描述';
COMMENT ON COLUMN dmk.td_metric_definition.source_table IS '指标来源表说明';
COMMENT ON COLUMN dmk.td_metric_definition.unit IS '指标单位（如 %、dBm、个、GB 等）';
COMMENT ON COLUMN dmk.td_metric_definition.is_default IS '是否为模块默认展示指标';
COMMENT ON COLUMN dmk.td_metric_definition.sort_no IS '同模块下的排序号';
COMMENT ON COLUMN dmk.td_metric_definition.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_metric_definition.updated_time IS '记录更新时间';

CREATE TABLE IF NOT EXISTS dmk.td_layer_config (
    layer_type varchar(32) NOT NULL,
    layer_role varchar(32) NOT NULL DEFAULT 'base',
    render_mode varchar(16) NOT NULL DEFAULT '2D',
    workspace varchar(64) NOT NULL DEFAULT 'ott',
    layer_name varchar(128) NOT NULL,
    default_style_name varchar(128) NOT NULL,
    wms_url varchar(256) NOT NULL DEFAULT '/geoserver/ott/wms',
    wms_version varchar(16) NOT NULL DEFAULT '1.1.1',
    wms_format varchar(64) NOT NULL DEFAULT 'image/png',
    wms_transparent boolean NOT NULL DEFAULT true,
    wms_srs varchar(32) NOT NULL DEFAULT 'EPSG:4326',
    wms_tiled boolean NOT NULL DEFAULT true,
    wms_tile_size integer NOT NULL DEFAULT 256,
    wms_min_zoom integer NOT NULL DEFAULT 8,
    wms_max_zoom integer NOT NULL DEFAULT 19,
    wms_opacity numeric(4, 2) NOT NULL DEFAULT 0.9,
    geom_column varchar(64) NOT NULL,
    cql_template text,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (layer_type, layer_role, render_mode)
);

COMMENT ON TABLE dmk.td_layer_config IS 'GeoServer WMS 图层配置表，Java 服务基于该表和白名单字段生成 layer_config。';
COMMENT ON COLUMN dmk.td_layer_config.layer_type IS '图层类型（building/grid/scene/cell/cluster/poor 等）';
COMMENT ON COLUMN dmk.td_layer_config.layer_role IS '图层角色：base=基础图层 view=视图层 publish=发布层';
COMMENT ON COLUMN dmk.td_layer_config.render_mode IS '渲染模式：2D / 3D';
COMMENT ON COLUMN dmk.td_layer_config.workspace IS 'GeoServer 工作空间，默认 ott';
COMMENT ON COLUMN dmk.td_layer_config.layer_name IS 'GeoServer 图层名称（workspace:layer 中的 layer 部分）';
COMMENT ON COLUMN dmk.td_layer_config.default_style_name IS '默认 SLD 样式名称';
COMMENT ON COLUMN dmk.td_layer_config.wms_url IS 'WMS 服务地址，默认 /geoserver/ott/wms';
COMMENT ON COLUMN dmk.td_layer_config.wms_version IS 'WMS 协议版本，默认 1.1.1';
COMMENT ON COLUMN dmk.td_layer_config.wms_format IS 'WMS 图片格式，默认 image/png';
COMMENT ON COLUMN dmk.td_layer_config.wms_transparent IS '是否透明背景，默认 true';
COMMENT ON COLUMN dmk.td_layer_config.wms_srs IS '坐标参考系，默认 EPSG:4326';
COMMENT ON COLUMN dmk.td_layer_config.wms_tiled IS '是否使用瓦片模式，默认 true';
COMMENT ON COLUMN dmk.td_layer_config.wms_tile_size IS '瓦片尺寸（像素），默认 256';
COMMENT ON COLUMN dmk.td_layer_config.wms_min_zoom IS '图层最小缩放级别，默认 8';
COMMENT ON COLUMN dmk.td_layer_config.wms_max_zoom IS '图层最大缩放级别，默认 19';
COMMENT ON COLUMN dmk.td_layer_config.wms_opacity IS '图层默认透明度（0.0~1.0），默认 0.9';
COMMENT ON COLUMN dmk.td_layer_config.geom_column IS '发布所用几何列名（如 grid_geom/aoi_geom），视图层可统一别名为 geom';
COMMENT ON COLUMN dmk.td_layer_config.cql_template IS 'CQL 过滤模板，由 Java 服务基于白名单字段拼装时填充';
COMMENT ON COLUMN dmk.td_layer_config.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_layer_config.updated_time IS '记录更新时间';

CREATE TABLE IF NOT EXISTS dmk.td_layer_metric (
    layer_type varchar(32) NOT NULL,
    metric_code varchar(64) NOT NULL,
    metric_name varchar(128) NOT NULL,
    default_style_name varchar(128) NOT NULL,
    supported_operator varchar(32)[] NOT NULL DEFAULT ARRAY[]::varchar[],
    supported_network_class varchar(32)[] NOT NULL DEFAULT ARRAY[]::varchar[],
    sort_no integer NOT NULL DEFAULT 0,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (layer_type, metric_code)
);

COMMENT ON TABLE dmk.td_layer_metric IS '图层指标白名单配置表，支撑 /api/common/layer-metrics。';
COMMENT ON COLUMN dmk.td_layer_metric.layer_type IS '图层类型，对应 td_layer_config.layer_type';
COMMENT ON COLUMN dmk.td_layer_metric.metric_code IS '指标编码，对应 td_metric_definition.metric_code';
COMMENT ON COLUMN dmk.td_layer_metric.metric_name IS '指标显示名称';
COMMENT ON COLUMN dmk.td_layer_metric.default_style_name IS '该指标默认 SLD 样式名称';
COMMENT ON COLUMN dmk.td_layer_metric.supported_operator IS '支持的运营商列表（数组），为空表示全部';
COMMENT ON COLUMN dmk.td_layer_metric.supported_network_class IS '支持的网络制式列表（数组），如 4G/5G_SA/all';
COMMENT ON COLUMN dmk.td_layer_metric.sort_no IS '同图层下指标排序号';
COMMENT ON COLUMN dmk.td_layer_metric.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_layer_metric.updated_time IS '记录更新时间';

CREATE TABLE IF NOT EXISTS dmk.td_layer_legend (
    legend_id varchar(64) PRIMARY KEY,
    account_id varchar(64) NOT NULL,
    layer_type varchar(32) NOT NULL,
    metric_code varchar(64) NOT NULL,
    legend_name varchar(128) NOT NULL,
    ranges jsonb NOT NULL,
    is_default boolean NOT NULL DEFAULT false,
    updated_by varchar(64),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    is_deleted smallint NOT NULL DEFAULT 0
);

COMMENT ON TABLE dmk.td_layer_legend IS '账号维度自定义图例表，ranges 保存颜色、区间、标签配置。';
COMMENT ON COLUMN dmk.td_layer_legend.legend_id IS '图例主键 ID';
COMMENT ON COLUMN dmk.td_layer_legend.account_id IS '账号 ID（自定义图例归属用户）';
COMMENT ON COLUMN dmk.td_layer_legend.layer_type IS '图层类型';
COMMENT ON COLUMN dmk.td_layer_legend.metric_code IS '指标编码';
COMMENT ON COLUMN dmk.td_layer_legend.legend_name IS '图例名称';
COMMENT ON COLUMN dmk.td_layer_legend.ranges IS '图例配置 JSON，包含颜色、区间、标签等';
COMMENT ON COLUMN dmk.td_layer_legend.is_default IS '是否为该用户默认图例';
COMMENT ON COLUMN dmk.td_layer_legend.updated_by IS '最后更新人账号';
COMMENT ON COLUMN dmk.td_layer_legend.updated_time IS '记录更新时间';
COMMENT ON COLUMN dmk.td_layer_legend.is_deleted IS '是否已删除：0=未删除 1=已删除（逻辑删除）';
CREATE INDEX IF NOT EXISTS idx_td_layer_legend_query ON dmk.td_layer_legend(account_id, layer_type, metric_code, is_deleted);

-- =========================================================
-- 2. 空间基础维度表
-- =========================================================

CREATE TABLE IF NOT EXISTS dmk.td_grid (
    regionid varchar(64) NOT NULL,
    x_offset_20 varchar(32) NOT NULL,
    y_offset_20 varchar(32) NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    grid_wkt text,
    grid_geom geometry(Polygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN grid_wkt IS NULL THEN NULL
             ELSE ST_GeomFromText(grid_wkt, 4326)::geometry(Polygon, 4326)
        END
    ) STORED,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (regionid, x_offset_20, y_offset_20)
);

COMMENT ON TABLE dmk.td_grid IS '栅格基础维表，保留 WKT 和生成 geometry 用于空间关联。';
COMMENT ON COLUMN dmk.td_grid.regionid IS '栅格所属区域 ID';
COMMENT ON COLUMN dmk.td_grid.x_offset_20 IS '栅格 X 偏移（20m 网格编码）';
COMMENT ON COLUMN dmk.td_grid.y_offset_20 IS '栅格 Y 偏移（20m 网格编码）';
COMMENT ON COLUMN dmk.td_grid.provincecode IS '省编码';
COMMENT ON COLUMN dmk.td_grid.province_name IS '省名称';
COMMENT ON COLUMN dmk.td_grid.citycode IS '地市编码';
COMMENT ON COLUMN dmk.td_grid.city_name IS '地市名称';
COMMENT ON COLUMN dmk.td_grid.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.td_grid.district_name IS '区县名称';
COMMENT ON COLUMN dmk.td_grid.center_lon IS '栅格中心点经度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_grid.center_lat IS '栅格中心点纬度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_grid.grid_wkt IS '栅格多边形 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.td_grid.grid_geom IS '由 grid_wkt 生成的 Polygon 几何列，用于 GiST 空间索引';
COMMENT ON COLUMN dmk.td_grid.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_grid.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_td_grid_region ON dmk.td_grid(provincecode, citycode, districtcode);
CREATE INDEX IF NOT EXISTS idx_td_grid_geom ON dmk.td_grid USING gist(grid_geom) WHERE grid_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.td_cell_param_m (
    year_month varchar(7) NOT NULL,
    data_type integer,
    operator_name varchar(32),
    network_class varchar(32) NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    cellkey varchar(64) NOT NULL,
    cell_name varchar(128),
    cell_lon numeric(10, 6),
    cell_lat numeric(10, 6),
    cell_wkt text,
    cell_geom geometry(Point, 4326) GENERATED ALWAYS AS (
        CASE WHEN cell_wkt IS NOT NULL THEN ST_GeomFromText(cell_wkt, 4326)::geometry(Point, 4326)
             WHEN cell_lon IS NOT NULL AND cell_lat IS NOT NULL THEN ST_SetSRID(ST_MakePoint(cell_lon, cell_lat), 4326)::geometry(Point, 4326)
             ELSE NULL
        END
    ) STORED,
    cell_regionid varchar(64),
    cell_x_offset_20 varchar(32),
    cell_y_offset_20 varchar(32),
    pci varchar(32),
    indoor_flag smallint,
    azimuth integer,
    freq varchar(32),
    freq_1 varchar(32),
    vendor varchar(64),
    antenna_height numeric(10, 2),
    mechanical_downdip numeric(10, 2),
    electron_downdip numeric(10, 2),
    cover_type varchar(64),
    rspower numeric(12, 4),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, cellkey, network_class)
);

COMMENT ON TABLE dmk.td_cell_param_m IS '月粒度工参维表，保留小区基础信息、经纬度和 WKT。';
COMMENT ON COLUMN dmk.td_cell_param_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.td_cell_param_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.td_cell_param_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.td_cell_param_m.network_class IS '网络制式（4G/5G_SA/wifi 等）';
COMMENT ON COLUMN dmk.td_cell_param_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.td_cell_param_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.td_cell_param_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.td_cell_param_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.td_cell_param_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.td_cell_param_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.td_cell_param_m.cellkey IS '小区唯一键 cellkey';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_name IS '小区名称';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_lon IS '小区经度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_lat IS '小区纬度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_wkt IS '小区点 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_geom IS '由 cell_wkt 或经纬度生成的 Point 几何列，用于 GiST 空间索引';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_regionid IS '小区所属栅格区域 ID';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_x_offset_20 IS '小区所属栅格 X 偏移';
COMMENT ON COLUMN dmk.td_cell_param_m.cell_y_offset_20 IS '小区所属栅格 Y 偏移';
COMMENT ON COLUMN dmk.td_cell_param_m.pci IS '物理小区标识 PCI';
COMMENT ON COLUMN dmk.td_cell_param_m.indoor_flag IS '室内外标识：0=室外 1=室内 -1=未知/全部';
COMMENT ON COLUMN dmk.td_cell_param_m.azimuth IS '天线方位角（度）';
COMMENT ON COLUMN dmk.td_cell_param_m.freq IS '频段标识';
COMMENT ON COLUMN dmk.td_cell_param_m.freq_1 IS '辅助频段标识';
COMMENT ON COLUMN dmk.td_cell_param_m.vendor IS '设备厂家';
COMMENT ON COLUMN dmk.td_cell_param_m.antenna_height IS '天线挂高（米）';
COMMENT ON COLUMN dmk.td_cell_param_m.mechanical_downdip IS '机械下倾角（度）';
COMMENT ON COLUMN dmk.td_cell_param_m.electron_downdip IS '电子下倾角（度）';
COMMENT ON COLUMN dmk.td_cell_param_m.cover_type IS '覆盖类型（如室分、宏站、微站等）';
COMMENT ON COLUMN dmk.td_cell_param_m.rspower IS '参考信号发射功率 RSPower';
COMMENT ON COLUMN dmk.td_cell_param_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_td_cell_param_region ON dmk.td_cell_param_m(year_month, provincecode, citycode, districtcode, operator_name, network_class);
CREATE INDEX IF NOT EXISTS idx_td_cell_param_geom ON dmk.td_cell_param_m USING gist(cell_geom) WHERE cell_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.td_building (
    building_id varchar(64) PRIMARY KEY,
    building_name varchar(128) NOT NULL,
    building_type varchar(64),
    building_type_name varchar(128),
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    bbox numeric(10, 6)[],
    height numeric(12, 2),
    floor_count integer,
    building_area numeric(18, 4),
    population_density numeric(14, 4),
    aoi_wkt text,
    aoi_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN aoi_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(aoi_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now()
);

COMMENT ON TABLE dmk.td_building IS '楼宇基础维表，保留楼宇分类、人口密度、AOI WKT 和 bbox。';
COMMENT ON COLUMN dmk.td_building.building_id IS '楼宇唯一 ID';
COMMENT ON COLUMN dmk.td_building.building_name IS '楼宇名称';
COMMENT ON COLUMN dmk.td_building.building_type IS '楼宇类型编码';
COMMENT ON COLUMN dmk.td_building.building_type_name IS '楼宇类型名称';
COMMENT ON COLUMN dmk.td_building.provincecode IS '省编码';
COMMENT ON COLUMN dmk.td_building.province_name IS '省名称';
COMMENT ON COLUMN dmk.td_building.citycode IS '地市编码';
COMMENT ON COLUMN dmk.td_building.city_name IS '地市名称';
COMMENT ON COLUMN dmk.td_building.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.td_building.district_name IS '区县名称';
COMMENT ON COLUMN dmk.td_building.center_lon IS '楼宇中心点经度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_building.center_lat IS '楼宇中心点纬度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_building.bbox IS '楼宇外接矩形 [minLon,minLat,maxLon,maxLat]';
COMMENT ON COLUMN dmk.td_building.height IS '楼宇高度（米）';
COMMENT ON COLUMN dmk.td_building.floor_count IS '楼层数';
COMMENT ON COLUMN dmk.td_building.building_area IS '楼宇面积（平方米，按业务口径可表示建筑面积或占地面积）';
COMMENT ON COLUMN dmk.td_building.population_density IS '人口密度（人/平方公里或人/平方米，按业务口径）';
COMMENT ON COLUMN dmk.td_building.aoi_wkt IS '楼宇 AOI WKT，EPSG:4326';
COMMENT ON COLUMN dmk.td_building.aoi_geom IS '由 aoi_wkt 生成的 MultiPolygon 几何列，用于 GiST 空间索引';
COMMENT ON COLUMN dmk.td_building.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_building.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_td_building_query ON dmk.td_building(provincecode, citycode, districtcode, building_type, is_valid);
CREATE INDEX IF NOT EXISTS idx_td_building_geom ON dmk.td_building USING gist(aoi_geom) WHERE aoi_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.td_scene (
    scene_id varchar(64) PRIMARY KEY,
    scene_name varchar(128) NOT NULL,
    scene_type varchar(64) NOT NULL,
    scene_type_name varchar(128),
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    bbox numeric(10, 6)[],
    area_size numeric(18, 4),
    aoi_wkt text,
    aoi_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN aoi_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(aoi_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    is_valid smallint NOT NULL DEFAULT 1,
    updated_time timestamp without time zone NOT NULL DEFAULT now()
);

COMMENT ON TABLE dmk.td_scene IS '重点场景维表，保留场景类型、AOI WKT、中心点和 bbox。';
COMMENT ON COLUMN dmk.td_scene.scene_id IS '场景唯一 ID';
COMMENT ON COLUMN dmk.td_scene.scene_name IS '场景名称';
COMMENT ON COLUMN dmk.td_scene.scene_type IS '场景类型编码';
COMMENT ON COLUMN dmk.td_scene.scene_type_name IS '场景类型名称';
COMMENT ON COLUMN dmk.td_scene.provincecode IS '省编码';
COMMENT ON COLUMN dmk.td_scene.province_name IS '省名称';
COMMENT ON COLUMN dmk.td_scene.citycode IS '地市编码';
COMMENT ON COLUMN dmk.td_scene.city_name IS '地市名称';
COMMENT ON COLUMN dmk.td_scene.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.td_scene.district_name IS '区县名称';
COMMENT ON COLUMN dmk.td_scene.center_lon IS '场景中心点经度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_scene.center_lat IS '场景中心点纬度（EPSG:4326）';
COMMENT ON COLUMN dmk.td_scene.bbox IS '场景外接矩形 [minLon,minLat,maxLon,maxLat]';
COMMENT ON COLUMN dmk.td_scene.area_size IS '场景面积（平方米）';
COMMENT ON COLUMN dmk.td_scene.aoi_wkt IS '场景 AOI WKT，EPSG:4326';
COMMENT ON COLUMN dmk.td_scene.aoi_geom IS '由 aoi_wkt 生成的 MultiPolygon 几何列，用于 GiST 空间索引';
COMMENT ON COLUMN dmk.td_scene.is_valid IS '是否有效，1=有效 0=无效';
COMMENT ON COLUMN dmk.td_scene.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_td_scene_search ON dmk.td_scene(provincecode, citycode, scene_type, scene_name, is_valid);
CREATE INDEX IF NOT EXISTS idx_td_scene_geom ON dmk.td_scene USING gist(aoi_geom) WHERE aoi_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.td_cluster_threshold (
    account_id varchar(64) NOT NULL,
    cluster_type varchar(64) NOT NULL,
    network_class varchar(32) NOT NULL,
    min_grid_count integer NOT NULL DEFAULT 5,
    max_area_size numeric(18, 4),
    min_weighted_score numeric(10, 4),
    max_region_distance numeric(18, 4),
    rsrp_threshold numeric(10, 4),
    coverage_threshold numeric(10, 4),
    threshold_config jsonb,
    updated_by varchar(64),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (account_id, cluster_type, network_class)
);

COMMENT ON TABLE dmk.td_cluster_threshold IS '聚类阈值配置表，支撑在线调整区域栅格数和区域范围阈值。';
COMMENT ON COLUMN dmk.td_cluster_threshold.account_id IS '账号 ID（按用户维度持久化阈值）';
COMMENT ON COLUMN dmk.td_cluster_threshold.cluster_type IS '聚类类型（如弱覆盖、超忙、综合质差等）';
COMMENT ON COLUMN dmk.td_cluster_threshold.network_class IS '网络制式';
COMMENT ON COLUMN dmk.td_cluster_threshold.min_grid_count IS '区域最少栅格数阈值';
COMMENT ON COLUMN dmk.td_cluster_threshold.max_area_size IS '区域最大面积阈值（平方米）';
COMMENT ON COLUMN dmk.td_cluster_threshold.min_weighted_score IS '加权得分下限阈值';
COMMENT ON COLUMN dmk.td_cluster_threshold.max_region_distance IS '区域最大跨度距离阈值（米）';
COMMENT ON COLUMN dmk.td_cluster_threshold.rsrp_threshold IS 'RSRP 阈值（dBm）';
COMMENT ON COLUMN dmk.td_cluster_threshold.coverage_threshold IS '覆盖率阈值（0-1）';
COMMENT ON COLUMN dmk.td_cluster_threshold.threshold_config IS '其他阈值参数 JSON';
COMMENT ON COLUMN dmk.td_cluster_threshold.updated_by IS '最后更新人账号';
COMMENT ON COLUMN dmk.td_cluster_threshold.updated_time IS '记录更新时间';

CREATE TABLE IF NOT EXISTS dmk.td_custom_region (
    region_id varchar(64) PRIMARY KEY,
    account_id varchar(64) NOT NULL,
    provincecode integer,
    citycode integer,
    districtcode integer,
    region_wkt text NOT NULL,
    region_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        ST_Multi(ST_GeomFromText(region_wkt, 4326))::geometry(MultiPolygon, 4326)
    ) STORED,
    bbox numeric(10, 6)[],
    created_time timestamp without time zone NOT NULL DEFAULT now(),
    expire_time timestamp without time zone,
    is_deleted smallint NOT NULL DEFAULT 0
);

COMMENT ON TABLE dmk.td_custom_region IS '用户自定义区域表，region_wkt 固定 EPSG:4326。';
COMMENT ON COLUMN dmk.td_custom_region.region_id IS '自定义区域 ID';
COMMENT ON COLUMN dmk.td_custom_region.account_id IS '账号 ID（区域归属用户）';
COMMENT ON COLUMN dmk.td_custom_region.provincecode IS '省编码';
COMMENT ON COLUMN dmk.td_custom_region.citycode IS '地市编码';
COMMENT ON COLUMN dmk.td_custom_region.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.td_custom_region.region_wkt IS '自定义区域 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.td_custom_region.region_geom IS '由 region_wkt 生成的 MultiPolygon 几何列';
COMMENT ON COLUMN dmk.td_custom_region.bbox IS '区域外接矩形';
COMMENT ON COLUMN dmk.td_custom_region.created_time IS '区域创建时间';
COMMENT ON COLUMN dmk.td_custom_region.expire_time IS '过期时间（用于临时区域清理）';
COMMENT ON COLUMN dmk.td_custom_region.is_deleted IS '是否已删除：0=未删除 1=已删除';
CREATE INDEX IF NOT EXISTS idx_td_custom_region_query ON dmk.td_custom_region(account_id, provincecode, citycode, created_time DESC, is_deleted);
CREATE INDEX IF NOT EXISTS idx_td_custom_region_geom ON dmk.td_custom_region USING gist(region_geom);

-- =========================================================
-- 3. 区域栅格与地市报表指标表
-- =========================================================

CREATE TABLE IF NOT EXISTS dmk.tm_grid_coverage_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    data_type integer NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    freq varchar(32) NOT NULL DEFAULT 'all',
    indoor_flag smallint NOT NULL DEFAULT -1,
    regionid varchar(64) NOT NULL,
    x_offset_20 varchar(32) NOT NULL,
    y_offset_20 varchar(32) NOT NULL,
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    grid_wkt text,
    grid_geom geometry(Polygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN grid_wkt IS NULL THEN NULL
             ELSE ST_GeomFromText(grid_wkt, 4326)::geometry(Polygon, 4326)
        END
    ) STORED,
    earfcn integer,
    rsrpcount bigint NOT NULL DEFAULT 0,
    totalrsrp numeric(20, 4),
    totalsinr numeric(20, 4),
    totalrsrq numeric(20, 4),
    avgrsrp numeric(10, 4),
    avgsinr numeric(10, 4),
    avgrsrq numeric(10, 4),
    rsrpgoodcount_105 bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_110 bigint NOT NULL DEFAULT 0,
    sinrgoodcount bigint NOT NULL DEFAULT 0,
    rsrqgoodcount bigint NOT NULL DEFAULT 0,
    rsrp_good_ratio_105 numeric(12, 6),
    rsrp_good_ratio_110 numeric(12, 6),
    mr_cover_rate_105 numeric(12, 6),
    mr_cover_rate_110 numeric(12, 6),
    is_covered_105 smallint NOT NULL DEFAULT 0,
    is_covered_110 smallint NOT NULL DEFAULT 0,
    weakcover_mrcount bigint NOT NULL DEFAULT 0,
    overlap_mrcount bigint NOT NULL DEFAULT 0,
    overshoot_mrcount bigint NOT NULL DEFAULT 0,
    use_heat_5g numeric(12, 6),
    total_user_count bigint,
    user_count_4g bigint,
    user_count_5g bigint,
    user_market_share_4g numeric(12, 6),
    user_market_share_5g numeric(12, 6),
    operator_5g_reside_rate numeric(12, 6),
    top1_cellkey varchar(64),
    top1_cell_name varchar(128),
    top1_cell_lon numeric(10, 6),
    top1_cell_lat numeric(10, 6),
    top1_cell_rsrpcount bigint,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, regionid, x_offset_20, y_offset_20, operator_name, network_class, freq, indoor_flag)
);

COMMENT ON TABLE dmk.tm_grid_coverage_m IS '栅格级覆盖指标月表，支撑 GIS 栅格图层、单栅格详情和底层聚合。';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.network_class IS '网络制式（4G/5G_SA/all）';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.freq IS '频段，all 表示全部频段聚合';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.indoor_flag IS '室内外标识：0=室外 1=室内 -1=全部';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.regionid IS '栅格区域 ID';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.x_offset_20 IS '栅格 X 偏移';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.y_offset_20 IS '栅格 Y 偏移';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.center_lon IS '栅格中心点经度';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.center_lat IS '栅格中心点纬度';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.grid_wkt IS '栅格 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.grid_geom IS '由 grid_wkt 生成的 Polygon 几何列，用于 GiST 索引/WMS 发布';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.earfcn IS '主用频点号 EARFCN';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.rsrpcount IS 'MR 采样点总数（RSRP 采样数）';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.totalrsrp IS 'RSRP 累加值（用于聚合时再求平均）';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.totalsinr IS 'SINR 累加值';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.totalrsrq IS 'RSRQ 累加值';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.avgrsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.avgsinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.avgrsrq IS '平均 RSRQ（dB）';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.rsrpgoodcount_105 IS 'RSRP≥-105 的采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.rsrpgoodcount_110 IS 'RSRP≥-110 的采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.sinrgoodcount IS 'SINR 达标采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.rsrqgoodcount IS 'RSRQ 达标采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.rsrp_good_ratio_105 IS 'RSRP≥-105 采样占比';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.rsrp_good_ratio_110 IS 'RSRP≥-110 采样占比';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.mr_cover_rate_105 IS 'MR 覆盖率(-105)：rsrpgoodcount_105/rsrpcount';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.mr_cover_rate_110 IS 'MR 覆盖率(-110)：rsrpgoodcount_110/rsrpcount';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.is_covered_105 IS '该栅格是否达 -105 覆盖：1=达标 0=未达标';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.is_covered_110 IS '该栅格是否达 -110 覆盖：1=达标 0=未达标';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.weakcover_mrcount IS '弱覆盖采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.overlap_mrcount IS '重叠覆盖采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.overshoot_mrcount IS '过覆盖采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.use_heat_5g IS '5G 使用热度';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.total_user_count IS '栅格内总用户数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.user_count_4g IS '4G 用户数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.user_count_5g IS '5G 用户数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.user_market_share_4g IS '4G 用户市场份额';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.user_market_share_5g IS '5G 用户市场份额';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.operator_5g_reside_rate IS '运营商 5G 驻留比';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.top1_cellkey IS 'TOP1 主服务小区 cellkey';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.top1_cell_name IS 'TOP1 主服务小区名称';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.top1_cell_lon IS 'TOP1 小区经度';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.top1_cell_lat IS 'TOP1 小区纬度';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.top1_cell_rsrpcount IS 'TOP1 小区在该栅格的采样数';
COMMENT ON COLUMN dmk.tm_grid_coverage_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_grid_cov_filter ON dmk.tm_grid_coverage_m(year_month, data_type, provincecode, citycode, districtcode, operator_name, network_class, freq, indoor_flag);
CREATE INDEX IF NOT EXISTS idx_tm_grid_cov_regionid ON dmk.tm_grid_coverage_m(year_month, regionid, x_offset_20, y_offset_20);
CREATE INDEX IF NOT EXISTS idx_tm_grid_cov_geom ON dmk.tm_grid_coverage_m USING gist(grid_geom) WHERE grid_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.tm_region_coverage_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    data_type integer NOT NULL,
    region_level varchar(16) NOT NULL,
    region_code integer NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    freq varchar(32) NOT NULL DEFAULT 'all',
    indoor_flag smallint NOT NULL DEFAULT -1,
    rsrpcount bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_105 bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_110 bigint NOT NULL DEFAULT 0,
    grid_count bigint NOT NULL DEFAULT 0,
    mr_grid_count bigint NOT NULL DEFAULT 0,
    covered_grid_count_105 bigint NOT NULL DEFAULT 0,
    covered_grid_count_110 bigint NOT NULL DEFAULT 0,
    mr_cover_rate_105 numeric(12, 6),
    mr_cover_rate_110 numeric(12, 6),
    grid_cover_rate_105 numeric(12, 6),
    grid_cover_rate_110 numeric(12, 6),
    avgrsrp numeric(10, 4),
    avgsinr numeric(10, 4),
    total_user_count bigint,
    user_count_4g bigint,
    user_count_5g bigint,
    user_ratio_4g numeric(12, 6),
    user_ratio_5g numeric(12, 6),
    total_user_market_share numeric(12, 6),
    user_market_share_4g numeric(12, 6),
    user_market_share_5g numeric(12, 6),
    operator_5g_reside_rate numeric(12, 6),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, region_level, region_code, operator_name, network_class, freq, indoor_flag)
);

COMMENT ON TABLE dmk.tm_region_coverage_m IS '行政区域覆盖聚合月表，支撑区域概览、覆盖统计和 OTT 地市报表。';
COMMENT ON COLUMN dmk.tm_region_coverage_m.grid_count IS '区域内总栅格数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.mr_grid_count IS '区域内有 MR 采样点（rsrpcount>0）的栅格数，作为栅格覆盖率的分母';
COMMENT ON COLUMN dmk.tm_region_coverage_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_region_coverage_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_region_coverage_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_region_coverage_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.tm_region_coverage_m.region_level IS '区域级别：nation/province/city/district';
COMMENT ON COLUMN dmk.tm_region_coverage_m.region_code IS '区域编码';
COMMENT ON COLUMN dmk.tm_region_coverage_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_region_coverage_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_region_coverage_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_region_coverage_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_region_coverage_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_region_coverage_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_region_coverage_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_region_coverage_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_region_coverage_m.freq IS '频段';
COMMENT ON COLUMN dmk.tm_region_coverage_m.indoor_flag IS '室内外标识';
COMMENT ON COLUMN dmk.tm_region_coverage_m.rsrpcount IS '区域内 MR 采样点总数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.rsrpgoodcount_105 IS 'RSRP≥-105 的采样数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.rsrpgoodcount_110 IS 'RSRP≥-110 的采样数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.covered_grid_count_105 IS '达到 -105 覆盖阈值的栅格数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.covered_grid_count_110 IS '达到 -110 覆盖阈值的栅格数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.mr_cover_rate_105 IS 'MR 覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_region_coverage_m.mr_cover_rate_110 IS 'MR 覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_region_coverage_m.grid_cover_rate_105 IS '栅格覆盖率(-105)：covered_grid_count_105/mr_grid_count';
COMMENT ON COLUMN dmk.tm_region_coverage_m.grid_cover_rate_110 IS '栅格覆盖率(-110)：covered_grid_count_110/mr_grid_count';
COMMENT ON COLUMN dmk.tm_region_coverage_m.avgrsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_region_coverage_m.avgsinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_region_coverage_m.total_user_count IS '区域内总用户数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.user_count_4g IS '4G 用户数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.user_count_5g IS '5G 用户数';
COMMENT ON COLUMN dmk.tm_region_coverage_m.user_ratio_4g IS '4G 用户占比';
COMMENT ON COLUMN dmk.tm_region_coverage_m.user_ratio_5g IS '5G 用户占比';
COMMENT ON COLUMN dmk.tm_region_coverage_m.total_user_market_share IS '总用户市场份额';
COMMENT ON COLUMN dmk.tm_region_coverage_m.user_market_share_4g IS '4G 用户市场份额';
COMMENT ON COLUMN dmk.tm_region_coverage_m.user_market_share_5g IS '5G 用户市场份额';
COMMENT ON COLUMN dmk.tm_region_coverage_m.operator_5g_reside_rate IS '运营商 5G 驻留比';
COMMENT ON COLUMN dmk.tm_region_coverage_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_region_cov_filter ON dmk.tm_region_coverage_m(year_month, data_type, provincecode, citycode, districtcode, operator_name, network_class);
CREATE INDEX IF NOT EXISTS idx_tm_region_cov_report ON dmk.tm_region_coverage_m(year_month, region_level, region_code, operator_name, network_class, grid_cover_rate_105 DESC);

-- =========================================================
-- 4. 楼宇与重点场景指标表
-- =========================================================

CREATE TABLE IF NOT EXISTS dmk.tm_building_coverage_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    data_type integer NOT NULL,
    building_id varchar(64) NOT NULL,
    building_name varchar(128) NOT NULL,
    building_type varchar(64),
    building_type_name varchar(128),
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    bbox numeric(10, 6)[],
    building_area numeric(18, 4),
    population_density numeric(14, 4),
    aoi_wkt text,
    aoi_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN aoi_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(aoi_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    freq varchar(32) NOT NULL DEFAULT 'all',
    indoor_flag smallint NOT NULL DEFAULT -1,
    rsrpcount bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_105 bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_110 bigint NOT NULL DEFAULT 0,
    grid_count bigint NOT NULL DEFAULT 0,
    mr_grid_count bigint NOT NULL DEFAULT 0,
    covered_grid_count_105 bigint NOT NULL DEFAULT 0,
    covered_grid_count_110 bigint NOT NULL DEFAULT 0,
    mr_cover_rate_105 numeric(12, 6),
    mr_cover_rate_110 numeric(12, 6),
    grid_cover_rate_105 numeric(12, 6),
    grid_cover_rate_110 numeric(12, 6),
    building_cover_rate numeric(12, 6),
    wireless_cover_rate numeric(12, 6),
    indoor_cover_rate numeric(12, 6),
    avgrsrp numeric(10, 4),
    avgsinr numeric(10, 4),
    avgrsrq numeric(10, 4),
    weakcover_mrcount bigint NOT NULL DEFAULT 0,
    overlap_mrcount bigint NOT NULL DEFAULT 0,
    overlap_total_value numeric(20, 4),
    overlap_rate numeric(12, 6),
    overlap_avgrsrp numeric(10, 4),
    overshoot_mrcount bigint NOT NULL DEFAULT 0,
    overshoot_total_value numeric(20, 4),
    overshoot_rate numeric(12, 6),
    overshoot_avgrsrp numeric(10, 4),
    mod_interference_mrcount bigint NOT NULL DEFAULT 0,
    mod_interference_total_value numeric(20, 4),
    mod_interference_avgrsrp numeric(10, 4),
    mod_interference_ratio numeric(12, 6),
    use_heat_5g numeric(12, 6),
    total_user_count bigint,
    user_count_4g bigint,
    user_count_5g bigint,
    user_market_share_4g numeric(12, 6),
    user_market_share_5g numeric(12, 6),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, building_id, operator_name, network_class, freq, indoor_flag)
);

COMMENT ON TABLE dmk.tm_building_coverage_m IS '楼宇覆盖指标月表，回填楼宇维度字段，支撑楼宇图层、对比和报表。';
COMMENT ON COLUMN dmk.tm_building_coverage_m.grid_count IS '楼宇覆盖范围内总栅格数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.mr_grid_count IS '楼宇覆盖范围内有 MR 采样点的栅格数，作为楼宇栅格覆盖率的分母';
COMMENT ON COLUMN dmk.tm_building_coverage_m.total_user_count IS '楼宇内总用户数，OTT 楼宇报表 total_user_count 字段直读';
COMMENT ON COLUMN dmk.tm_building_coverage_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_building_coverage_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_building_coverage_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_building_coverage_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.tm_building_coverage_m.building_id IS '楼宇 ID';
COMMENT ON COLUMN dmk.tm_building_coverage_m.building_name IS '楼宇名称';
COMMENT ON COLUMN dmk.tm_building_coverage_m.building_type IS '楼宇类型编码';
COMMENT ON COLUMN dmk.tm_building_coverage_m.building_type_name IS '楼宇类型名称';
COMMENT ON COLUMN dmk.tm_building_coverage_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_building_coverage_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_building_coverage_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_building_coverage_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_building_coverage_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_building_coverage_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_building_coverage_m.center_lon IS '楼宇中心点经度';
COMMENT ON COLUMN dmk.tm_building_coverage_m.center_lat IS '楼宇中心点纬度';
COMMENT ON COLUMN dmk.tm_building_coverage_m.bbox IS '楼宇外接矩形';
COMMENT ON COLUMN dmk.tm_building_coverage_m.building_area IS '楼宇面积（平方米，冗余自楼宇基础维表）';
COMMENT ON COLUMN dmk.tm_building_coverage_m.population_density IS '人口密度';
COMMENT ON COLUMN dmk.tm_building_coverage_m.aoi_wkt IS '楼宇 AOI WKT，EPSG:4326';
COMMENT ON COLUMN dmk.tm_building_coverage_m.aoi_geom IS '由 aoi_wkt 生成的 MultiPolygon 几何列';
COMMENT ON COLUMN dmk.tm_building_coverage_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_building_coverage_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_building_coverage_m.freq IS '频段';
COMMENT ON COLUMN dmk.tm_building_coverage_m.indoor_flag IS '室内外标识';
COMMENT ON COLUMN dmk.tm_building_coverage_m.rsrpcount IS '楼宇覆盖范围内 MR 采样数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.rsrpgoodcount_105 IS 'RSRP≥-105 的采样数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.rsrpgoodcount_110 IS 'RSRP≥-110 的采样数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.covered_grid_count_105 IS '达到 -105 覆盖阈值的栅格数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.covered_grid_count_110 IS '达到 -110 覆盖阈值的栅格数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.mr_cover_rate_105 IS 'MR 覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_building_coverage_m.mr_cover_rate_110 IS 'MR 覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_building_coverage_m.grid_cover_rate_105 IS '栅格覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_building_coverage_m.grid_cover_rate_110 IS '栅格覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_building_coverage_m.building_cover_rate IS '楼宇覆盖率';
COMMENT ON COLUMN dmk.tm_building_coverage_m.wireless_cover_rate IS '无线覆盖率';
COMMENT ON COLUMN dmk.tm_building_coverage_m.indoor_cover_rate IS '室内覆盖率';
COMMENT ON COLUMN dmk.tm_building_coverage_m.avgrsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_building_coverage_m.avgsinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_building_coverage_m.avgrsrq IS '平均 RSRQ（dB），支撑楼宇竞对无线网络覆盖';
COMMENT ON COLUMN dmk.tm_building_coverage_m.weakcover_mrcount IS '弱覆盖采样数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overlap_mrcount IS '重叠覆盖采样数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overlap_total_value IS '重叠覆盖总值';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overlap_rate IS '重叠覆盖率';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overlap_avgrsrp IS '重叠覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overshoot_mrcount IS '过覆盖采样数';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overshoot_total_value IS '过覆盖总值';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overshoot_rate IS '过覆盖率';
COMMENT ON COLUMN dmk.tm_building_coverage_m.overshoot_avgrsrp IS '过覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_building_coverage_m.mod_interference_mrcount IS 'MOD 干扰采样数，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_building_coverage_m.mod_interference_total_value IS 'MOD 干扰采样点总值，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_building_coverage_m.mod_interference_avgrsrp IS 'MOD 干扰平均 RSRP（dBm），4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_building_coverage_m.mod_interference_ratio IS 'MOD 干扰占比，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_building_coverage_m.use_heat_5g IS '5G 使用热度';
COMMENT ON COLUMN dmk.tm_building_coverage_m.user_count_4g IS '楼宇 4G 用户数，用于替换原无线市场份额指标';
COMMENT ON COLUMN dmk.tm_building_coverage_m.user_count_5g IS '楼宇 5G 用户数，用于替换原无线市场份额指标';
COMMENT ON COLUMN dmk.tm_building_coverage_m.user_market_share_4g IS '楼宇 4G 用户市场份额';
COMMENT ON COLUMN dmk.tm_building_coverage_m.user_market_share_5g IS '楼宇 5G 用户市场份额';
COMMENT ON COLUMN dmk.tm_building_coverage_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_building_cov_filter ON dmk.tm_building_coverage_m(year_month, data_type, provincecode, citycode, districtcode, building_type, operator_name, network_class);
CREATE INDEX IF NOT EXISTS idx_tm_building_cov_report ON dmk.tm_building_coverage_m(year_month, citycode, building_type, grid_cover_rate_110 DESC);
CREATE INDEX IF NOT EXISTS idx_tm_building_cov_geom ON dmk.tm_building_coverage_m USING gist(aoi_geom) WHERE aoi_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.tm_building_user_wifi_m (
    year_month varchar(7) NOT NULL,
    building_id varchar(64) NOT NULL,
    building_name varchar(128),
    building_type varchar(64),
    provincecode integer,
    citycode integer,
    districtcode integer,
    operator_name varchar(32) NOT NULL,
    wifi_total_user_count bigint,
    wifi_user_count bigint,
    wifi_market_share numeric(12, 6),
    wifi_signal_strength numeric(10, 4),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, building_id, operator_name)
);

COMMENT ON TABLE dmk.tm_building_user_wifi_m IS '楼宇 WiFi 指标月表，楼宇 4G/5G_SA 用户数和市场份额落在 tm_building_coverage_m。';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.building_id IS '楼宇 ID';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.building_name IS '楼宇名称';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.building_type IS '楼宇类型编码';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.wifi_total_user_count IS '楼宇内 WiFi 总用户数';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.wifi_user_count IS '本运营商 WiFi 用户数';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.wifi_market_share IS '本运营商 WiFi 市场份额';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.wifi_signal_strength IS 'WiFi 平均信号强度（dBm）';
COMMENT ON COLUMN dmk.tm_building_user_wifi_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_building_user_wifi_query ON dmk.tm_building_user_wifi_m(year_month, provincecode, citycode, districtcode, building_type);

CREATE TABLE IF NOT EXISTS dmk.tm_scene_coverage_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    data_type integer NOT NULL,
    scene_id varchar(64) NOT NULL,
    scene_name varchar(128) NOT NULL,
    scene_type varchar(64) NOT NULL,
    scene_type_name varchar(128),
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    bbox numeric(10, 6)[],
    aoi_wkt text,
    aoi_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN aoi_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(aoi_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    freq varchar(32) NOT NULL DEFAULT 'all',
    indoor_flag smallint NOT NULL DEFAULT -1,
    rsrpcount bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_105 bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_110 bigint NOT NULL DEFAULT 0,
    grid_count bigint NOT NULL DEFAULT 0,
    mr_grid_count bigint NOT NULL DEFAULT 0,
    covered_grid_count_105 bigint NOT NULL DEFAULT 0,
    covered_grid_count_110 bigint NOT NULL DEFAULT 0,
    mr_cover_rate_105 numeric(12, 6),
    mr_cover_rate_110 numeric(12, 6),
    grid_cover_rate_105 numeric(12, 6),
    grid_cover_rate_110 numeric(12, 6),
    avgrsrp numeric(10, 4),
    avgsinr numeric(10, 4),
    weakcover_mrcount bigint NOT NULL DEFAULT 0,
    overlap_mrcount bigint NOT NULL DEFAULT 0,
    overlap_total_value numeric(20, 4),
    overlap_rate numeric(12, 6),
    overlap_avgrsrp numeric(10, 4),
    overshoot_mrcount bigint NOT NULL DEFAULT 0,
    overshoot_total_value numeric(20, 4),
    overshoot_rate numeric(12, 6),
    overshoot_avgrsrp numeric(10, 4),
    mod_interference_mrcount bigint NOT NULL DEFAULT 0,
    mod_interference_total_value numeric(20, 4),
    mod_interference_avgrsrp numeric(10, 4),
    mod_interference_ratio numeric(12, 6),
    total_user_count bigint,
    user_count_4g bigint,
    user_count_5g bigint,
    user_ratio_4g numeric(12, 6),
    user_ratio_5g numeric(12, 6),
    total_user_market_share numeric(12, 6),
    user_market_share_4g numeric(12, 6),
    user_market_share_5g numeric(12, 6),
    operator_5g_reside_rate numeric(12, 6),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, scene_id, operator_name, network_class, freq, indoor_flag)
);

COMMENT ON TABLE dmk.tm_scene_coverage_m IS '重点场景覆盖指标月表，回填场景维度字段，支撑场景概览、用户分析、对比和报表。';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.grid_count IS '场景覆盖范围内总栅格数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.mr_grid_count IS '场景覆盖范围内有 MR 采样点的栅格数，作为场景栅格覆盖率的分母';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.scene_id IS '场景 ID';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.scene_name IS '场景名称';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.scene_type IS '场景类型编码';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.scene_type_name IS '场景类型名称';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.center_lon IS '场景中心点经度';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.center_lat IS '场景中心点纬度';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.bbox IS '场景外接矩形';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.aoi_wkt IS '场景 AOI WKT';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.aoi_geom IS '由 aoi_wkt 生成的 MultiPolygon 几何列';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.freq IS '频段';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.indoor_flag IS '室内外标识';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.rsrpcount IS '场景覆盖范围内 MR 采样数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.rsrpgoodcount_105 IS 'RSRP≥-105 的采样数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.rsrpgoodcount_110 IS 'RSRP≥-110 的采样数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.covered_grid_count_105 IS '达到 -105 覆盖阈值的栅格数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.covered_grid_count_110 IS '达到 -110 覆盖阈值的栅格数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.mr_cover_rate_105 IS 'MR 覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.mr_cover_rate_110 IS 'MR 覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.grid_cover_rate_105 IS '栅格覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.grid_cover_rate_110 IS '栅格覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.avgrsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.avgsinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.weakcover_mrcount IS '弱覆盖采样数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overlap_mrcount IS '重叠覆盖采样数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overlap_total_value IS '重叠覆盖总值';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overlap_rate IS '重叠覆盖率';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overlap_avgrsrp IS '重叠覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overshoot_mrcount IS '过覆盖采样数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overshoot_total_value IS '过覆盖总值';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overshoot_rate IS '过覆盖率';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.overshoot_avgrsrp IS '过覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.mod_interference_mrcount IS 'MOD 干扰采样数，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.mod_interference_total_value IS 'MOD 干扰采样点总值，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.mod_interference_avgrsrp IS 'MOD 干扰平均 RSRP（dBm），4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.mod_interference_ratio IS 'MOD 干扰占比，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.total_user_count IS '场景内总用户数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.user_count_4g IS '4G 用户数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.user_count_5g IS '5G 用户数';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.user_ratio_4g IS '4G 用户占比';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.user_ratio_5g IS '5G 用户占比';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.total_user_market_share IS '总用户市场份额';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.user_market_share_4g IS '4G 用户市场份额';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.user_market_share_5g IS '5G 用户市场份额';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.operator_5g_reside_rate IS '运营商 5G 驻留比';
COMMENT ON COLUMN dmk.tm_scene_coverage_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_scene_cov_filter ON dmk.tm_scene_coverage_m(year_month, data_type, provincecode, citycode, scene_type, scene_name, operator_name, network_class);
CREATE INDEX IF NOT EXISTS idx_tm_scene_cov_geom ON dmk.tm_scene_coverage_m USING gist(aoi_geom) WHERE aoi_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.tm_scene_grid_coverage_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    data_type integer NOT NULL,
    scene_id varchar(64) NOT NULL,
    scene_name varchar(128) NOT NULL,
    scene_type varchar(64) NOT NULL,
    scene_type_name varchar(128),
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    freq varchar(32) NOT NULL DEFAULT 'all',
    indoor_flag smallint NOT NULL DEFAULT -1,
    regionid varchar(64) NOT NULL,
    x_offset_20 varchar(32) NOT NULL,
    y_offset_20 varchar(32) NOT NULL,
    grid_wkt text,
    grid_geom geometry(Polygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN grid_wkt IS NULL THEN NULL
             ELSE ST_GeomFromText(grid_wkt, 4326)::geometry(Polygon, 4326)
        END
    ) STORED,
    rsrpcount bigint NOT NULL DEFAULT 0,
    avgrsrp numeric(10, 4),
    avgsinr numeric(10, 4),
    mr_cover_rate_105 numeric(12, 6),
    mr_cover_rate_110 numeric(12, 6),
    grid_cover_rate_105 numeric(12, 6),
    grid_cover_rate_110 numeric(12, 6),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, scene_id, regionid, x_offset_20, y_offset_20, operator_name, network_class, freq, indoor_flag)
);

COMMENT ON TABLE dmk.tm_scene_grid_coverage_m IS '重点场景栅格桥接月表，支撑 /api/scenes/layer 与场景栅格发布。';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.scene_id IS '场景 ID';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.scene_name IS '场景名称';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.scene_type IS '场景类型编码';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.scene_type_name IS '场景类型名称';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.freq IS '频段';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.indoor_flag IS '室内外标识';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.regionid IS '栅格区域 ID';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.x_offset_20 IS '栅格 X 偏移';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.y_offset_20 IS '栅格 Y 偏移';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.grid_wkt IS '栅格 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.grid_geom IS '由 grid_wkt 生成的 Polygon 几何列';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.rsrpcount IS '栅格 MR 采样数';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.avgrsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.avgsinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.mr_cover_rate_105 IS 'MR 覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.mr_cover_rate_110 IS 'MR 覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.grid_cover_rate_105 IS '栅格覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.grid_cover_rate_110 IS '栅格覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_scene_grid_coverage_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_scene_grid_cov_filter ON dmk.tm_scene_grid_coverage_m(year_month, data_type, provincecode, citycode, scene_type, scene_name, operator_name, network_class);
CREATE INDEX IF NOT EXISTS idx_tm_scene_grid_cov_geom ON dmk.tm_scene_grid_coverage_m USING gist(grid_geom) WHERE grid_geom IS NOT NULL;

-- =========================================================
-- 5. 工参与小区覆盖指标表
-- =========================================================

CREATE TABLE IF NOT EXISTS dmk.td_building_grid_m (
    year_month varchar(7) NOT NULL,
    data_type integer NOT NULL,
    building_id varchar(64) NOT NULL,
    regionid varchar(64) NOT NULL,
    x_offset_20 varchar(32) NOT NULL,
    y_offset_20 varchar(32) NOT NULL,
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    freq varchar(32) NOT NULL DEFAULT 'all',
    indoor_flag smallint NOT NULL DEFAULT -1,
    building_name varchar(128),
    provincecode integer,
    citycode integer,
    districtcode integer,
    grid_wkt text,
    grid_geom geometry(Polygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN grid_wkt IS NULL THEN NULL
             ELSE ST_GeomFromText(grid_wkt, 4326)::geometry(Polygon, 4326)
        END
    ) STORED,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, building_id, regionid, x_offset_20, y_offset_20, operator_name, network_class, freq, indoor_flag)
);

COMMENT ON TABLE dmk.td_building_grid_m IS '楼宇栅格桥接月表，支撑 /api/buildings/layer 和楼宇-栅格关联。';
COMMENT ON COLUMN dmk.td_building_grid_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.td_building_grid_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.td_building_grid_m.building_id IS '楼宇 ID';
COMMENT ON COLUMN dmk.td_building_grid_m.regionid IS '栅格区域 ID';
COMMENT ON COLUMN dmk.td_building_grid_m.x_offset_20 IS '栅格 X 偏移';
COMMENT ON COLUMN dmk.td_building_grid_m.y_offset_20 IS '栅格 Y 偏移';
COMMENT ON COLUMN dmk.td_building_grid_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.td_building_grid_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.td_building_grid_m.freq IS '频段';
COMMENT ON COLUMN dmk.td_building_grid_m.indoor_flag IS '室内外标识';
COMMENT ON COLUMN dmk.td_building_grid_m.building_name IS '楼宇名称（冗余）';
COMMENT ON COLUMN dmk.td_building_grid_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.td_building_grid_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.td_building_grid_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.td_building_grid_m.grid_wkt IS '栅格 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.td_building_grid_m.grid_geom IS '由 grid_wkt 生成的 Polygon 几何列';
COMMENT ON COLUMN dmk.td_building_grid_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_td_building_grid_query ON dmk.td_building_grid_m(year_month, data_type, provincecode, citycode, districtcode, operator_name, network_class, freq, indoor_flag);
CREATE INDEX IF NOT EXISTS idx_td_building_grid_geom ON dmk.td_building_grid_m USING gist(grid_geom) WHERE grid_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.td_building_cell_m (
    year_month varchar(7) NOT NULL,
    data_type integer NOT NULL,
    building_id varchar(64) NOT NULL,
    cellkey varchar(64) NOT NULL,
    cell_name varchar(128),
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    freq varchar(32) NOT NULL DEFAULT 'all',
    indoor_flag smallint NOT NULL DEFAULT -1,
    provincecode integer,
    citycode integer,
    districtcode integer,
    cell_lon numeric(10, 6),
    cell_lat numeric(10, 6),
    cell_wkt text,
    cell_geom geometry(Point, 4326) GENERATED ALWAYS AS (
        CASE WHEN cell_wkt IS NOT NULL THEN ST_GeomFromText(cell_wkt, 4326)::geometry(Point, 4326)
             WHEN cell_lon IS NOT NULL AND cell_lat IS NOT NULL THEN ST_SetSRID(ST_MakePoint(cell_lon, cell_lat), 4326)::geometry(Point, 4326)
             ELSE NULL
        END
    ) STORED,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, building_id, cellkey, operator_name, network_class, freq, indoor_flag)
);

COMMENT ON TABLE dmk.td_building_cell_m IS '楼宇小区桥接月表，支撑 /api/buildings/cells 与楼宇-小区关联。';
COMMENT ON COLUMN dmk.td_building_cell_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.td_building_cell_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.td_building_cell_m.building_id IS '楼宇 ID';
COMMENT ON COLUMN dmk.td_building_cell_m.cellkey IS '小区唯一键 cellkey';
COMMENT ON COLUMN dmk.td_building_cell_m.cell_name IS '小区名称（冗余）';
COMMENT ON COLUMN dmk.td_building_cell_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.td_building_cell_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.td_building_cell_m.freq IS '频段';
COMMENT ON COLUMN dmk.td_building_cell_m.indoor_flag IS '室内外标识';
COMMENT ON COLUMN dmk.td_building_cell_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.td_building_cell_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.td_building_cell_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.td_building_cell_m.cell_lon IS '小区经度';
COMMENT ON COLUMN dmk.td_building_cell_m.cell_lat IS '小区纬度';
COMMENT ON COLUMN dmk.td_building_cell_m.cell_wkt IS '小区点 WKT';
COMMENT ON COLUMN dmk.td_building_cell_m.cell_geom IS '小区点几何列（由 cell_wkt 或经纬度生成）';
COMMENT ON COLUMN dmk.td_building_cell_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_td_building_cell_query ON dmk.td_building_cell_m(year_month, data_type, provincecode, citycode, districtcode, operator_name, network_class, freq, indoor_flag);
CREATE INDEX IF NOT EXISTS idx_td_building_cell_geom ON dmk.td_building_cell_m USING gist(cell_geom) WHERE cell_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.tm_cell_grid_coverage_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    data_type integer NOT NULL,
    operator_name varchar(32) NOT NULL,
    network_class varchar(32) NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    cellkey varchar(64) NOT NULL,
    cell_name varchar(128),
    cell_lon numeric(10, 6),
    cell_lat numeric(10, 6),
    cell_wkt text,
    cell_geom geometry(Point, 4326) GENERATED ALWAYS AS (
        CASE WHEN cell_wkt IS NOT NULL THEN ST_GeomFromText(cell_wkt, 4326)::geometry(Point, 4326)
             WHEN cell_lon IS NOT NULL AND cell_lat IS NOT NULL THEN ST_SetSRID(ST_MakePoint(cell_lon, cell_lat), 4326)::geometry(Point, 4326)
             ELSE NULL
        END
    ) STORED,
    pci varchar(32),
    indoor_flag smallint NOT NULL DEFAULT -1,
    azimuth integer,
    freq varchar(32) NOT NULL DEFAULT 'all',
    vendor varchar(64),
    antenna_height numeric(10, 2),
    mechanical_downdip numeric(10, 2),
    electron_downdip numeric(10, 2),
    cover_type varchar(64),
    rspower numeric(12, 4),
    regionid varchar(64) NOT NULL,
    x_offset_20 varchar(32) NOT NULL,
    y_offset_20 varchar(32) NOT NULL,
    grid_lon numeric(10, 6),
    grid_lat numeric(10, 6),
    grid_wkt text,
    grid_geom geometry(Polygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN grid_wkt IS NULL THEN NULL
             ELSE ST_GeomFromText(grid_wkt, 4326)::geometry(Polygon, 4326)
        END
    ) STORED,
    cell_grid_line_wkt text,
    cell_grid_line_geom geometry(LineString, 4326) GENERATED ALWAYS AS (
        CASE WHEN cell_grid_line_wkt IS NULL THEN NULL
             ELSE ST_GeomFromText(cell_grid_line_wkt, 4326)::geometry(LineString, 4326)
        END
    ) STORED,
    rsrpcount bigint NOT NULL DEFAULT 0,
    totalrsrp numeric(20, 4),
    totalsinr numeric(20, 4),
    avgrsrp numeric(10, 4),
    avg_sinr numeric(10, 4),
    rsrpgoodcount_105 bigint NOT NULL DEFAULT 0,
    rsrpgoodcount_110 bigint NOT NULL DEFAULT 0,
    mr_cover_rate_105 numeric(12, 6),
    mr_cover_rate_110 numeric(12, 6),
    weakcover_mrcount bigint NOT NULL DEFAULT 0,
    overlap_mrcount bigint NOT NULL DEFAULT 0,
    overlap_total_value numeric(20, 4),
    overlap_rate numeric(12, 6),
    overlap_avgrsrp numeric(10, 4),
    overshoot_mrcount bigint NOT NULL DEFAULT 0,
    overshoot_total_value numeric(20, 4),
    overshoot_rate numeric(12, 6),
    overshoot_avgrsrp numeric(10, 4),
    mod_interference_mrcount bigint NOT NULL DEFAULT 0,
    mod_interference_total_value numeric(20, 4),
    mod_interference_avgrsrp numeric(10, 4),
    mod_interference_ratio numeric(12, 6),
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, data_type, operator_name, network_class, freq, indoor_flag, cellkey, regionid, x_offset_20, y_offset_20)
);

COMMENT ON TABLE dmk.tm_cell_grid_coverage_m IS '小区覆盖栅格月表，支撑单小区覆盖栅格、栅格 TOP 小区和栅格-小区连线。';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cellkey IS '小区唯一键 cellkey';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cell_name IS '小区名称';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cell_lon IS '小区经度';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cell_lat IS '小区纬度';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cell_wkt IS '小区点 WKT';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cell_geom IS '小区点几何列';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.pci IS '物理小区标识 PCI';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.indoor_flag IS '室内外标识';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.azimuth IS '天线方位角（度）';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.freq IS '频段';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.vendor IS '设备厂家';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.antenna_height IS '天线挂高（米）';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.mechanical_downdip IS '机械下倾角';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.electron_downdip IS '电子下倾角';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cover_type IS '覆盖类型';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.rspower IS '参考信号发射功率';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.regionid IS '覆盖栅格区域 ID';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.x_offset_20 IS '覆盖栅格 X 偏移';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.y_offset_20 IS '覆盖栅格 Y 偏移';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.grid_lon IS '覆盖栅格中心点经度';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.grid_lat IS '覆盖栅格中心点纬度';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.grid_wkt IS '覆盖栅格 WKT';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.grid_geom IS '覆盖栅格 Polygon 几何列';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cell_grid_line_wkt IS '小区→栅格连线 WKT（LineString）';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.cell_grid_line_geom IS '小区→栅格连线 LineString 几何列';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.rsrpcount IS '该小区在该栅格的 MR 采样数';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.totalrsrp IS 'RSRP 累加值';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.totalsinr IS 'SINR 累加值';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.avgrsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.avg_sinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.rsrpgoodcount_105 IS 'RSRP≥-105 的采样数';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.rsrpgoodcount_110 IS 'RSRP≥-110 的采样数';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.mr_cover_rate_105 IS 'MR 覆盖率(-105)';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.mr_cover_rate_110 IS 'MR 覆盖率(-110)';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.weakcover_mrcount IS '弱覆盖采样数';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overlap_mrcount IS '重叠覆盖采样数';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overlap_total_value IS '重叠覆盖总值';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overlap_rate IS '重叠覆盖率';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overlap_avgrsrp IS '重叠覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overshoot_mrcount IS '过覆盖采样数';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overshoot_total_value IS '过覆盖总值';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overshoot_rate IS '过覆盖率';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.overshoot_avgrsrp IS '过覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.mod_interference_mrcount IS 'MOD 干扰采样数，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.mod_interference_total_value IS 'MOD 干扰采样点总值，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.mod_interference_avgrsrp IS 'MOD 干扰平均 RSRP（dBm），4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.mod_interference_ratio IS 'MOD 干扰占比，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cell_grid_coverage_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_cell_grid_cell ON dmk.tm_cell_grid_coverage_m(year_month, cellkey, network_class, rsrpcount DESC);
CREATE INDEX IF NOT EXISTS idx_tm_cell_grid_grid ON dmk.tm_cell_grid_coverage_m(year_month, regionid, x_offset_20, y_offset_20, operator_name, network_class, rsrpcount DESC);
CREATE INDEX IF NOT EXISTS idx_tm_cell_grid_cell_geom ON dmk.tm_cell_grid_coverage_m USING gist(cell_geom) WHERE cell_geom IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_tm_cell_grid_grid_geom ON dmk.tm_cell_grid_coverage_m USING gist(grid_geom) WHERE grid_geom IS NOT NULL;

-- =========================================================
-- 6. 聚类、加权得分与质差指标表
-- =========================================================

CREATE TABLE IF NOT EXISTS dmk.tm_cluster_area_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    data_type integer NOT NULL,
    cluster_id varchar(64) NOT NULL,
    cluster_name varchar(128),
    cluster_type varchar(64) NOT NULL,
    top_type varchar(32) NOT NULL DEFAULT 'all',
    network_class varchar(32) NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    bbox numeric(10, 6)[],
    area_wkt text,
    area_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN area_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(area_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    grid_count bigint NOT NULL DEFAULT 0,
    covered_grid_count bigint NOT NULL DEFAULT 0,
    weak_grid_count bigint NOT NULL DEFAULT 0,
    weak_grid_ratio numeric(12, 6),
    area_size numeric(18, 4),
    perimeter numeric(18, 4),
    weighted_score numeric(12, 6),
    business_score numeric(12, 6),
    area_score numeric(12, 6),
    value_score numeric(12, 6),
    coverage_score numeric(12, 6),
    user_score numeric(12, 6),
    rsrpcount bigint NOT NULL DEFAULT 0,
    weakcover_mrcount bigint NOT NULL DEFAULT 0,
    overlap_mrcount bigint NOT NULL DEFAULT 0,
    overlap_total_value numeric(20, 4),
    overlap_rate numeric(12, 6),
    overlap_avgrsrp numeric(10, 4),
    overshoot_mrcount bigint NOT NULL DEFAULT 0,
    overshoot_total_value numeric(20, 4),
    overshoot_rate numeric(12, 6),
    overshoot_avgrsrp numeric(10, 4),
    mod_interference_mrcount bigint NOT NULL DEFAULT 0,
    mod_interference_total_value numeric(20, 4),
    mod_interference_avgrsrp numeric(10, 4),
    mod_interference_ratio numeric(12, 6),
    avg_rsrp numeric(10, 4),
    avg_sinr numeric(10, 4),
    mr_cover_rate numeric(12, 6),
    total_user_count bigint,
    user_count_4g bigint,
    user_count_5g bigint,
    user_density numeric(18, 4),
    high_value_user_ratio numeric(12, 6),
    avg_arpu numeric(12, 4),
    vip_user_count bigint,
    total_traffic_gb numeric(18, 4),
    voice_minutes numeric(18, 4),
    video_user_ratio numeric(12, 6),
    related_scene_count integer,
    is_feedback smallint NOT NULL DEFAULT 0,
    rank_no integer,
    percent_rank numeric(12, 6),
    feedback_source varchar(32),
    update_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, cluster_id)
);

COMMENT ON TABLE dmk.tm_cluster_area_m IS '聚类区域月表，支撑聚类清单、加权得分、多维分析和聚类区域 WMS。';
COMMENT ON COLUMN dmk.tm_cluster_area_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_cluster_area_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_cluster_area_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_cluster_area_m.data_type IS '数据来源类型';
COMMENT ON COLUMN dmk.tm_cluster_area_m.cluster_id IS '聚类区域 ID';
COMMENT ON COLUMN dmk.tm_cluster_area_m.cluster_name IS '聚类区域名称';
COMMENT ON COLUMN dmk.tm_cluster_area_m.cluster_type IS '聚类类型（弱覆盖/超忙/综合质差等）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.top_type IS 'TOP 档位标识：top10/top50/all 等';
COMMENT ON COLUMN dmk.tm_cluster_area_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_cluster_area_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_cluster_area_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_cluster_area_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_cluster_area_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_cluster_area_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_cluster_area_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_cluster_area_m.center_lon IS '聚类区域中心点经度';
COMMENT ON COLUMN dmk.tm_cluster_area_m.center_lat IS '聚类区域中心点纬度';
COMMENT ON COLUMN dmk.tm_cluster_area_m.bbox IS '聚类区域外接矩形';
COMMENT ON COLUMN dmk.tm_cluster_area_m.area_wkt IS '聚类区域 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.tm_cluster_area_m.area_geom IS '聚类区域 MultiPolygon 几何列';
COMMENT ON COLUMN dmk.tm_cluster_area_m.grid_count IS '聚类区域内栅格总数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.covered_grid_count IS '聚类区域内已覆盖栅格数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.weak_grid_count IS '聚类区域内弱覆盖栅格数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.weak_grid_ratio IS '弱覆盖栅格占比';
COMMENT ON COLUMN dmk.tm_cluster_area_m.area_size IS '聚类区域面积（平方米）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.perimeter IS '聚类区域周长（米）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.weighted_score IS '聚类加权综合得分';
COMMENT ON COLUMN dmk.tm_cluster_area_m.business_score IS '业务维度得分';
COMMENT ON COLUMN dmk.tm_cluster_area_m.area_score IS '区域维度得分';
COMMENT ON COLUMN dmk.tm_cluster_area_m.value_score IS '价值维度得分';
COMMENT ON COLUMN dmk.tm_cluster_area_m.coverage_score IS '覆盖维度得分';
COMMENT ON COLUMN dmk.tm_cluster_area_m.user_score IS '用户维度得分';
COMMENT ON COLUMN dmk.tm_cluster_area_m.rsrpcount IS '聚类区域内 RSRP 采样点数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.weakcover_mrcount IS '聚类区域内弱覆盖采样数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overlap_mrcount IS '聚类区域内重叠覆盖采样数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overlap_total_value IS '聚类区域内重叠覆盖总值';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overlap_rate IS '聚类区域内重叠覆盖率';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overlap_avgrsrp IS '聚类区域内重叠覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overshoot_mrcount IS '聚类区域内过覆盖采样数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overshoot_total_value IS '聚类区域内过覆盖总值';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overshoot_rate IS '聚类区域内过覆盖率';
COMMENT ON COLUMN dmk.tm_cluster_area_m.overshoot_avgrsrp IS '聚类区域内过覆盖平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.mod_interference_mrcount IS '聚类区域内 MOD 干扰采样数，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cluster_area_m.mod_interference_total_value IS '聚类区域内 MOD 干扰采样点总值，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cluster_area_m.mod_interference_avgrsrp IS '聚类区域内 MOD 干扰平均 RSRP（dBm），4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cluster_area_m.mod_interference_ratio IS '聚类区域内 MOD 干扰占比，4G 按 MOD3、5G 按 MOD30 解释';
COMMENT ON COLUMN dmk.tm_cluster_area_m.avg_rsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.avg_sinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.mr_cover_rate IS 'MR 覆盖率';
COMMENT ON COLUMN dmk.tm_cluster_area_m.total_user_count IS '区域内总用户数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.user_count_4g IS '4G 用户数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.user_count_5g IS '5G 用户数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.user_density IS '用户密度（人/平方公里）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.high_value_user_ratio IS '高价值用户占比';
COMMENT ON COLUMN dmk.tm_cluster_area_m.avg_arpu IS '平均 ARPU';
COMMENT ON COLUMN dmk.tm_cluster_area_m.vip_user_count IS 'VIP 用户数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.total_traffic_gb IS '总流量（GB）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.voice_minutes IS '语音业务时长（分钟）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.video_user_ratio IS '视频用户占比';
COMMENT ON COLUMN dmk.tm_cluster_area_m.related_scene_count IS '关联场景数';
COMMENT ON COLUMN dmk.tm_cluster_area_m.is_feedback IS '是否已反馈：0=未反馈 1=已反馈';
COMMENT ON COLUMN dmk.tm_cluster_area_m.rank_no IS '加权得分排名（同档位内）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.percent_rank IS '排名分位数（0-1）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.feedback_source IS '反馈来源（manual/system/external 等）';
COMMENT ON COLUMN dmk.tm_cluster_area_m.update_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_cluster_area_filter ON dmk.tm_cluster_area_m(year_month, data_type, provincecode, citycode, network_class, cluster_type, top_type, weighted_score DESC);
CREATE INDEX IF NOT EXISTS idx_tm_cluster_area_geom ON dmk.tm_cluster_area_m USING gist(area_geom) WHERE area_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.tm_cluster_feedback (
    feedback_id varchar(64) PRIMARY KEY,
    year_month varchar(7) NOT NULL,
    cluster_id varchar(64) NOT NULL,
    problem_reason_type varchar(64) NOT NULL,
    solution_type varchar(64) NOT NULL,
    problem_desc text NOT NULL,
    solution_desc text NOT NULL,
    feedback_user varchar(64) NOT NULL,
    feedback_source varchar(32) NOT NULL DEFAULT 'manual',
    is_feedback smallint NOT NULL DEFAULT 1,
    updated_by varchar(64),
    update_time timestamp without time zone NOT NULL DEFAULT now()
);

COMMENT ON TABLE dmk.tm_cluster_feedback IS '质差聚类区域反馈表，保存问题根因、解决措施和反馈来源。';
COMMENT ON COLUMN dmk.tm_cluster_feedback.feedback_id IS '反馈记录 ID';
COMMENT ON COLUMN dmk.tm_cluster_feedback.year_month IS '所属账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_cluster_feedback.cluster_id IS '聚类区域 ID';
COMMENT ON COLUMN dmk.tm_cluster_feedback.problem_reason_type IS '问题根因类型编码';
COMMENT ON COLUMN dmk.tm_cluster_feedback.solution_type IS '解决措施类型编码';
COMMENT ON COLUMN dmk.tm_cluster_feedback.problem_desc IS '问题描述（自由文本）';
COMMENT ON COLUMN dmk.tm_cluster_feedback.solution_desc IS '解决措施描述（自由文本）';
COMMENT ON COLUMN dmk.tm_cluster_feedback.feedback_user IS '反馈提交用户账号';
COMMENT ON COLUMN dmk.tm_cluster_feedback.feedback_source IS '反馈来源：manual/system/external 等';
COMMENT ON COLUMN dmk.tm_cluster_feedback.is_feedback IS '是否有效反馈：1=是 0=已撤销';
COMMENT ON COLUMN dmk.tm_cluster_feedback.updated_by IS '最后更新人账号';
COMMENT ON COLUMN dmk.tm_cluster_feedback.update_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_cluster_feedback_query ON dmk.tm_cluster_feedback(year_month, cluster_id, update_time DESC);

CREATE TABLE IF NOT EXISTS dmk.tm_poor_region_metric_m (
    year_month varchar(7) NOT NULL,
    year integer NOT NULL,
    month integer NOT NULL,
    region_level varchar(16) NOT NULL,
    region_code integer NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    stat_type varchar(32) NOT NULL,
    poor_type varchar(32) NOT NULL,
    metric_group varchar(64) NOT NULL,
    scene_type varchar(64) NOT NULL DEFAULT 'all',
    scene_type_name varchar(128),
    network_class varchar(32) NOT NULL DEFAULT 'all',
    metric_code varchar(64) NOT NULL,
    metric_name varchar(128),
    metric_value numeric(20, 6),
    rank_no integer,
    scene_count bigint,
    cell_count bigint,
    traffic_count numeric(20, 6),
    poor_scene_count bigint,
    poor_cell_count bigint,
    busy_cell_count bigint,
    region_wkt text,
    region_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN region_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(region_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, region_level, region_code, stat_type, poor_type, metric_group, scene_type, network_class, metric_code)
);

COMMENT ON TABLE dmk.tm_poor_region_metric_m IS '质差区域指标月表，统一支撑概览、走势、GIS 地图和指标排名。';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.year IS '账期年份';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.month IS '账期月份';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.region_level IS '区域级别';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.region_code IS '区域编码';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.stat_type IS '统计页签类型（概览/趋势/地图/排名）';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.poor_type IS '质差类型（弱覆盖/超忙/感知差等）';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.metric_group IS '指标分组';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.scene_type IS '场景类型，all 表示全部场景';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.scene_type_name IS '场景类型名称';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.metric_code IS '指标编码';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.metric_name IS '指标名称';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.metric_value IS '指标值';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.rank_no IS '排名序号';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.scene_count IS '场景数量';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.cell_count IS '小区数量';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.traffic_count IS '业务量统计值';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.poor_scene_count IS '质差场景数量';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.poor_cell_count IS '质差小区数量';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.busy_cell_count IS '超忙小区数量';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.region_wkt IS '区域 WKT，EPSG:4326';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.region_geom IS '区域 MultiPolygon 几何列';
COMMENT ON COLUMN dmk.tm_poor_region_metric_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_poor_region_metric_query ON dmk.tm_poor_region_metric_m(year_month, region_level, provincecode, citycode, stat_type, poor_type, metric_group, scene_type, network_class, metric_code, rank_no);
CREATE INDEX IF NOT EXISTS idx_tm_poor_region_metric_geom ON dmk.tm_poor_region_metric_m USING gist(region_geom) WHERE region_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.tm_poor_scene_list_m (
    year_month varchar(7) NOT NULL,
    poor_scene_id varchar(64) NOT NULL,
    poor_type varchar(32) NOT NULL,
    metric_group varchar(64) NOT NULL,
    scene_id varchar(64) NOT NULL,
    scene_name varchar(128) NOT NULL,
    scene_type varchar(64) NOT NULL,
    scene_type_name varchar(128),
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    center_lon numeric(10, 6),
    center_lat numeric(10, 6),
    bbox numeric(10, 6)[],
    aoi_wkt text,
    aoi_geom geometry(MultiPolygon, 4326) GENERATED ALWAYS AS (
        CASE WHEN aoi_wkt IS NULL THEN NULL
             ELSE ST_Multi(ST_GeomFromText(aoi_wkt, 4326))::geometry(MultiPolygon, 4326)
        END
    ) STORED,
    avg_rsrp numeric(10, 4),
    avg_sinr numeric(10, 4),
    grid_count bigint,
    weak_grid_count bigint,
    weak_grid_ratio numeric(12, 6),
    grid_cover_rate numeric(12, 6),
    mr_cover_rate numeric(12, 6),
    total_user_count bigint,
    total_traffic_gb numeric(18, 4),
    voice_drop_rate numeric(12, 6),
    perception_score numeric(12, 6),
    rank_no integer,
    poor_reason varchar(128),
    poor_reason_name varchar(128),
    update_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, poor_scene_id)
);

COMMENT ON TABLE dmk.tm_poor_scene_list_m IS '质差场景清单月表，支撑清单查询、排序和导出。';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.poor_scene_id IS '质差场景记录 ID';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.poor_type IS '质差类型';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.metric_group IS '指标分组';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.scene_id IS '场景 ID';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.scene_name IS '场景名称';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.scene_type IS '场景类型编码';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.scene_type_name IS '场景类型名称';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.center_lon IS '场景中心点经度';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.center_lat IS '场景中心点纬度';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.bbox IS '场景外接矩形';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.aoi_wkt IS '场景 AOI WKT';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.aoi_geom IS '场景 AOI MultiPolygon 几何列';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.avg_rsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.avg_sinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.grid_count IS '场景内栅格数';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.weak_grid_count IS '弱覆盖栅格数';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.weak_grid_ratio IS '弱覆盖栅格占比';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.grid_cover_rate IS '栅格覆盖率';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.mr_cover_rate IS 'MR 覆盖率';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.total_user_count IS '场景内总用户数';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.total_traffic_gb IS '总流量（GB）';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.voice_drop_rate IS '语音掉话率';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.perception_score IS '感知评分';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.rank_no IS '清单内排名';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.poor_reason IS '质差原因编码';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.poor_reason_name IS '质差原因名称';
COMMENT ON COLUMN dmk.tm_poor_scene_list_m.update_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_poor_scene_list_query ON dmk.tm_poor_scene_list_m(year_month, provincecode, citycode, scene_type, rank_no, grid_cover_rate);
CREATE INDEX IF NOT EXISTS idx_tm_poor_scene_list_geom ON dmk.tm_poor_scene_list_m USING gist(aoi_geom) WHERE aoi_geom IS NOT NULL;

CREATE TABLE IF NOT EXISTS dmk.tm_poor_cell_list_m (
    year_month varchar(7) NOT NULL,
    poor_cell_id varchar(64) NOT NULL,
    poor_type varchar(32) NOT NULL,
    metric_group varchar(64),
    cellkey varchar(64) NOT NULL,
    cell_name varchar(128),
    operator_name varchar(32),
    network_class varchar(32) NOT NULL,
    provincecode integer,
    province_name varchar(64),
    citycode integer,
    city_name varchar(64),
    districtcode integer,
    district_name varchar(64),
    scene_id varchar(64),
    scene_name varchar(128),
    scene_type varchar(64),
    scene_type_name varchar(128),
    cell_lon numeric(10, 6),
    cell_lat numeric(10, 6),
    cell_wkt text,
    cell_geom geometry(Point, 4326) GENERATED ALWAYS AS (
        CASE WHEN cell_wkt IS NOT NULL THEN ST_GeomFromText(cell_wkt, 4326)::geometry(Point, 4326)
             WHEN cell_lon IS NOT NULL AND cell_lat IS NOT NULL THEN ST_SetSRID(ST_MakePoint(cell_lon, cell_lat), 4326)::geometry(Point, 4326)
             ELSE NULL
        END
    ) STORED,
    rsrpcount bigint,
    avg_rsrp numeric(10, 4),
    avg_sinr numeric(10, 4),
    weakcover_mrcount bigint,
    busy_user_count bigint,
    traffic_total numeric(18, 4),
    total_traffic_gb numeric(18, 4),
    voice_drop_rate numeric(12, 6),
    perception_score numeric(12, 6),
    rank_no integer,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    PRIMARY KEY (year_month, poor_cell_id)
);

COMMENT ON TABLE dmk.tm_poor_cell_list_m IS '质差小区/超忙小区清单月表，保留 traffic_total 与 total_traffic_gb 兼容导出。';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.year_month IS '账期，格式 YYYY-MM';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.poor_cell_id IS '质差小区记录 ID';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.poor_type IS '质差类型（质差/超忙等）';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.metric_group IS '指标分组';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.cellkey IS '小区唯一键 cellkey';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.cell_name IS '小区名称';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.operator_name IS '运营商名称';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.network_class IS '网络制式';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.provincecode IS '省编码';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.province_name IS '省名称';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.citycode IS '地市编码';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.city_name IS '地市名称';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.districtcode IS '区县编码';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.district_name IS '区县名称';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.scene_id IS '关联场景 ID';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.scene_name IS '关联场景名称';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.scene_type IS '关联场景类型编码';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.scene_type_name IS '关联场景类型名称';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.cell_lon IS '小区经度';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.cell_lat IS '小区纬度';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.cell_wkt IS '小区点 WKT';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.cell_geom IS '小区点几何列';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.rsrpcount IS 'MR 采样数';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.avg_rsrp IS '平均 RSRP（dBm）';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.avg_sinr IS '平均 SINR（dB）';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.weakcover_mrcount IS '弱覆盖采样数';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.busy_user_count IS '忙时用户数';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.traffic_total IS '业务量原始单位（兼容导出口径）';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.total_traffic_gb IS '总流量（GB）';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.voice_drop_rate IS '语音掉话率';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.perception_score IS '感知评分';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.rank_no IS '清单内排名';
COMMENT ON COLUMN dmk.tm_poor_cell_list_m.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_poor_cell_list_query ON dmk.tm_poor_cell_list_m(year_month, provincecode, citycode, poor_type, network_class, rank_no);
CREATE INDEX IF NOT EXISTS idx_tm_poor_cell_list_geom ON dmk.tm_poor_cell_list_m USING gist(cell_geom) WHERE cell_geom IS NOT NULL;

-- =========================================================
-- 7. 导出任务表
-- =========================================================

CREATE TABLE IF NOT EXISTS dmk.tm_export_task (
    task_id varchar(64) PRIMARY KEY,
    account_id varchar(64) NOT NULL,
    tenant varchar(64),
    biz_module varchar(64) NOT NULL,
    export_type varchar(64),
    request_param jsonb,
    export_columns varchar(128)[] NOT NULL DEFAULT ARRAY[]::varchar[],
    status varchar(32) NOT NULL,
    progress integer NOT NULL DEFAULT 0,
    file_name varchar(256),
    file_url text,
    file_size bigint,
    error_msg text,
    created_time timestamp without time zone NOT NULL DEFAULT now(),
    finish_time timestamp without time zone,
    updated_time timestamp without time zone NOT NULL DEFAULT now(),
    CHECK (status IN ('pending', 'processing', 'running', 'success', 'failed', 'canceled')),
    CHECK (progress BETWEEN 0 AND 100)
);

COMMENT ON TABLE dmk.tm_export_task IS '异步导出任务表，支撑导出详情、列表、取消、下载接口。';
COMMENT ON COLUMN dmk.tm_export_task.task_id IS '导出任务 ID';
COMMENT ON COLUMN dmk.tm_export_task.account_id IS '发起账号 ID';
COMMENT ON COLUMN dmk.tm_export_task.tenant IS '租户标识';
COMMENT ON COLUMN dmk.tm_export_task.biz_module IS '业务模块（building/scene/cluster/poor 等）';
COMMENT ON COLUMN dmk.tm_export_task.export_type IS '导出类型（excel/csv 等）';
COMMENT ON COLUMN dmk.tm_export_task.request_param IS '导出请求参数 JSON 快照';
COMMENT ON COLUMN dmk.tm_export_task.export_columns IS '导出字段列表（数组）';
COMMENT ON COLUMN dmk.tm_export_task.status IS '任务状态：pending/processing/running/success/failed/canceled';
COMMENT ON COLUMN dmk.tm_export_task.progress IS '任务进度（0-100）';
COMMENT ON COLUMN dmk.tm_export_task.file_name IS '导出文件名';
COMMENT ON COLUMN dmk.tm_export_task.file_url IS '导出文件下载地址';
COMMENT ON COLUMN dmk.tm_export_task.file_size IS '导出文件大小（字节）';
COMMENT ON COLUMN dmk.tm_export_task.error_msg IS '错误信息（失败时填充）';
COMMENT ON COLUMN dmk.tm_export_task.created_time IS '任务创建时间';
COMMENT ON COLUMN dmk.tm_export_task.finish_time IS '任务完成时间';
COMMENT ON COLUMN dmk.tm_export_task.updated_time IS '记录更新时间';
CREATE INDEX IF NOT EXISTS idx_tm_export_task_query ON dmk.tm_export_task(account_id, biz_module, status, created_time DESC);
