-- ============================================================
-- 关系图谱 MySQL 构建脚本
-- 说明：
-- 1. 执行前先执行 03_lx_relation_graph_mysql_ddl.sql。
-- 2. 本脚本优先写入家庭关系点边，再写入工商股东/法人点边。
-- 3. 点表和边表通过主键与聚合逻辑保证去重，可重复执行。
-- 4. 家庭个人点 object_key = MD5(身份证号)。
-- 5. 家庭边按两端 object_key 无向归并，夫妻双方都是员工时只保留一条边。
-- 6. 工商源表沿用现有关系图谱 SQL：sjfx_pro.t_eci_company_orc / sjfx_pro.t_eci_partner_orc。
-- ============================================================

SET SESSION group_concat_max_len = 8192;

-- ============================================================
-- Step 1. 家庭关系去重
-- 仅有证件号的家庭成员入图；无证件号无法生成身份证 MD5，本轮不入图。
-- ============================================================
DROP TEMPORARY TABLE IF EXISTS tmp_rel_family_dedup;
CREATE TEMPORARY TABLE tmp_rel_family_dedup AS
SELECT
    id,
    TRIM(person_id) AS person_id,
    TRIM(relation_type) AS relation_type,
    TRIM(relation_name) AS relation_name,
    TRIM(gender) AS gender,
    DATE_FORMAT(birth_date, '%Y-%m-%d') AS birth_date,
    TRIM(relation_cert_type) AS relation_cert_type,
    TRIM(relation_cert_no) AS relation_cert_no,
    TRIM(mobile_phone1) AS mobile_phone1,
    TRIM(mobile_phone2) AS mobile_phone2,
    TRIM(wechat_no1) AS wechat_no1,
    TRIM(wechat_no2) AS wechat_no2,
    TRIM(wechat_no3) AS wechat_no3,
    TRIM(contact_address) AS contact_address,
    annual_income,
    TRIM(relation_desc) AS relation_desc,
    status,
    DATE_FORMAT(effective_date, '%Y-%m-%d %H:%i:%s') AS effective_date,
    DATE_FORMAT(invalid_date, '%Y-%m-%d %H:%i:%s') AS invalid_date,
    TRIM(remark) AS remark,
    TRIM(data_source) AS data_source,
    create_time,
    update_time
FROM (
    SELECT
        r.*,
        ROW_NUMBER() OVER (
            PARTITION BY
                TRIM(r.person_id),
                TRIM(r.relation_type),
                TRIM(r.relation_name),
                TRIM(r.relation_cert_no)
            ORDER BY r.update_time DESC, r.create_time DESC, r.id DESC
        ) AS rn
    FROM ccdi_staff_fmy_relation r
    WHERE r.status = 1
      AND r.person_id IS NOT NULL
      AND TRIM(r.person_id) <> ''
      AND r.relation_type IS NOT NULL
      AND TRIM(r.relation_type) <> ''
      AND r.relation_name IS NOT NULL
      AND TRIM(r.relation_name) <> ''
      AND r.relation_cert_no IS NOT NULL
      AND TRIM(r.relation_cert_no) <> ''
) x
WHERE x.rn = 1;

-- ============================================================
-- Step 2. 家庭关系点：员工本人优先入图
-- ============================================================
INSERT INTO lx_rel_node (
    object_key,
    node_name,
    id_number,
    subject_type,
    source_type,
    detail_ref_type,
    detail_ref_key
)
SELECT
    MD5(f.person_id) AS object_key,
    COALESCE(NULLIF(MAX(TRIM(staff.name)), ''), f.person_id) AS node_name,
    f.person_id AS id_number,
    '个人' AS subject_type,
    '员工家庭关系-员工' AS source_type,
    'STAFF_FAMILY' AS detail_ref_type,
    f.person_id AS detail_ref_key
FROM tmp_rel_family_dedup f
LEFT JOIN ccdi_base_staff staff
    ON staff.id_card = f.person_id
GROUP BY f.person_id
ON DUPLICATE KEY UPDATE
    node_name = COALESCE(NULLIF(VALUES(node_name), ''), lx_rel_node.node_name),
    id_number = COALESCE(NULLIF(VALUES(id_number), ''), lx_rel_node.id_number),
    subject_type = COALESCE(NULLIF(lx_rel_node.subject_type, ''), VALUES(subject_type)),
    source_type = CASE
        WHEN lx_rel_node.source_type IS NULL OR lx_rel_node.source_type = '' THEN VALUES(source_type)
        WHEN FIND_IN_SET(VALUES(source_type), lx_rel_node.source_type) > 0 THEN lx_rel_node.source_type
        ELSE CONCAT(lx_rel_node.source_type, ',', VALUES(source_type))
    END,
    detail_ref_type = COALESCE(NULLIF(lx_rel_node.detail_ref_type, ''), VALUES(detail_ref_type)),
    detail_ref_key = COALESCE(NULLIF(lx_rel_node.detail_ref_key, ''), VALUES(detail_ref_key)),
    updated_time = CURRENT_TIMESTAMP;

