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

PostgreSQL中zipnames表按优先级聚合同一zipcode单一行的SQL实现

问题

我有一张名为zipnames的表,包含id、zipcode、name_fi和name_sv四个字段,其中name_fi和name_sv均可为空。每个zipcode最多对应四种行:两个名称都存在、仅name_fi存在、仅name_sv存在、两者都为空。

现需编写SELECT语句,使每个zipcode仅返回一行,优先级规则为:优先返回双名称都存在的行,其次是仅单个名称存在的行,仅当无任何名称存在的行时才返回双空行。

使用环境为PostgreSQL v14,可提供纯SQL或Python的SQLAlchemy代码实现。

示例数据

| id | zipcode | name_fi  | name_sv     |
|----|---------|----------|-------------|
|  1 | 00000   |          |             |
|  2 | 00100   | HELSINKI | HELSINGFORS |
|  3 | 00100   | HELSINKI |             |
|  4 | 00100   |          | HELSINGFORS |
|  5 | 00100   |          |             |
|  6 | 50100   | MIKKELI  |             |
|  7 | 50100   |          |             |
|  8 | 64250   |          | PJELAX      |

期望输出

| id | zipcode | name_fi  | name_sv     |
|----|---------|----------|-------------|
|  1 | 00000   |          |             |
|  2 | 00100   | HELSINKI | HELSINGFORS |
|  6 | 50100   | MIKKELI  |             |
|  8 | 64250   |          | PJELAX      |

纯SQL实现

核心逻辑是给每行标记优先级,再按zipcode分组取优先级最高的行:

  • 双名称都存在:优先级1(最高)
  • 仅单个名称存在:优先级2
  • 双空:优先级3(最低)

用ROW_NUMBER()窗口函数实现排序筛选:

SELECT id, zipcode, name_fi, name_sv
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (
            PARTITION BY zipcode 
            ORDER BY 
                CASE 
                    WHEN name_fi IS NOT NULL AND name_sv IS NOT NULL THEN 1
                    WHEN name_fi IS NOT NULL OR name_sv IS NOT NULL THEN 2
                    ELSE 3
                END
        ) AS rn
    FROM zipnames
) t
WHERE rn = 1;

SQLAlchemy实现(Python)

对应SQL逻辑,用case构造优先级排序条件,结合窗口函数筛选:

from sqlalchemy import create_engine, select, case, func
from sqlalchemy.orm import sessionmaker
from your_model_module import Zipnames  # 替换为你的模型类

# 初始化数据库连接
engine = create_engine('postgresql://user:password@host:port/dbname')
Session = sessionmaker(bind=engine)
session = Session()

# 构造子查询,添加优先级排序后的行号
subquery = (
    select(
        Zipnames.id,
        Zipnames.zipcode,
        Zipnames.name_fi,
        Zipnames.name_sv,
        func.row_number().over(
            partition_by=Zipnames.zipcode,
            order_by=case(
                [(Zipnames.name_fi.isnot(None) & Zipnames.name_sv.isnot(None), 1)],
                [(Zipnames.name_fi.isnot(None) | Zipnames.name_sv.isnot(None), 2)],
                else_=3
            )
        ).label('rn')
    )
).subquery()

# 主查询筛选每个zipcode的首行
query = select(subquery).where(subquery.c.rn == 1)

# 执行查询并获取结果
results = session.execute(query).fetchall()

# 输出结果示例
for row in results:
    print(row)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 03:16:08