You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效统计数据表各列的唯一值及其出现行数?

高效统计数据表各列唯一值及对应行数的SQL方案

需求说明

需要对customer表进行数据探索,统计每一列的每个唯一字符串对应的行数,期望输出格式如下:

+------------+-------------+------------+----------+
| table_name | column_name | distinct   | count(*) |
|            |             | row_string |          |
+------------+-------------+------------+----------+
| customer   | state       | WA         | 15       |
+------------+-------------+------------+----------+
| customer   | state       | NSW        | 786      |
+------------+-------------+------------+----------+
| ...        | ...         | ...        | ...      |
+------------+-------------+------------+----------+
| customer   | zip_code    | 3563       | 33       |
+------------+-------------+------------+----------+
| ...        | ...         | ...        | ...      |
+------------+-------------+------------+----------+

原实现方式为对每个列单独分组统计后用UNION拼接:

select state, count(*)
from customer
group by state
union
select zip_code, count(*)
from customer
group by zip_code
union
...

但列数较多时,该方法会多次全表扫描,效率极低。

高效实现方案

核心思路是先将表的列转置为行(Unpivot),再一次性分组统计,全程仅需扫描表一次,大幅降低IO开销。以下是不同数据库的具体实现:

1. 支持UNPIVOT语法的数据库(SQL Server、Oracle等)

直接使用原生UNPIVOT语法转置列:

SELECT 
    'customer' AS table_name,
    column_name,
    row_string AS distinct_row_string,
    COUNT(*) AS count
FROM customer
UNPIVOT (
    row_string FOR column_name IN (state, zip_code, col1, col2) -- 列出所有需要统计的列
) AS unpivoted
GROUP BY column_name, row_string
ORDER BY column_name, count DESC;

2. PostgreSQL

方法一:LATERAL 拼接行(适合列数较少时)

SELECT 
    'customer' AS table_name,
    column_name,
    row_string AS distinct_row_string,
    COUNT(*) AS count
FROM customer,
LATERAL (
    VALUES 
        ('state', state::text),
        ('zip_code', zip_code::text),
        ('col1', col1::text)
) AS unpivoted(column_name, row_string)
WHERE row_string IS NOT NULL -- 可选:过滤空值
GROUP BY column_name, row_string
ORDER BY column_name, count DESC;

方法二:JSONB 自动转置(适合列数较多时,无需手动列所有列)

SELECT 
    'customer' AS table_name,
    key AS column_name,
    value AS distinct_row_string,
    COUNT(*) AS count
FROM customer,
jsonb_each_text(to_jsonb(customer))
WHERE value IS NOT NULL -- 可选:过滤空值
GROUP BY key, value
ORDER BY key, count DESC;

3. MySQL(8.0+)

方法一:WITH 子句转置后分组

WITH unpivoted AS (
    SELECT 'state' AS column_name, state AS row_string FROM customer
    UNION ALL
    SELECT 'zip_code' AS column_name, zip_code AS row_string FROM customer
    UNION ALL
    SELECT 'col1' AS column_name, col1 AS row_string FROM customer
    -- 继续添加其他需要统计的列
)
SELECT 
    'customer' AS table_name,
    column_name,
    row_string AS distinct_row_string,
    COUNT(*) AS count
FROM unpivoted
WHERE row_string IS NOT NULL
GROUP BY column_name, row_string
ORDER BY column_name, count DESC;

方法二:JSON_TABLE 自动转置

SELECT 
    'customer' AS table_name,
    j.column_name,
    j.row_string AS distinct_row_string,
    COUNT(*) AS count
FROM customer,
JSON_TABLE(
    JSON_OBJECT('state', state, 'zip_code', zip_code, 'col1', col1),
    '$.*' COLUMNS (
        column_name VARCHAR(255) PATH '$[key]',
        row_string VARCHAR(255) PATH '$[value]'
    )
) AS j
WHERE j.row_string IS NOT NULL
GROUP BY j.column_name, j.row_string
ORDER BY j.column_name, count DESC;

效率优势

原方法每个列的GROUP BY都会触发一次全表扫描,列数越多扫描次数越多;转置后仅需扫描表一次,后续分组统计仅基于转置后的数据集,IO开销大幅减少,大表场景下性能提升尤为明显。

内容的提问来源于stack exchange,提问作者user17107276

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:40:14