DB2 SQL 在对行进行分组时获取不同的值

Posted

技术标签:

【中文标题】DB2 SQL 在对行进行分组时获取不同的值【英文标题】:DB2 SQL Getting distinct value when grouping rows 【发布时间】:2017-05-31 18:58:24 【问题描述】:

BUSINESSTABLE 如下所示:

HOTEL_CHAIN    HOTEL_LOCATION   HOTEL_OWNER
_____________________________________________________
Marriott       Las Vegas        Nelson
Best Western   New York         Richards
Best Western   San Francisco    Smith
Marriott       New York         Nelson
Hilton         Boston           James

我正在尝试在 DB2 数据库中执行一条 SQL 语句,该语句按 HOTEL_CHAIN 对这些条目进行分组。如果组合在一起的行包含相同的 HOTEL_LOCATION 或 HOTEL_OWNER,则应保留该信息。否则,应显示“NULL”值。例如,两家万豪酒店都有相同的所有者 Nelson,因此我想在新表中显示该信息。但是,每家万豪酒店位于不同的位置,所以我想在该列中显示“NULL”。

结果表 (HOTELTABLE) 应如下所示:

HOTEL_CHAIN    HOTEL_LOCATION   HOTEL_OWNER
_____________________________________________________
Marriott       NULL             Nelson
Best Western   NULL             NULL
Hilton         Boston           James

我正在尝试使用以下 SQL 语句来完成此操作:

INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER) 
SELECT
HOTEL_CHAIN,
CASE COUNT(DISTINCT(HOTEL_LOCATION)) WHEN 1 THEN HOTEL_LOCATION ELSE 'NULL' END,
CASE COUNT(DISTINCT(HOTEL_OWNER)) WHEN 1 THEN HOTEL_OWNER ELSE 'NULL' END,
FROM BUSINESSTABLE GROUP BY HOTEL_CHAIN

我收到一个 SQL 错误 SQLCODE-119 A COLUMN OR EXPRESSION IN A HAVING CLAUSE IS NOT VALID。在我的案例陈述中,它似乎在抱怨第二个 HOTEL_LOCATION 和第二个 HOTEL_OWNER。我还尝试使用 DISTINCT(HOTEL_LOCATION) 并引发另一个错误。有人可以解释一下编码的正确方法吗?谢谢!

【问题讨论】:

【参考方案1】:

不要使用COUNT(DISTINCT)。使用MIN()MAX()

INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER) 
    SELECT HOTEL_CHAIN,
           (CASE WHEN MIN(HOTEL_LOCATION) = MAX(HOTEL_LOCATION)
                 THEN MIN(HOTEL_LOCATION) ELSE 'NULL'
            END),
           (CASE WHEN MIN(HOTEL_OWNER) = MAX(HOTEL_OWNER)
                 THEN MIN(HOTEL_OWNER) ELSE 'NULL'
            END)
    FROM BUSINESSTABLE
    GROUP BY HOTEL_CHAIN;

注意事项:

为什么不COUNT(DISTINCT)?它通常比MIN()MAX() 贵得多,因为它需要维护所有值的内部列表。 我不赞成使用名为'NULL' 的字符串值。似乎它旨在助长混乱。也许只是 NULL 价值本身?

【讨论】:

【参考方案2】:

我同意 Gordon 的 null (gj Gordon)。

其他方法

INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER)

select distinct f1.HOTEL_CHAIN, 
       case when f2.HasDiffLocation is not null then 'NULL' else f1.HOTEL_LOCATION end as HOTEL_LOCATION,
       case when f3.HasDiffOwner is not null then 'NULL' else f1.HOTEL_OWNER end as HOTEL_OWNER
from BUSINESSTABLE f1
left outer join lateral 
(
    select 1 HasDiffLocation from BUSINESSTABLE f2b
    where f1.HOTEL_CHAIN=f2b.HOTEL_CHAIN and f1.HOTEL_LOCATION<>f2b.HOTEL_LOCATION
    fetch first rows only
) f2 on 1=1

left outer join lateral 
(
    select 1 HasDiffOwner from BUSINESSTABLE f3b
    where f1.HOTEL_CHAIN=f3b.HOTEL_CHAIN and f1.HOTEL_OWNER<>f3b.HOTEL_OWNER
    fetch first rows only
) f3 on 1=1

或者像这样:

INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER)
select distinct f1.HOTEL_CHAIN, 
ifnull(f2.result, f1.HOTEL_LOCATION) as HOTEL_LOCATION,
ifnull(f3.result, f1.HOTEL_OWNER) as HOTEL_LOCATION,
from BUSINESSTABLE f1
left outer join lateral 
(
    select 'NULL' result from BUSINESSTABLE f2b
    where f1.HOTEL_CHAIN=f2b.HOTEL_CHAIN and f1.HOTEL_LOCATION<>f2b.HOTEL_LOCATION
    fetch first rows only
) f2 on 1=1

left outer join lateral 
(
    select 'NULL' result from BUSINESSTABLE f3b
    where f1.HOTEL_CHAIN=f3b.HOTEL_CHAIN and f1.HOTEL_OWNER<>f3b.HOTEL_OWNER
    fetch first rows only
) f3 on 1=1

【讨论】:

以上是关于DB2 SQL 在对行进行分组时获取不同的值的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery:如何在滚动时间戳窗口内对行进行分组和计数?

根据 SQL Server 2008 R2 中特定列中的模式更改对行进行分组

SQL:按日期分组并对列中的值求和

SQL 按 Top 3 和其他对行进行分组。 (按州和其他排名前 3 名的城市的收入)

使用熊猫对行进行分组并找到平均值[重复]

在Microsoft SWS中,如何对行进行分组?