group by 多行变成一行-- (sum (case end case 也可以完成同样功能))

本文介绍了一个复杂的SQL查询案例,通过对特定数据库表的连接操作和条件筛选,获取关于成本服务触发器类型、工作项名称等信息。重点展示了如何通过SQL语句处理大量数据并返回指定格式的结果集。
select *
from (select mtab.*, rownum row_no
from (select distinct decode(mss.equip_id,
null,
cosmos_config_pkg.GET_SiteName(mss.site_id),
cosmos_config_pkg.GET_Equip_SerialName(mss.mdl_ver_id,
mss.equip_id)) name,
null servPkgID,
null srevPkgName,
wi.work_item_id itemId,
wi.work_item_name itemName,
csp.serv_provider_name servProv,
decode(mss.trigger_typ_id,
5,
to_char(mss.start_dt, 'mm/dd/yyyy'),
6,
to_char(mss.start_dt, 'mm/dd/yyyy'),
to_char(mss.start_value)) stDt,
decode(mss.trigger_typ_id,
5,
nvl(to_char(mss.end_dt, 'mm/dd/yyyy'),
'EOT'),
6,
nvl(to_char(mss.end_dt, 'mm/dd/yyyy'),
'EOT'),
nvl(to_char(mss.end_value), 'EOT')) edDt,
decode(mss.trigger_typ_id,
5,
(select ef.freq_desc
from cost_event_frequency ef
where ef.freq_id = mss.freq_id),
6,
(select et.event_typ_name
from cost_event_typ et
where et.event_typ_id =
mss.event_typ_id),
1,
'FFS',
2,
'AH',
3,
'AS',
4,
'FFH',
'') periodicity,
decode(mss.trigger_typ_id,
5,
'NA',
6,
nvl(to_char(mss.event_occurence), 'ALL'),
1,
to_char(mss.freq_value),
2,
to_char(mss.freq_value),
3,
to_char(mss.freq_value),
4,
to_char(mss.freq_value),
'') sequence,
nvl(cosmos_config_pkg.GET_Equip_SerialName(mss.mdl_ver_id,
mss.ref_equip_id),
'NA') refESN,
(select stt.trigger_typ_name
from COST_SERV_TRIGGER_TYP stt
where stt.trigger_typ_id =
mss.trigger_typ_id) frequency,
null servType,
decode(mv.mdl_ver_typ_id, 1129, 'Y', 'N') crRenegInd,
decode(mv.mdl_ver_typ_id, 1127, 'Y', 'N') crStartInd,
decode(mv.mdl_ver_typ_id, 1130, 'Y', 'N') crModelInd,
decode(mv.mdl_ver_typ_id, 1150, 'Y', 'N') crActualInd,
decode(mv.mdl_ver_typ_id, 1087, 'Y', 'N') crOpDataInd,
decode(mv.mdl_ver_typ_id, 1151, 'Y', 'N') crFutureInd,
decode(mv.mdl_ver_typ_id, 1060, 'Y', 'N') crWorkInd,
decode(mv.mdl_ver_typ_id, 1090, 'Y', 'N') reTain1Ind,
decode(mv.mdl_ver_typ_id, 1091, 'Y', 'N') reTain2Ind,
decode(mv.mdl_ver_typ_id, 1094, 'Y', 'N') reTain3Ind,
decode(mv.mdl_ver_typ_id, 1095, 'Y', 'N') reTain4Ind
from cost_model_ver mv,
cost_event_service es,
cost_mdl_standalone_service mss,
cost_work_item wi,
cost_work_item_ctlg wic,
cost_work_item_category cwic,
cost_service_provider csp
where mv.mdl_id = 12991468
and es.mdl_ver_id = mv.mdl_ver_id
and mss.mdl_ver_id = mv.mdl_ver_id
and mss.mdl_standalone_serv_id = es.mdl_standalone_serv_id
and wi.work_item_id = mss.work_item_id
and wic.work_item_id = wi.work_item_id
and wic.ctlg_ver_id =
cosmos_config_pkg.GET_CATALOG_VERSION(mv.mdl_ver_id)
and cwic.work_item_category_id = wi.work_item_category_id
and csp.serv_provider_id = mss.serv_provider_id
and es.actualize_ind = 'P'
and mv.mdl_ver_typ_id in
(1060, 1087, 1127, 1129, 1130, 1150, 1151)
and mss.equip_id is null) mtab)
where row_no < = 100and row_no > 0