-- ============================================================
-- Step 3. 家庭关系点：家属入图
-- 如果家属同时也是员工，主键一致，source_type 会合并。
-- ============================================================
INSERT INTO lx_rel_node (
    object_key,
    node_name,
    id_number,
    subject_type,
    source_type,
    detail_ref_type,
    detail_ref_key
)
SELECT
    MD5(f.relation_cert_no) AS object_key,
    COALESCE(NULLIF(MAX(TRIM(staff.name)), ''), MAX(f.relation_name)) AS node_name,
    f.relation_cert_no AS id_number,
    '个人' AS subject_type,
    '员工家庭关系-成员' AS source_type,
    'STAFF_FAMILY' AS detail_ref_type,
    f.relation_cert_no AS detail_ref_key
FROM tmp_rel_family_dedup f
LEFT JOIN ccdi_base_staff staff
    ON staff.id_card = f.relation_cert_no
GROUP BY f.relation_cert_no
ON DUPLICATE KEY UPDATE
    node_name = COALESCE(NULLIF(VALUES(node_name), ''), lx_rel_node.node_name),
    id_number = COALESCE(NULLIF(VALUES(id_number), ''), lx_rel_node.id_number),
    subject_type = COALESCE(NULLIF(lx_rel_node.subject_type, ''), VALUES(subject_type)),
    source_type = CASE
        WHEN lx_rel_node.source_type IS NULL OR lx_rel_node.source_type = '' THEN VALUES(source_type)
        WHEN FIND_IN_SET(VALUES(source_type), lx_rel_node.source_type) > 0 THEN lx_rel_node.source_type
        ELSE CONCAT(lx_rel_node.source_type, ',', VALUES(source_type))
    END,
    detail_ref_type = COALESCE(NULLIF(lx_rel_node.detail_ref_type, ''), VALUES(detail_ref_type)),
    detail_ref_key = COALESCE(NULLIF(lx_rel_node.detail_ref_key, ''), VALUES(detail_ref_key)),
    updated_time = CURRENT_TIMESTAMP;

-- ============================================================
-- Step 4. 家庭关系边：按两端 object_key 无向归并
-- ============================================================
DROP TEMPORARY TABLE IF EXISTS tmp_rel_family_edge_rows;
CREATE TEMPORARY TABLE tmp_rel_family_edge_rows AS
SELECT
    MD5(f.person_id) AS person_object_key,
    MD5(f.relation_cert_no) AS relation_object_key,
    LEAST(MD5(f.person_id), MD5(f.relation_cert_no)) AS from_object_key,
    GREATEST(MD5(f.person_id), MD5(f.relation_cert_no)) AS to_object_key,
    f.*
FROM tmp_rel_family_dedup f
WHERE f.person_id <> f.relation_cert_no;

