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

如何在SQL中对相似但非完全一致的group_name执行GROUP BY?

处理SQL中相似分组名称的GROUP BY方案

一、SQL中的实现方案

1. 简单场景:规则匹配(正则/字符串函数)

对于有明显规律的相似名称,直接用SQL内置字符串函数或正则表达式统一分组名。比如案例中的Apple、Microsoft变体,可通过关键词匹配或后缀清理实现统一。

示例查询:

SELECT 
    CASE
        WHEN group_name LIKE '%Apple%' OR group_name = 'AAPL' THEN 'Apple'
        WHEN group_name LIKE '%Microsoft%' OR group_name = 'MSFT' THEN 'Microsoft'
        ELSE group_name  -- 未匹配的名称保留原值
    END AS new_group_name,
    SUM(val) AS total_val
FROM tb1
GROUP BY new_group_name;

如果需要通用后缀清理(如去除Inc.、Corp.),可使用REGEXP_REPLACE:

SELECT 
    LOWER(REGEXP_REPLACE(group_name, '\\s*(Inc\\.|Corp\\.|Ltd\\.)$', '')) AS cleaned_name,
    SUM(val) AS total_val
FROM tb1
GROUP BY cleaned_name;

这种方式仅适用于规则明确的场景,遇到无规律的语义相似会失效。

2. 复杂场景:自定义映射表

若相似性无统一规则,最可靠的方式是维护一个分组映射表,将所有变体映射到标准名称。

先创建映射表:

CREATE TABLE group_mapping (
    variant_name VARCHAR(100),
    standard_name VARCHAR(100)
);

INSERT INTO group_mapping VALUES
('Apple Inc.', 'Apple'),
('AAPL', 'Apple'),
('Apple', 'Apple'),
('Microsoft', 'Microsoft'),
('MSFT', 'Microsoft');

再关联原表查询:

SELECT 
    COALESCE(m.standard_name, t.group_name) AS new_group_name,
    SUM(t.val) AS total_val
FROM tb1 t
LEFT JOIN group_mapping m ON t.group_name = m.variant_name
GROUP BY new_group_name;

这种方式灵活可控,后续新增变体只需更新映射表即可,适合需要精确分组的场景。

3. 高级SQL方案:模糊匹配函数

部分数据库(如PostgreSQL的pg_trgm扩展、MySQL的LEVENSHTEIN函数)支持模糊匹配,可通过计算字符串相似度实现分组。

以PostgreSQL为例,利用pg_trgm的相似度函数分组:

-- 先启用扩展
CREATE EXTENSION IF NOT EXISTS pg_trgm;

WITH standard_groups AS (
    SELECT UNNEST(ARRAY['Apple', 'Microsoft']) AS standard_name
)
SELECT 
    s.standard_name AS new_group_name,
    SUM(t.val) AS total_val
FROM tb1 t
JOIN standard_groups s ON similarity(t.group_name, s.standard_name) > 0.6  -- 自定义相似度阈值
GROUP BY s.standard_name;

该方法适合规则模糊但拼写/语义接近的场景,但需数据库支持对应扩展,且阈值需根据数据调整。

二、Python+Gensim实现语义相似分组

若SQL方法无法处理复杂语义相似(如完全不同的别名指向同一实体),可通过Python结合Gensim的词向量模型做语义聚类,再将结果导回SQL使用。

步骤示例:

import gensim.downloader as api
from gensim.models import Word2Vec
from sklearn.cluster import KMeans
import pandas as pd
import sqlalchemy

# 1. 从数据库读取数据
engine = sqlalchemy.create_engine('your_db_connection_string')
df = pd.read_sql("SELECT group_name, val FROM tb1", engine)

# 2. 预处理名称文本
names = df['group_name'].str.lower().str.split().tolist()

# 3. 训练词向量模型(或使用预训练模型)
model = Word2Vec(sentences=names, vector_size=100, window=2, min_count=1, workers=4)
# 可选预训练模型:model = api.load('glove-wiki-gigaword-100')

# 4. 生成每个名称的向量表示
def get_name_vector(name):
    words = name.lower().split()
    vecs = [model.wv[word] for word in words if word in model.wv]
    return sum(vecs)/len(vecs) if vecs else None

df['vector'] = df['group_name'].apply(get_name_vector)
df = df.dropna(subset=['vector'])

# 5. KMeans聚类(假设分为2组,对应Apple和Microsoft)
kmeans = KMeans(n_clusters=2, random_state=42)
df['cluster_id'] = kmeans.fit_predict(list(df['vector']))

# 6. 为聚类分配标准名称
cluster_mapping = {0: 'Apple', 1: 'Microsoft'}
df['new_group_name'] = df['cluster_id'].map(cluster_mapping)

# 7. 计算总和或导出映射表到数据库
result = df.groupby('new_group_name')['val'].sum().reset_index()
print(result)

# 导出映射表回数据库
mapping_df = df[['group_name', 'new_group_name']].drop_duplicates()
mapping_df.to_sql('group_mapping', engine, if_exists='replace', index=False)

该方法适合语义相似但拼写差异大的场景,但需具备基础NLP知识,且聚类结果需人工校验调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 03:33:17