select distinct decode(mss.equip_id,
null,
cosmos_config_pkg.GET_SiteName(mss.site_id),
cosmos_config_pkg.GET_Equip_SerialName(mss.mdl_ver_id,
mss.equip_id)) name,
null servPkgID,
null srevPkgName,
wi.work_item_id itemId,
wi.work_item_name itemName,
csp.serv_provider_name servProv,
decode(mss.trigger_typ_id,
5,
to_char(mss.start_dt, 'mm/dd/yyyy'),
6,
to_char(mss.start_dt, 'mm/dd/yyyy'),
to_char(mss.start_value)) stDt,
decode(mss.trigger_typ_id,
5,
nvl(to_char(mss.end_dt, 'mm/dd/yyyy'), 'EOT'),
6,
nvl(to_char(mss.end_dt, 'mm/dd/yyyy'), 'EOT'),
nvl(to_char(mss.end_value), 'EOT')) edDt,
decode(mss.trigger_typ_id,
5,
(select ef.freq_desc
from cost_event_frequency ef
where ef.freq_id = mss.freq_id),
6,
(select et.event_typ_name
from cost_event_typ et
where et.event_typ_id = mss.event_typ_id),
1,
'FFS',
2,
'AH',
3,
'AS',
4,
'FFH',
'') periodicity,
decode(mss.trigger_typ_id,
5,
'NA',
6,
nvl(to_char(mss.event_occurence), 'ALL'),
1,
to_char(mss.freq_value),
2,
to_char(mss.freq_value),
3,
to_char(mss.freq_value),
4,
to_char(mss.freq_value),
'') sequence,
nvl(cosmos_config_pkg.GET_Equip_SerialName(mss.mdl_ver_id,
mss.ref_equip_id),
'NA') refESN,
(select stt.trigger_typ_name
from COST_SERV_TRIGGER_TYP stt
where stt.trigger_typ_id = mss.trigger_typ_id) frequency,
null servType,
max(decode(mv.mdl_ver_typ_id, 1129, 'Y', 'N')) crRenegInd,
max(decode(mv.mdl_ver_typ_id, 1127, 'Y', 'N')) crStartInd,
max(decode(mv.mdl_ver_typ_id, 1130, 'Y', 'N')) crModelInd,
max(decode(mv.mdl_ver_typ_id, 1150, 'Y', 'N')) crActualInd,
max(decode(mv.mdl_ver_typ_id, 1087, 'Y', 'N')) crOpDataInd,
max(decode(mv.mdl_ver_typ_id, 1151, 'Y', 'N')) crFutureInd,
max(decode(mv.mdl_ver_typ_id, 1060, 'Y', 'N')) crWorkInd,
max(decode(mv.mdl_ver_typ_id, 1090, 'Y', 'N')) reTain1Ind,
max(decode(mv.mdl_ver_typ_id, 1091, 'Y', 'N')) reTain2Ind,
max(decode(mv.mdl_ver_typ_id, 1094, 'Y', 'N')) reTain3Ind,
max(decode(mv.mdl_ver_typ_id, 1095, 'Y', 'N')) reTain4Ind