INSERT INTO lx_rel_family_edge (
    object_key,
    from_key,
    to_key,
    person_id,
    relation_name,
    relation_type,
    relation_cert_no,
    gender,
    birth_date,
    relation_cert_type,
    mobile_phone1,
    mobile_phone2,
    wechat_no1,
    wechat_no2,
    wechat_no3,
    contact_address,
    annual_income,
    relation_desc,
    status,
    effective_date,
    invalid_date,
    remark,
    data_source
)
SELECT
    MD5(CONCAT('family|', from_object_key, '|', to_object_key)) AS object_key,
    CONCAT('rel_node/', from_object_key) AS from_key,
    CONCAT('rel_node/', to_object_key) AS to_key,
    GROUP_CONCAT(DISTINCT person_id ORDER BY person_id SEPARATOR '/') AS person_id,
    GROUP_CONCAT(DISTINCT relation_name ORDER BY relation_name SEPARATOR '/') AS relation_name,
    GROUP_CONCAT(DISTINCT relation_type ORDER BY relation_type SEPARATOR '/') AS relation_type,
    GROUP_CONCAT(DISTINCT relation_cert_no ORDER BY relation_cert_no SEPARATOR '/') AS relation_cert_no,
    GROUP_CONCAT(DISTINCT NULLIF(gender, '') ORDER BY gender SEPARATOR '/') AS gender,
    GROUP_CONCAT(DISTINCT NULLIF(birth_date, '') ORDER BY birth_date SEPARATOR '/') AS birth_date,
    GROUP_CONCAT(DISTINCT NULLIF(relation_cert_type, '') ORDER BY relation_cert_type SEPARATOR '/') AS relation_cert_type,
    GROUP_CONCAT(DISTINCT NULLIF(mobile_phone1, '') ORDER BY mobile_phone1 SEPARATOR '/') AS mobile_phone1,
    GROUP_CONCAT(DISTINCT NULLIF(mobile_phone2, '') ORDER BY mobile_phone2 SEPARATOR '/') AS mobile_phone2,
    GROUP_CONCAT(DISTINCT NULLIF(wechat_no1, '') ORDER BY wechat_no1 SEPARATOR '/') AS wechat_no1,
    GROUP_CONCAT(DISTINCT NULLIF(wechat_no2, '') ORDER BY wechat_no2 SEPARATOR '/') AS wechat_no2,
    GROUP_CONCAT(DISTINCT NULLIF(wechat_no3, '') ORDER BY wechat_no3 SEPARATOR '/') AS wechat_no3,
    GROUP_CONCAT(DISTINCT NULLIF(contact_address, '') ORDER BY contact_address SEPARATOR '/') AS contact_address,
    MAX(annual_income) AS annual_income,
    GROUP_CONCAT(DISTINCT NULLIF(relation_desc, '') ORDER BY relation_desc SEPARATOR '/') AS relation_desc,
    GROUP_CONCAT(DISTINCT CAST(status AS CHAR) ORDER BY status SEPARATOR '/') AS status,
    GROUP_CONCAT(DISTINCT NULLIF(effective_date, '') ORDER BY effective_date SEPARATOR '/') AS effective_date,
    GROUP_CONCAT(DISTINCT NULLIF(invalid_date, '') ORDER BY invalid_date SEPARATOR '/') AS invalid_date,
    GROUP_CONCAT(DISTINCT NULLIF(remark, '') ORDER BY remark SEPARATOR '/') AS remark,
    GROUP_CONCAT(DISTINCT NULLIF(data_source, '') ORDER BY data_source SEPARATOR '/') AS data_source
FROM tmp_rel_family_edge_rows
GROUP BY from_object_key, to_object_key
ON DUPLICATE KEY UPDATE
    from_key = VALUES(from_key),
    to_key = VALUES(to_key),
    person_id = VALUES(person_id),
    relation_name = VALUES(relation_name),
    relation_type = VALUES(relation_type),
    relation_cert_no = VALUES(relation_cert_no),
    gender = VALUES(gender),
    birth_date = VALUES(birth_date),
    relation_cert_type = VALUES(relation_cert_type),
    mobile_phone1 = VALUES(mobile_phone1),
    mobile_phone2 = VALUES(mobile_phone2),
    wechat_no1 = VALUES(wechat_no1),
    wechat_no2 = VALUES(wechat_no2),
    wechat_no3 = VALUES(wechat_no3),
    contact_address = VALUES(contact_address),
    annual_income = VALUES(annual_income),
    relation_desc = VALUES(relation_desc),
    status = VALUES(status),
    effective_date = VALUES(effective_date),
    invalid_date = VALUES(invalid_date),
    remark = VALUES(remark),
    data_source = VALUES(data_source),
    updated_time = CURRENT_TIMESTAMP;

-- ============================================================
-- Step 5. 工商公司最新快照
-- 如果生产 MySQL 未同步 sjfx_pro.t_eci_company_orc / t_eci_partner_orc，可只执行 Step 1-4。
-- ============================================================
DROP TEMPORARY TABLE IF EXISTS tmp_rel_company_latest;
CREATE TEMPORARY TABLE tmp_rel_company_latest AS
SELECT
    TRIM(key_no) AS key_no,
    TRIM(company_id) AS company_id,
    TRIM(company_name) AS company_name,
    TRIM(credit_code) AS credit_code,
    TRIM(oper_key_no) AS oper_key_no,
    TRIM(oper_name) AS oper_name,
    check_date
