Files
lingniu-vehicle-ingest/vehicle-data-platform/docs/oneos-readonly-audit.sql

253 lines
10 KiB
SQL

-- OneOS 客户账号与当前车辆范围只读审计
-- 仅允许在只读连接执行;不包含任何 INSERT/UPDATE/DELETE/DDL。
SET SESSION TRANSACTION READ ONLY;
SET SESSION MAX_EXECUTION_TIME = 10000;
-- 0. 核验实际授权。只读账号不应出现 ALL PRIVILEGES、PROCESS、REPLICATION 或 DDL/DML 权限。
SHOW GRANTS FOR CURRENT_USER;
-- 1. 核对关键表字段,识别代码、文档与生产结构漂移。
SELECT table_schema, table_name, column_name, data_type, is_nullable, column_key
FROM information_schema.columns
WHERE table_schema IN ('ln_asset_management', 'ry-cloud')
AND table_name IN (
'vehicle_info', 'vehicle_lease_order_record', 'vehicle_lease_order_record_log',
'vehicle_lease_contract_info', 'vehicle_lease_order_detail', 'delivery_vehicle',
'return_vehicle_task', 'customer_info', 'sys_user', 'sys_user_role'
)
AND column_name IN (
'id', 'user_id', 'vehicle_id', 'plate_number', 'vin', 'customer_id',
'other_customer_id', 'contract_id', 'contract_code', 'last_delivery_time',
'last_return_time', 'delivery_time', 'arrival_time', 'user_type', 'status', 'del_flag'
)
ORDER BY table_schema, table_name, ordinal_position;
-- 2. 车辆基础数据质量。
SELECT
COUNT(*) AS active_vehicles,
SUM(vin IS NULL OR TRIM(vin) = '') AS missing_vin,
COUNT(DISTINCT NULLIF(TRIM(vin), '')) AS distinct_vin,
COUNT(DISTINCT NULLIF(TRIM(plate_number), '')) AS distinct_plate
FROM ln_asset_management.vehicle_info
WHERE del_flag = '0';
-- 3. 客户档案与客户账号覆盖率,不输出手机号、密码等敏感字段。
SELECT
COUNT(*) AS active_customers,
SUM(u.user_id IS NOT NULL) AS customers_with_account,
SUM(u.status = '0' AND u.del_flag = '0') AS customers_with_enabled_account,
SUM(u.user_id IS NULL) AS customers_without_account
FROM ln_asset_management.customer_info c
LEFT JOIN `ry-cloud`.sys_user u
ON u.user_id = c.id
AND u.user_type = 'customer'
WHERE c.del_flag = '0';
-- 4. 客户账号角色覆盖率。
SELECT
COUNT(DISTINCT u.user_id) AS customer_accounts,
COUNT(DISTINCT ur.user_id) AS customer_accounts_with_role
FROM `ry-cloud`.sys_user u
LEFT JOIN `ry-cloud`.sys_user_role ur ON ur.user_id = u.user_id
WHERE u.user_type = 'customer'
AND u.del_flag = '0';
-- 5. 旧聚合时间口径,仅用于与事务事实口径对比,不能作为授权真值。
SELECT
COUNT(*) AS scope_rows,
COUNT(DISTINCT r.vehicle_id) AS scope_vehicles,
COUNT(DISTINCT r.customer_id) AS scope_customers,
SUM(r.customer_id IS NULL) AS missing_customer,
SUM(v.vin IS NULL OR TRIM(v.vin) = '') AS missing_vin,
SUM(c.id IS NULL AND r.customer_id IS NOT NULL) AS missing_customer_profile
FROM ln_asset_management.vehicle_lease_order_record r
LEFT JOIN ln_asset_management.vehicle_info v
ON v.id = r.vehicle_id AND v.del_flag = '0'
LEFT JOIN ln_asset_management.customer_info c
ON c.id = r.customer_id AND c.del_flag = '0'
WHERE r.del_flag = '0'
AND r.last_delivery_time IS NOT NULL
AND (r.last_return_time IS NULL OR r.last_return_time < r.last_delivery_time);
-- 5A. 当前交车/还车事务事实候选及归属质量。
SELECT
COUNT(*) AS candidate_rows,
COUNT(DISTINCT d.vehicle_id) AS candidate_vehicles,
SUM(v.id IS NULL OR v.vin IS NULL OR TRIM(v.vin) = '') AS invalid_vehicle,
SUM(r.id IS NULL OR r.customer_id IS NULL) AS missing_aggregate_customer,
SUM(ci.id IS NULL AND r.customer_id IS NOT NULL) AS invalid_customer_profile,
SUM(co.id IS NULL) AS invalid_contract,
SUM(co.id IS NOT NULL AND COALESCE(co.other_customer_id, co.customer_id) IS NULL) AS missing_contract_customer,
SUM(
r.customer_id IS NOT NULL
AND COALESCE(co.other_customer_id, co.customer_id) IS NOT NULL
AND r.customer_id <> COALESCE(co.other_customer_id, co.customer_id)
) AS customer_mismatch
FROM ln_asset_management.delivery_vehicle d
LEFT JOIN ln_asset_management.vehicle_info v
ON v.id = d.vehicle_id AND v.del_flag = '0'
LEFT JOIN ln_asset_management.vehicle_lease_order_record r
ON r.vehicle_id = d.vehicle_id AND r.del_flag = '0'
LEFT JOIN ln_asset_management.customer_info ci
ON ci.id = r.customer_id AND ci.del_flag = '0'
LEFT JOIN ln_asset_management.vehicle_lease_contract_info co
ON co.id = d.contract_id AND co.del_flag = '0'
WHERE d.del_flag = '0'
AND d.delivery_status IN (2, 3)
AND d.vehicle_id IS NOT NULL
AND d.delivery_time IS NOT NULL
AND NOT EXISTS (
SELECT 1
FROM ln_asset_management.delivery_vehicle newer
WHERE newer.del_flag = '0'
AND newer.vehicle_id = d.vehicle_id
AND (
COALESCE(newer.delivery_time, '1000-01-01') > COALESCE(d.delivery_time, '1000-01-01')
OR (
COALESCE(newer.delivery_time, '1000-01-01') = COALESCE(d.delivery_time, '1000-01-01')
AND newer.id > d.id
)
)
)
AND NOT EXISTS (
SELECT 1
FROM ln_asset_management.return_vehicle_task rt
WHERE rt.delivery_vehicle_id = d.id
AND rt.del_flag = '0'
AND rt.status IN (2, 3, 5)
);
-- 6. 检查同一车辆是否出现多个当前客户范围记录。
SELECT r.vehicle_id, COUNT(*) AS active_scope_rows, COUNT(DISTINCT r.customer_id) AS customer_count
FROM ln_asset_management.vehicle_lease_order_record r
WHERE r.del_flag = '0'
AND r.last_delivery_time IS NOT NULL
AND (r.last_return_time IS NULL OR r.last_return_time < r.last_delivery_time)
GROUP BY r.vehicle_id
HAVING COUNT(*) > 1 OR COUNT(DISTINCT r.customer_id) > 1
ORDER BY active_scope_rows DESC
LIMIT 100;
-- 7. 检查客户 ID 与客户档案不一致的记录。
SELECT COUNT(*) AS unmatched_customer_records
FROM ln_asset_management.vehicle_lease_order_record r
LEFT JOIN ln_asset_management.customer_info c
ON c.id = r.customer_id AND c.del_flag = '0'
WHERE r.del_flag = '0'
AND r.customer_id IS NOT NULL
AND c.id IS NULL;
-- 8. 聚合表客户与合同有效客户是否一致。
SELECT
COUNT(*) AS records_with_contract,
SUM(c.id IS NULL) AS missing_contract,
SUM(c.id IS NOT NULL AND r.customer_id IS NULL) AS missing_record_customer,
SUM(
c.id IS NOT NULL
AND r.customer_id IS NOT NULL
AND r.customer_id <> COALESCE(c.other_customer_id, c.customer_id)
) AS effective_customer_mismatch
FROM ln_asset_management.vehicle_lease_order_record r
LEFT JOIN ln_asset_management.vehicle_lease_contract_info c
ON c.id = r.contract_id AND c.del_flag = '0'
WHERE r.del_flag = '0'
AND r.contract_id IS NOT NULL;
-- 9. 已交车但聚合表被清空或缺少客户/合同的可疑记录。
-- delivery_vehicle 的正式完成状态字段需先通过第 1 项结构核对,再按生产枚举追加状态条件。
SELECT
COUNT(*) AS delivered_rows,
SUM(r.id IS NULL) AS missing_aggregate_record,
SUM(r.id IS NOT NULL AND r.customer_id IS NULL) AS aggregate_missing_customer,
SUM(r.id IS NOT NULL AND r.contract_id IS NULL) AS aggregate_missing_contract,
SUM(r.id IS NOT NULL AND r.last_delivery_time IS NULL) AS aggregate_missing_delivery_time
FROM ln_asset_management.delivery_vehicle d
LEFT JOIN ln_asset_management.vehicle_lease_order_record r
ON r.vehicle_id = d.vehicle_id AND r.del_flag = '0'
WHERE d.del_flag = '0'
AND d.delivery_time IS NOT NULL;
-- 10. 当前聚合表与最新历史记录的关键字段差异。
SELECT COUNT(*) AS aggregate_log_mismatch
FROM ln_asset_management.vehicle_lease_order_record r
JOIN ln_asset_management.vehicle_lease_order_record_log l
ON l.vehicle_id = r.vehicle_id
AND l.del_flag = '0'
AND l.id = (
SELECT MAX(l2.id)
FROM ln_asset_management.vehicle_lease_order_record_log l2
WHERE l2.vehicle_id = r.vehicle_id AND l2.del_flag = '0'
)
WHERE r.del_flag = '0'
AND NOT (
r.customer_id <=> l.customer_id
AND r.contract_id <=> l.contract_id
AND r.last_delivery_time <=> l.last_delivery_time
AND r.last_return_time <=> l.last_return_time
);
-- 11. 检查支撑客户车辆范围查询的索引。这里只读索引元数据,不执行 DDL。
SELECT table_name, index_name, non_unique,
GROUP_CONCAT(column_name ORDER BY seq_in_index) AS indexed_columns
FROM information_schema.statistics
WHERE table_schema = 'ln_asset_management'
AND table_name IN (
'vehicle_info', 'vehicle_lease_order_record', 'vehicle_lease_order_record_log',
'vehicle_lease_contract_info', 'delivery_vehicle', 'return_vehicle_task'
)
GROUP BY table_name, index_name, non_unique
ORDER BY table_name, index_name;
-- 12. 客户编码与系统用户名的冲突、错类型和错租户情况。
-- tenant_id 的目标值应由生产配置确认,这里先按客户 ID 关联并报告实际分布。
SELECT
COUNT(*) AS customer_profiles,
SUM(u.user_id IS NULL) AS no_same_id_account,
SUM(u.user_id IS NOT NULL AND u.user_type <> 'customer') AS same_id_wrong_type,
SUM(
u.user_id IS NOT NULL
AND (CONVERT(u.user_name USING utf8mb4) COLLATE utf8mb4_unicode_ci)
<> (CONVERT(c.customer_code USING utf8mb4) COLLATE utf8mb4_unicode_ci)
) AS username_code_mismatch,
COUNT(DISTINCT CASE WHEN u.user_id IS NOT NULL THEN u.tenant_id END) AS account_tenant_count
FROM ln_asset_management.customer_info c
LEFT JOIN `ry-cloud`.sys_user u ON u.user_id = c.id AND u.del_flag = '0'
WHERE c.del_flag = '0';
-- 13. 同一租户、用户名是否存在多账号或跨 user_type 冲突。
SELECT tenant_id, user_name,
COUNT(*) AS account_count,
COUNT(DISTINCT user_type) AS user_type_count
FROM `ry-cloud`.sys_user
WHERE del_flag = '0'
AND user_name IS NOT NULL
AND TRIM(user_name) <> ''
GROUP BY tenant_id, user_name
HAVING COUNT(*) > 1 OR COUNT(DISTINCT user_type) > 1
ORDER BY account_count DESC
LIMIT 100;
-- 14. 业务库整体体积与最大表。table_rows 为 InnoDB 估算值,不用于财务或业务计数。
SELECT
COUNT(*) AS base_tables,
SUM(data_length) AS data_bytes,
SUM(index_length) AS index_bytes
FROM information_schema.tables
WHERE table_schema = 'ln_asset_management'
AND table_type = 'BASE TABLE';
SELECT table_name, table_rows, data_length, index_length
FROM information_schema.tables
WHERE table_schema = 'ln_asset_management'
AND table_type = 'BASE TABLE'
ORDER BY data_length + index_length DESC
LIMIT 20;
-- 15. API 月日志体积,用于核对保留策略;不读取任何日志内容。
SELECT table_name, table_rows, data_length, index_length
FROM information_schema.tables
WHERE table_schema = 'ln_asset_management'
AND table_name LIKE 'api_request_log\\_%'
ORDER BY table_name;