--,mdl_ver_typ_id
from cost_model_ver mv,
cost_event_service es,
cost_mdl_standalone_service mss,
cost_work_item wi,
cost_work_item_ctlg wic,
cost_work_item_category cwic,
cost_service_provider csp
where mv.mdl_id = 12991468
and es.mdl_ver_id = mv.mdl_ver_id
and mss.mdl_ver_id = mv.mdl_ver_id
and mss.mdl_standalone_serv_id = es.mdl_standalone_serv_id
and wi.work_item_id = mss.work_item_id
and wic.work_item_id = wi.work_item_id
and wic.ctlg_ver_id =
cosmos_config_pkg.GET_CATALOG_VERSION(mv.mdl_ver_id)
and cwic.work_item_category_id = wi.work_item_category_id
and csp.serv_provider_id = mss.serv_provider_id
and es.actualize_ind = 'P'
and mv.mdl_ver_typ_id in (1060, 1087, 1127, 1129, 1130, 1150, 1151)
and mss.equip_id is null
group by decode(mss.equip_id,
null,
cosmos_config_pkg.GET_SiteName(mss.site_id),
cosmos_config_pkg.GET_Equip_SerialName(mss.mdl_ver_id,
mss.equip_id)),
null,
null,
wi.work_item_id,
wi.work_item_name,
csp.serv_provider_name,
decode(mss.trigger_typ_id,
5,
to_char(mss.start_dt, 'mm/dd/yyyy'),
6,
to_char(mss.start_dt, 'mm/dd/yyyy'),
to_char(mss.start_value)),
decode(mss.trigger_typ_id,
5,
nvl(to_char(mss.end_dt, 'mm/dd/yyyy'), 'EOT'),
6,
nvl(to_char(mss.end_dt, 'mm/dd/yyyy'), 'EOT'),
nvl(to_char(mss.end_value), 'EOT')),
mss.trigger_typ_id,

decode(mss.trigger_typ_id,
5,
'NA',
6,
nvl(to_char(mss.event_occurence), 'ALL'),
1,
to_char(mss.freq_value),
2,
to_char(mss.freq_value),
3,
to_char(mss.freq_value),
4,
to_char(mss.freq_value),
''),
nvl(cosmos_config_pkg.GET_Equip_SerialName(mss.mdl_ver_id,
mss.ref_equip_id),
'NA'),