FROM (
    SELECT
        c.*,
        ROW_NUMBER() OVER (
            PARTITION BY TRIM(c.credit_code)
            ORDER BY SUBSTR(c.check_date, 1, 10) DESC, c.updated_date DESC
        ) AS rn
    FROM sjfx_pro.t_eci_company_orc c
    WHERE LENGTH(TRIM(c.credit_code)) = 18
      AND c.isadd <> '-1'
      AND c.company_id IS NOT NULL
      AND TRIM(c.company_id) <> ''
      AND c.key_no IS NOT NULL
      AND TRIM(c.key_no) <> ''
      AND c.company_name IS NOT NULL
      AND TRIM(c.company_name) <> ''
) x
WHERE x.rn = 1;

DROP TEMPORARY TABLE IF EXISTS tmp_rel_partner_dedup;
CREATE TEMPORARY TABLE tmp_rel_partner_dedup AS
SELECT
    TRIM(key_no) AS key_no,
    TRIM(company_id) AS company_id,
    TRIM(company_name) AS company_name,
    TRIM(stock_name) AS stock_name,
    TRIM(stock_type) AS stock_type,
    TRIM(stock_percent) AS stock_percent,
    TRIM(should_capi) AS should_capi,
    TRIM(should_capi_value) AS should_capi_value,
    TRIM(should_capi_unit) AS should_capi_unit,
    TRIM(shoud_date) AS shoud_date,
    TRIM(p_key_no) AS p_key_no,
    dates
FROM (
    SELECT
        p.*,
        ROW_NUMBER() OVER (
            PARTITION BY TRIM(p.company_id), TRIM(p.p_key_no), TRIM(p.stock_type)
            ORDER BY p.dates DESC, p.capi_date DESC, p.shoud_date DESC
        ) AS rn
    FROM sjfx_pro.t_eci_partner_orc p
    WHERE p.isadd <> '-1'
      AND p.company_id IS NOT NULL
      AND TRIM(p.company_id) <> ''
      AND p.key_no IS NOT NULL
      AND TRIM(p.key_no) <> ''
      AND p.p_key_no IS NOT NULL
      AND TRIM(p.p_key_no) <> ''
      AND p.stock_name IS NOT NULL
      AND TRIM(p.stock_name) <> ''
      AND p.stock_type IN ('企业股东', '自然人股东')
) x
WHERE x.rn = 1;

-- ============================================================
-- Step 6. 工商点入 lx_rel_node
-- ============================================================
INSERT INTO lx_rel_node (
    object_key,
    node_name,
    id_number,
    subject_type,
    source_type,
    detail_ref_type,
    detail_ref_key
)
SELECT
    node_key AS object_key,
    MAX(node_name) AS node_name,
    MAX(id_number) AS id_number,
    MAX(subject_type) AS subject_type,
    GROUP_CONCAT(DISTINCT source_type ORDER BY source_type SEPARATOR ',') AS source_type,
    MAX(detail_ref_type) AS detail_ref_type,
    MAX(detail_ref_key) AS detail_ref_key
FROM (
    SELECT
        c.company_id AS node_key,
        c.company_name AS node_name,
        c.credit_code AS id_number,
        '企业' AS subject_type,
        '工商企业' AS source_type,
        'ECI_COMPANY' AS detail_ref_type,
        c.company_id AS detail_ref_key
    FROM tmp_rel_company_latest c

    UNION ALL

    SELECT
        p.p_key_no AS node_key,
        p.stock_name AS node_name,
        NULL AS id_number,
        '企业' AS subject_type,
        '企业股东' AS source_type,
        'ECI_PARTNER' AS detail_ref_type,
        p.p_key_no AS detail_ref_key
    FROM tmp_rel_partner_dedup p
    WHERE p.stock_type = '企业股东'

    UNION ALL

    SELECT
        p.p_key_no AS node_key,
        p.stock_name AS node_name,
        NULL AS id_number,
        '个人' AS subject_type,
        '自然人股东' AS source_type,
        'ECI_PARTNER' AS detail_ref_type,
        p.p_key_no AS detail_ref_key
    FROM tmp_rel_partner_dedup p
    WHERE p.stock_type = '自然人股东'

    UNION ALL

    SELECT
        c.oper_key_no AS node_key,
        c.oper_name AS node_name,
        NULL AS id_number,
        '个人' AS subject_type,
        '法定代表人' AS source_type,
        'ECI_COMPANY_OPERATOR' AS detail_ref_type,
        c.oper_key_no AS detail_ref_key
    FROM tmp_rel_company_latest c
    WHERE c.oper_key_no IS NOT NULL
      AND c.oper_key_no <> ''
      AND c.oper_name IS NOT NULL
      AND c.oper_name <> ''
) n
WHERE node_key IS NOT NULL
  AND node_key <> ''
GROUP BY node_key
ON DUPLICATE KEY UPDATE
    node_name = COALESCE(NULLIF(VALUES(node_name), ''), lx_rel_node.node_name),
    id_number = COALESCE(NULLIF(VALUES(id_number), ''), lx_rel_node.id_number),
    subject_type = COALESCE(NULLIF(VALUES(subject_type), ''), lx_rel_node.subject_type),
    source_type = CASE
        WHEN lx_rel_node.source_type IS NULL OR lx_rel_node.source_type = '' THEN VALUES(source_type)
        WHEN VALUES(source_type) IS NULL OR VALUES(source_type) = '' THEN lx_rel_node.source_type
        WHEN LOCATE(VALUES(source_type), lx_rel_node.source_type) > 0 THEN lx_rel_node.source_type
        ELSE CONCAT_WS(',', lx_rel_node.source_type, VALUES(source_type))
    END,
    detail_ref_type = COALESCE(NULLIF(lx_rel_node.detail_ref_type, ''), VALUES(detail_ref_type)),
    detail_ref_key = COALESCE(NULLIF(lx_rel_node.detail_ref_key, ''), VALUES(detail_ref_key)),
    updated_time = CURRENT_TIMESTAMP;

-- ============================================================
-- Step 7. 工商股东边入 lx_rel_stock_edge
-- ============================================================
INSERT INTO lx_rel_stock_edge (
    object_key,
    from_key,
    to_key,
    company_name,
    stock_name,
    stock_type,
    stock_percent,
    should_capi,
    should_capi_value,
    should_capi_unit,
    shoud_date,
    p_key_no
)
SELECT
    CONCAT(c.company_id, p.p_key_no, p.stock_type) AS object_key,
    CONCAT('rel_node/', p.p_key_no) AS from_key,
    CONCAT('rel_node/', c.company_id) AS to_key,
    p.company_name,
    p.stock_name,
    p.stock_type,
    p.stock_percent,
    p.should_capi,
    p.should_capi_value,
    p.should_capi_unit,
    p.shoud_date,
    p.p_key_no
FROM tmp_rel_partner_dedup p
INNER JOIN tmp_rel_company_latest c
    ON c.company_id = p.company_id
ON DUPLICATE KEY UPDATE
    from_key = VALUES(from_key),
    to_key = VALUES(to_key),
    company_name = VALUES(company_name),
    stock_name = VALUES(stock_name),
    stock_type = VALUES(stock_type),
    stock_percent = VALUES(stock_percent),
    should_capi = VALUES(should_capi),
    should_capi_value = VALUES(should_capi_value),
    should_capi_unit = VALUES(should_capi_unit),
    shoud_date = VALUES(shoud_date),
    p_key_no = VALUES(p_key_no),
    updated_time = CURRENT_TIMESTAMP;

-- ============================================================
-- Step 8. 工商法人边入 lx_rel_represent_edge
-- ============================================================
INSERT INTO lx_rel_represent_edge (
    object_key,
    from_key,
    to_key,
    oper_name,
    oper_key_no
)
SELECT
    CONCAT(c.company_id, c.oper_key_no) AS object_key,
    CONCAT('rel_node/', c.oper_key_no) AS from_key,
    CONCAT('rel_node/', c.company_id) AS to_key,
    c.oper_name,
    c.oper_key_no
FROM tmp_rel_company_latest c
WHERE c.oper_key_no IS NOT NULL
  AND c.oper_key_no <> ''
  AND c.oper_name IS NOT NULL
  AND c.oper_name <> ''
ON DUPLICATE KEY UPDATE
    from_key = VALUES(from_key),
    to_key = VALUES(to_key),
    oper_name = VALUES(oper_name),
    oper_key_no = VALUES(oper_key_no),
    updated_time = CURRENT_TIMESTAMP;

-- ============================================================
-- Step 9. 结果检查
-- ============================================================
SELECT 'lx_rel_node' AS table_name, COUNT(1) AS row_cnt FROM lx_rel_node
UNION ALL
SELECT 'lx_rel_family_edge' AS table_name, COUNT(1) AS row_cnt FROM lx_rel_family_edge
UNION ALL
SELECT 'lx_rel_stock_edge' AS table_name, COUNT(1) AS row_cnt FROM lx_rel_stock_edge
UNION ALL
SELECT 'lx_rel_represent_edge' AS table_name, COUNT(1) AS row_cnt FROM lx_rel_represent_edge;