mss.trigger_typ_id,
null,
mss.freq_id,
mss.event_typ_id
<think>我们有一个需求:在SQL中使用GROUP BYSUM结合CASE WHEN进行条件去重统计。 目标:对数据进行分组(GROUP BY),然后在每个分组内,根据条件进行去重统计,并求和(SUM)某些条件下的值。 注意:去重统计通常是指对某个字段进行去重计数(COUNT(DISTINCT ...)),但这里结合了SUMCASE WHEN,我们可以实现更复杂的条件去重统计。 常见场景: 例如,我们有一个销售订单表,每个订单有订单号(唯一)、客户ID、销售金额、订单日期等。我们想要统计每个客户的总订单金额(不去重)以及不同产品类别的订单数(去重计数)?或者更复杂的:统计每个客户在满足某些条件下的去重订单数,同时还要对另一个字段进行条件求和。 但是,去重统计通常使用COUNT(DISTINCT ...)来完成,而SUM(CASE WHEN ...)则常用于条件聚合(如行转列)。那么如何将两者结合呢? 实际上,我们可以利用子查询先对需要去重的字段进行预处理(比如先按分组和需要去重的字段进行分组,然后标记去重),然后再进行聚合。或者,我们可以直接在SUM中使用DISTINCT,但要注意SUM里面使用DISTINCT是去重字段的值再求和,而不是计数。 然而,根据引用[2]中的例子,他们使用了SUM(CASE WHEN ... THEN 1 ELSE 0 END)来实现条件计数,这并没有去重。所以,如果我们想要在条件计数中去重,就需要在CASE WHEN之前先对数据进行去重处理,或者使用COUNT(DISTINCT CASE WHEN ... THEN ... END)。 因此,正确的做法是使用: COUNT(DISTINCT (CASE WHEN condition THEN column_to_count END)) 或者 COUNT(DISTINCT CASE WHEN condition THEN column_to_count ELSE NULL END) 注意:COUNT函数会忽略NULL值,所以当条件不满足时,我们返回NULL,这样就不会被计数。 但是,如果需求是:在满足某个条件的情况下,对某个字段进行去重计数,同时还要对另一个字段进行条件求和(使用SUM),那么我们可以在一个SELECT语句中同时使用多个聚合函数。 例如,假设我们有一个表`sales`,字段如下: order_id (订单ID,唯一) customer_id (客户ID) product_id (产品ID) amount (订单金额) order_date (订单日期) 需求:按客户分组,统计每个客户: 1. 总订单金额(所有订单的金额求和) 2. 去重统计该客户购买的不同产品数量(即同一个客户购买的同一种产品只计一次) 3. 统计该客户在2023年的订单金额总和 4. 统计该客户在2023年购买的不同产品数量(去重) 我们可以这样写: ```sql SELECT customer_id, SUM(amount) AS total_amount, -- 所有订单金额求和 COUNT(DISTINCT product_id) AS distinct_products, -- 去重统计产品数量(所有订单) SUM(CASE WHEN YEAR(order_date) = 2023 THEN amount ELSE 0 END) AS amount_2023, -- 2023年的订单金额求和 COUNT(DISTINCT CASE WHEN YEAR(order_date) = 2023 THEN product_id ELSE NULL END) AS distinct_products_2023 -- 2023年购买的不同产品数量 FROM sales GROUP BY customer_id; ``` 解释: - 第一个聚合:SUM(amount) 直接对金额求和。 - 第二个聚合:COUNT(DISTINCT product_id) 对每个客户的所有订单中的产品ID进行去重计数。 - 第三个聚合:使用条件聚合,只对2023年的订单金额求和(非2023年的金额加0)。 - 第四个聚合:在2023年的条件下,对产品ID进行去重计数。注意:这里CASE WHEN返回的是产品ID(满足条件时)或NULL(不满足条件),然后COUNT(DISTINCT ...)会忽略NULL,所以只计算2023年的不同产品数量。 因此,我们可以将COUNT(DISTINCT ...)与CASE WHEN结合使用,实现条件去重计数。 但是,如果需求是:在同一个聚合中既要根据条件去重,又要对另一个字段进行求和(比如,对满足条件的订单金额进行求和,同时还要对满足条件的订单中的产品去重计数),那么就需要分开两个聚合函数。 注意:不能在一个聚合函数中同时做两件事(比如既求和又去重计数),需要分别写。 另外,引用[3]中展示了使用MAX(CASE WHEN ...)来实现行转列,但这里不涉及去重计数,而是将多行数据转换为一行中的多列。 总结:去重统计通常使用COUNT(DISTINCT ...),而条件去重统计则使用COUNT(DISTINCT CASE WHEN ... THEN ... END)。同时,条件求和使用SUM(CASE WHEN ... THEN ... ELSE ... END)。 因此,针对用户的问题:SQL GROUP BY SUM CASE WHEN 去重统计用法,我们可以理解为在分组后,使用条件聚合(CASE WHEN)配合SUM或COUNT(DISTINCT)来实现不同的统计需求。 下面给出一个通用的模板: ```sql SELECT group_column1, group_column2, ..., -- 条件求和 SUM(CASE WHEN condition1 THEN value_column ELSE 0 END) AS sum_value_condition1, -- 条件去重计数 COUNT(DISTINCT CASE WHEN condition2 THEN distinct_column ELSE NULL END) AS distinct_count_condition2 FROM table_name GROUP BY group_column1, group_column2, ...; ``` 注意:在COUNT(DISTINCT ...)中,如果条件不满足,我们返回NULL,这样就不会被计数。在SUM中,我们通常返回0,这样不会影响求和(因为NULL在SUM中会被忽略,所以如果希望不满足条件的记为0,则用0,否则可以用NULL,但注意SUM会忽略NULL,相当于加0)。 另外,如果要去重的字段在条件满足时可能有多个值,我们需要确保在分组后,对每个组内的该字段进行去重。 如果用户的需求是“条件去重求和”,即先对某个字段去重,然后再对去重后的值求和?这通常不太常见,因为去重后的值求和可能没有实际意义(除非去重后每个值只出现一次,然后求和)。如果是这样,我们可以先对需要去重的字段进行子查询去重,然后再进行条件求和。但这种情况需要具体分析。 因此,根据用户的问题,我们主要介绍条件去重计数(COUNT(DISTINCT CASE WHEN))和条件求和(SUM(CASE WHEN))的用法。 如果用户有具体的表结构和需求,我们可以给出更具体的SQL示例。</think>在 SQL 中使用 `GROUP BY` 结合 `SUM(CASE WHEN)` 实现条件去重统计,核心是通过嵌套子查询或 `COUNT(DISTINCT)` 实现去重逻辑。以下是具体用法和示例: --- ### **方法 1:子查询内去重 + 外层条件聚合** **适用场景**:需对分组后的数据按条件去重统计 **示例**:统计每个部门(`dept`)的 **去重后的技术岗员工薪资总和**(`job = '技术'`) ```sql SELECT dept, SUM(CASE WHEN job = '技术' THEN salary ELSE 0 END) AS tech_total_salary FROM ( SELECT dept, job, salary FROM employees GROUP BY dept, job, salary -- 先按部门、岗位、薪资去重 ) AS distinct_data GROUP BY dept; ``` **说明**: 1. 内层子查询通过 `GROUP BY dept, job, salary` 实现去重 2. 外层用 `SUM(CASE WHEN)` 按条件聚合 --- ### **方法 2:COUNT(DISTINCT CASE WHEN) 去重计数** **适用场景**:按条件统计去重后的数量(如满足条件的用户数) **示例**:统计每个班级(`class_id`)中 **绩及格(≥60)的不同学生数量** ```sql SELECT class_id, COUNT(DISTINCT CASE WHEN score >= 60 THEN student_id END) AS pass_students FROM exam_scores GROUP BY class_id; ``` **说明**: - `COUNT(DISTINCT CASE WHEN ...)` 直接实现条件去重计数 - 不满足条件时返回 `NULL`,自动被 `COUNT` 忽略 --- ### **方法 3:SUM(CASE WHEN) + DISTINCT 联合使用** **适用场景**:对去重后的值进行条件求和(如统计不同产品的总销售额) **示例**:统计每个地区(`region`)的 **不同产品(去重)的销售额总和** ```sql SELECT region, SUM(DISTINCT CASE WHEN product_id IS NOT NULL THEN sales ELSE 0 END) AS unique_product_sales FROM orders GROUP BY region; ``` **注意**:`SUM(DISTINCT ...)` 需确保计算字段的唯一性,否则结果可能非预期。 --- ### **关键点总结** 1. **去重位置**: - 子查询内去重 → 适用于复杂条件 - `COUNT(DISTINCT CASE WHEN)` → 简洁高效的条件去重计数 2. **条件逻辑**: - `CASE WHEN` 中定义统计条件(如 `score >= 60`) - 用 `NULL` 排除无效数据(`COUNT` 自动忽略) 3. **分组依据**: - `GROUP BY` 后的字段决定分组维度(如 `dept`, `class_id`) > 引用示例:类似 `COUNT(DISTINCT CASE WHEN score >=60 THEN student_id END)` 的用法常见于绩分析场景[^2]。 --- ### **相关问题** 1. 如何对多个条件同时进行去重统计? **示例**:同时统计及格和不及格的学生数 ```sql SELECT class_id, COUNT(DISTINCT CASE WHEN score >= 60 THEN student_id END) AS pass_count, COUNT(DISTINCT CASE WHEN score < 60 THEN student_id END) AS fail_count FROM exam_scores GROUP BY class_id; ``` 2. 行转列场景中如何实现去重? **场景**:将不同产品的销售额转为列显示(每个产品仅统计一次) ```sql SELECT region, MAX(CASE WHEN product_id = 'A' THEN sales END) AS sales_A, MAX(CASE WHEN product_id = 'B' THEN sales END) AS sales_B FROM ( SELECT region, product_id, SUM(sales) AS sales FROM orders GROUP BY region, product_id -- 先按产品和地区去重聚合 ) AS sub GROUP BY region; ``` > 引用示例:类似行转列用法可参考 `MAX(CASE WHEN ...)` 结构[^3]。 3. 如何优化大数据量下的去重统计性能? - 在子查询中尽量缩小数据集(如先过滤再聚合) - 对 `GROUP BY` 字段建立索引
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值