csp模拟2nd_B-HRZ学英语

本文解析了一个简单的模拟题,涉及字符串操作,通过统计字符频率来判断是否满足特定条件,并按字典序替换缺失字符。文章提供了C++代码实现,展示了如何高效地解决此类问题。

B-HRZ学英语


题目描述

在这里插入图片描述

题目思路

这个题目很简单,是一个小模拟题,其中包含对字符串的操作。
我们只需要每次从输入字符串str中截取包含26个字符的子串,然后每次去统计这个字符串中各个字符的数量,如果满足A~Z的所有字符中,每个字符的数量都不超过1,这样就满足要求,然后我们就找到?对应的位置,将A ~Z中字符数量为0的字符按照字典序从小到大替换掉即可。
这里我在模测的时候由于没有看清题目,题意理解错误而导致出错了,有点不应该。

代码实现

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define _for(i,a,b) for(int i = (a); i < (b); i++)
#define _rep(i,a,b) for(int i = (a); i <= (b); i++) 
using namespace std;
const int MAXN = 1e6 + 10;

string str,ans;
int num[30];
bool flag;


int main()
{
	ios::sync_with_stdio(false);
	cin >> str;
	
	_for(i,0,str.size()-25)
	{
		memset(num,0,sizeof(num));
		flag = true;
		ans = str.substr(i,26);
		_for(j,0,26)
		{
			if(ans[j] != '?')
				num[ans[j]-'A']++;
			if(num[ans[j]-'A'] > 1) flag = false;
		}
		
		if(!flag) continue;
		_for(j,0,26)
		{
			if(num[j] == 0)
				ans[ans.find('?')] = 'A' + j;
		}
		
		cout << ans;
		return 0;
	}
	cout << -1;
	return 0;
} 
我这里有一条oracle执行的sql,执行单时间挺长,需要你帮我对它进行优化,提高查询效率,sql语句如下 select LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) as STATDATE, case when b.MANAGER_COM = '869701' then '860097' else b.MANAGER_COM end as COMCODE, null as COMNAME, '3' as COMLEVEL, substr(b.MANAGER_COM,1,4) as PARENT_CODE, 'YX' as CHANNEL_CODE, '营销' as CHANNEL_NAME, sum(case when a.line_name in ('L_200-营销首年佣金','L_215-中心城市首年佣金') then a.actual_used_of else null END) as FIRST_FEE_A, -- 首期佣金 累计达成额 sum(case when a.line_name in ('L_200-营销基本法','L_215-中心城市基本法') then a.actual_used_of else null END) as FIRST_FEE_JBEN_A, -- 首期基本法 累计达成额 sum(case when a.line_name in ('L_215-中心城市业务费用','L_200-营销业务费用小计', 'L_200-营销培训费用小计', 'L_200-营销专项费用小计', 'L_200-营销聘才专项', 'L_200-营销将星/利剑/续航等', 'L_200-营销磐龙专项等') then a.actual_used_of else null END) as FIRST_FEE_YWTDJY_A, -- 首期业务推动经营费用 累计达成额 sum(case when a.line_name in ('L_200-营销业务推动费用','L_215-中心城市业务推动费用','L_215-中心城市协解费用专项','L_215-中心城市人力发展费用','L_200-营销人力发展费用','L_200-营销聘才专项', 'L_200-营销将星/利剑/续航等', 'L_200-营销磐龙专项等') then a.actual_used_of else null END) as FIRST_FEE_JL_A,-- 首期激励方案费用 累计达成额 sum(case when a.line_name in ('L_200-营销培训费用小计','L_215-中心城市培训费用小计') then a.actual_used_of else null END) as FIRST_FEE_YWPX_A, -- 首期业务培训费用 累计达成额 sum(case when a.line_name in ('L_200-营销专项费用小计','L_215-中心城市专项费用小计') then a.actual_used_of else null END) as FIRST_FEE_QT_A, -- 首期其他费用 累计达成额 null as FIRST_FEE_JX_A, -- 首期绩效 累计达成额 null as FIRST_FEE_SXF_A, -- 首期手续费 累计达成额 sum(case when a.line_name in ('L_200-营销首年佣金','L_215-中心城市首年佣金','L_200-营销基本法','L_215-中心城市基本法','L_215-中心城市业务费用','L_200-营销业务费用小计', 'L_200-营销培训费用小计', 'L_200-营销专项费用小计', 'L_200-营销聘才专项', 'L_200-营销将星/利剑/续航等', 'L_200-营销磐龙专项等') then a.actual_used_of else null END) as FIRST_FEE_BDSJ_A from MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a left join MISOPER.T_SLFS_COM_MAP b on a.company_code = b.OF_SEGMENT1_VALUE where (b.MANAGER_COM != '' or b.MANAGER_COM is not null) and length(b.MANAGER_COM) = 6 and b.MANAGER_COM not in ('863499','860000','869701','860606','860004') group by b.MANAGER_COM,a.PERIOD_NAME union select LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) as STATDATE, case when b.MANAGER_COM = '869701' then '860097' else b.MANAGER_COM end as COMCODE, null as COMNAME, '3' as COMLEVEL, substr(b.MANAGER_COM,1,4) as PARENT_CODE, 'KJ' as CHANNEL_CODE, '客经' as CHANNEL_NAME, sum(case when a.line_name = 'L_0-续期首年佣金' then a.actual_used_of else null END) as FIRST_FEE_A, -- 首期佣金 累计达成额 sum(case when a.line_name in ('L_0-续期聘才费用','L_0-续期基本法成本','L_0-续期展业福利费') then a.actual_used_of else null END) as FIRST_FEE_JBEN_A, -- 首期基本法 累计达成额 sum(case when a.line_name = 'L_0-续期业务费用-其中展业' then a.actual_used_of else null END) as FIRST_FEE_YWTDJY_A, -- 首期业务推动经营费用 累计达成额 sum(case when a.line_name in ('L_0-客经业务推动','L_0-客经业推专项','L_0-客经协解专项','L_0-客经人力发展','L_0-客经人发专项') then a.actual_used_of else null END) as FIRST_FEE_JL_A,-- 首期激励方案费用 累计达成额 sum(case when a.line_name = 'L_0-客经培训' then a.actual_used_of else null END) as FIRST_FEE_YWPX_A, -- 首期业务培训费用 累计达成额 sum(case when a.line_name = 'L_0-客经社保' then a.actual_used_of else null END) as FIRST_FEE_QT_A, -- 首期其他费用 累计达成额 null as FIRST_FEE_JX_A, -- 首期绩效 累计达成额 null as FIRST_FEE_SXF_A, -- 首期手续费 累计达成额 sum(case when a.line_name in ('L_0-续期首年佣金','L_0-续期聘才费用','L_0-续期基本法成本','L_0-续期展业福利费','L_0-续期业务费用-其中展业') then a.actual_used_of else null END) as FIRST_FEE_BDSJ_A from MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a left join MISOPER.T_SLFS_COM_MAP b on a.company_code = b.OF_SEGMENT1_VALUE where (b.MANAGER_COM != '' or b.MANAGER_COM is not null) and length(b.MANAGER_COM) = 6 and b.MANAGER_COM not in ('863499','860000','869701','860606','860004') group by b.MANAGER_COM,a.PERIOD_NAME union select LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) as STATDATE, case when b.MANAGER_COM = '869701' then '860097' else b.MANAGER_COM end as COMCODE, null as COMNAME, '3' as COMLEVEL, substr(b.MANAGER_COM,1,4) as PARENT_CODE, 'ZX' as CHANNEL_CODE, '振兴' as CHANNEL_NAME, sum(case when a.line_name = 'L_218-振兴首年佣金' then a.actual_used_of else null END) as FIRST_FEE_A, -- 首期佣金 累计达成额 sum(case when a.line_name = 'L_218-振兴基本法' then a.actual_used_of else null END) as FIRST_FEE_JBEN_A, -- 首期基本法 累计达成额 sum(case when a.line_name = 'L_218-振兴首期业务费用' then a.actual_used_of else null END) as FIRST_FEE_YWTDJY_A, -- 首期业务推动经营费用 累计达成额 sum(case when a.line_name in ('L_218-振兴人力发展费用','L_218-振兴专项费用小计','L_218-振兴业务推动费用') then a.actual_used_of else null END) as FIRST_FEE_JL_A, -- 首期激励方案费用 累计达成额 sum(case when a.line_name = 'L_218-振兴培训费用小计' then a.actual_used_of else null END) as FIRST_FEE_YWPX_A, -- 首期业务培训费用 累计达成额 null as FIRST_FEE_QT_A, -- 首期其他费用 累计达成额 null as FIRST_FEE_JX_A, -- 首期绩效 累计达成额 null as FIRST_FEE_SXF_A, -- 首期手续费 累计达成额 sum(case when a.line_name in ('L_218-振兴首年佣金','L_218-振兴基本法','L_218-振兴首期业务费用') then a.actual_used_of else null END) as FIRST_FEE_BDSJ_A from MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a left join MISOPER.T_SLFS_COM_MAP b on a.company_code = b.OF_SEGMENT1_VALUE where (b.MANAGER_COM != '' or b.MANAGER_COM is not null) and length(b.MANAGER_COM) = 6 and b.MANAGER_COM not in ('863499','860000','869701','860606','860004') group by b.MANAGER_COM,a.PERIOD_NAME union select LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) as STATDATE, case when b.MANAGER_COM = '869701' then '860097' else b.MANAGER_COM end as COMCODE, null as COMNAME, '3' as COMLEVEL, substr(b.MANAGER_COM,1,4) as PARENT_CODE, 'TXCJ' as CHANNEL_CODE, '团险BBC' as CHANNEL_NAME, sum(case when a.line_name = 'L_100-团险BBC首年佣金' then a.actual_used_of else null END) as FIRST_FEE_A, -- 首期佣金 累计达成额 sum(case when a.line_name = 'L_100-团险BBC人力成本' then a.actual_used_of else null END) as FIRST_FEE_JBEN_A, -- 首期基本法 累计达成额 sum(case when a.line_name in ('L_100-团险BBC业务招待费','L_100-团险BBC业务推动费用','L_100-团险BBC协解专项','L_100-团险BBC手续费(含预提)') then a.actual_used_of else null END) as FIRST_FEE_YWTDJY_A, -- 首期业务推动经营费用 累计达成额 null as FIRST_FEE_JL_A,-- 首期激励方案费用 累计达成额 null as FIRST_FEE_YWPX_A, -- 首期业务培训费用 累计达成额 null as FIRST_FEE_QT_A, -- 首期其他费用 累计达成额 null as FIRST_FEE_JX_A, -- 首期绩效 累计达成额 null as FIRST_FEE_SXF_A, -- 首期手续费 累计达成额 sum(case when a.line_name in ('L_100-团险BBC首年佣金','L_100-团险BBC人力成本','L_100-团险BBC业务招待费','L_100-团险BBC业务推动费用','L_100-团险BBC协解专项','L_100-团险BBC手续费(含预提)') then a.actual_used_of else null END) as FIRST_FEE_BDSJ_A from MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a left join MISOPER.T_SLFS_COM_MAP b on a.company_code = b.OF_SEGMENT1_VALUE where (b.MANAGER_COM != '' or b.MANAGER_COM is not null) and length(b.MANAGER_COM) = 6 and b.MANAGER_COM not in ('863499','860000','869701','860606','860004') group by b.MANAGER_COM,a.PERIOD_NAME union select LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) as STATDATE, case when b.MANAGER_COM = '869701' then '860097' else b.MANAGER_COM end as COMCODE, null as COMNAME, '3' as COMLEVEL, substr(b.MANAGER_COM,1,4) as PARENT_CODE, 'CSP' as CHANNEL_CODE, '银保CSP' as CHANNEL_NAME, sum(case when a.line_name in ('L_300-银保CSP首年佣金','L_300-银保CSP产融首年佣金') then a.actual_used_of else null END) as FIRST_FEE_A, -- 首期佣金 累计达成额 sum(case when a.line_name in ('L_300-银保CSP基本法','L_300-银保CSP产融基本法') then a.actual_used_of else null END) as FIRST_FEE_JBEN_A, -- 首期基本法 累计达成额 sum(case when a.line_name in ('L_300-银保CSP业务推动费用','L_300-银保CSP对公产融业务费用','L_300-银保CSP直营产融业务费用','L_300-银保CSP协解专项') then a.actual_used_of else null END) as FIRST_FEE_YWTDJY_A, -- 首期业务推动经营费用 累计达成额 null as FIRST_FEE_JL_A,-- 首期激励方案费用 累计达成额 null as FIRST_FEE_YWPX_A, -- 首期业务培训费用 累计达成额 null as FIRST_FEE_QT_A, -- 首期其他费用 累计达成额 null as FIRST_FEE_JX_A, -- 首期绩效 累计达成额 null as FIRST_FEE_SXF_A, -- 首期手续费 累计达成额 sum(case when a.line_name in ('L_300-银保CSP首年佣金','L_300-银保CSP产融首年佣金','L_300-银保CSP基本法','L_300-银保CSP产融基本法','L_300-银保CSP业务推动费用','L_300-银保CSP对公产融业务费用','L_300-银保CSP直营产融业务费用','L_300-银保CSP协解专项') then a.actual_used_of else null END) as FIRST_FEE_BDSJ_A from MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a left join MISOPER.T_SLFS_COM_MAP b on a.company_code = b.OF_SEGMENT1_VALUE where (b.MANAGER_COM != '' or b.MANAGER_COM is not null) and length(b.MANAGER_COM) = 6 and b.MANAGER_COM not in ('863499','860000','869701','860606','860004') group by b.MANAGER_COM,a.PERIOD_NAME union select LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) as STATDATE, case when b.MANAGER_COM = '869701' then '860097' else b.MANAGER_COM end as COMCODE, null as COMNAME, '3' as COMLEVEL, substr(b.MANAGER_COM,1,4) as PARENT_CODE, 'CT' as CHANNEL_CODE, '银保传统' as CHANNEL_NAME, null as FIRST_FEE_A, -- 首期佣金 累计达成额 sum(case when a.line_name = 'L_300-银保传统人力基本薪资' then a.actual_used_of else null END) as FIRST_FEE_JBEN_A, -- 首期基本法 累计达成额 sum(case when a.line_name in ('L_300-银保传统业务费用小计','L_300-银保专项费用汇总','L_300-银保传统满期协解专项') then a.actual_used_of else null END) as FIRST_FEE_YWTDJY_A, -- 首期业务推动经营费用 累计达成额 null as FIRST_FEE_JL_A,-- 首期激励方案费用-业务推动费用 累计达成额 null as FIRST_FEE_YWPX_A, -- 首期业务培训费用 累计达成额 null as FIRST_FEE_QT_A, -- 首期其他费用 累计达成额 sum(case when a.line_name = 'L_300-银保传统人力成本' then a.actual_used_of else null END) as FIRST_FEE_JX_A, -- 首期绩效 累计达成额 sum(case when a.line_name = 'L_300-银保传统手续费' then a.actual_used_of else null END) as FIRST_FEE_SXF_A, -- 首期手续费 累计达成额 sum(case when a.line_name in ('L_300-银保传统业务费用小计','L_300-银保专项费用汇总','L_300-银保传统满期协解专项','L_300-银保传统人力基本薪资','L_300-银保传统人力成本','L_300-银保传统手续费') then a.actual_used_of else null END) as FIRST_FEE_BDSJ_A --变动实际费用 from MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a left join MISOPER.T_SLFS_COM_MAP b on a.company_code = b.OF_SEGMENT1_VALUE where (b.MANAGER_COM != '' or b.MANAGER_COM is not null) and length(b.MANAGER_COM) = 6 and b.MANAGER_COM not in ('863499','860000','869701','860606','860004') group by b.MANAGER_COM,a.PERIOD_NAME union select LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) as STATDATE, case when b.MANAGER_COM = '869701' then '860097' else b.MANAGER_COM end as COMCODE, null as COMNAME, '3' as COMLEVEL, substr(b.MANAGER_COM,1,4) as PARENT_CODE, 'JD' as CHANNEL_CODE, '经代' as CHANNEL_NAME, null as FIRST_FEE_A, -- 首期佣金 累计达成额 null as FIRST_FEE_JBEN_A, -- 首期基本法 累计达成额 sum(case when a.line_name in ('L_500-经代业务费用','L_500-经代预提') then a.actual_used_of else null END) as FIRST_FEE_YWTDJY_A, -- 首期业务推动经营费用 累计达成额 null as FIRST_FEE_JL_A,-- 首期激励方案费用-业务推动费用 累计达成额 null as FIRST_FEE_YWPX_A, -- 首期业务培训费用 累计达成额 null as FIRST_FEE_QT_A, -- 首期其他费用 累计达成额 null as FIRST_FEE_JX_A, -- 首期绩效 累计达成额 sum(case when a.line_name = 'L_500-经代手续费' then a.actual_used_of else null END) as FIRST_FEE_SXF_A, -- 首期手续费 累计达成额 sum(case when a.line_name in ('L_500-经代业务费用','L_500-经代预提','L_500-经代手续费') then a.actual_used_of else null END) as FIRST_FEE_BDSJ_A --变动实际费用 from MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a left join MISOPER.T_SLFS_COM_MAP b on a.company_code = b.OF_SEGMENT1_VALUE where (b.MANAGER_COM != '' or b.MANAGER_COM is not null) and length(b.MANAGER_COM) = 6 and b.MANAGER_COM not in ('863499','860000','869701','860606','860004') group by b.MANAGER_COM,a.PERIOD_NAME
09-16
<think> 我们面对的是一个复杂的UNION ALL查询,包含多个子查询,每个子查询都针对不同的渠道(营销、客经、振兴等)进行数据汇总。每个子查询的结构相似,都是对同一张表(MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP)进行左连接,然后进行分组聚合。由于数据量可能很大,且多个UNION ALL会导致多次扫描同一张大表,因此优化思路主要是减少表扫描次数,并且优化连接和聚合操作。 ### 优化思路 1. **减少表扫描次数**:目前查询中每个UNION分支都独立扫描了一次表`MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP`和连接表`MISOPER.T_SLFS_COM_MAP`。我们可以考虑将多个分支合并为一次扫描,然后通过条件聚合(即在一个SELECT语句中使用多个条件聚合)来避免多次扫描同一张表。 2. **使用条件聚合代替多个分支**:我们可以将多个UNION分支合并为一个SELECT语句,然后使用`CASE WHEN`针对不同的渠道计算不同的聚合值。这样只需要扫描一次表,然后通过分组和条件聚合得到所有渠道的数据。 3. **优化连接操作**:原查询使用了左连接,但是WHERE条件中对右表字段进行了过滤(非空、长度、排除特定值),这实际上将左连接变成了内连接。我们可以显式地写成内连接(INNER JOIN),这样优化器可以更好地选择执行计划。 4. **避免重复计算**:在同一个分支内,多个聚合列有重复的条件判断,可以考虑使用更高效的写法,例如将共同的判断条件提取出来,避免重复扫描。 5. **预过滤数据**:在连接之前先对两个表进行过滤,减少连接的数据量。 ### 具体优化步骤 #### 步骤1:将UNION ALL分支合并为一个查询,使用条件聚合 我们可以将多个渠道的聚合计算放在一个SELECT语句中,通过增加一个渠道标识字段来区分不同的渠道,然后按照渠道标识进行分组,同时进行条件聚合。 但是注意,原查询中每个分支的聚合条件不同,且渠道标识在SELECT子句中是固定的(比如第一个分支是'YX',第二个是'KJ'等)。因此,我们可以将每个渠道的条件聚合分别计算。 #### 步骤2:重写为条件聚合的单一查询 由于每个渠道的聚合条件不同,我们可以这样设计: - 在SELECT子句中,为每个渠道分别计算各个聚合列,并且使用条件判断(CASE WHEN)来区分渠道以及该渠道对应的行条件。 但是,由于每个渠道的聚合条件独立,我们需要对每个渠道分别进行条件判断。这样,每个聚合列都会包含一个渠道条件和一个行条件(即原CASE WHEN中的条件)。 #### 步骤3:调整连接和过滤条件 将左连接改为内连接,因为WHERE条件中已经要求`b.MANAGER_COM`必须满足非空、长度为6且不在排除列表中。同时,将过滤条件提前到连接条件中(或者使用子查询先过滤)以减少连接的数据量。 ### 优化后的SQL结构 ```sql SELECT LAST_DAY(TO_DATE(a.PERIOD_NAME,'YYYY-MM')) AS STATDATE, CASE WHEN b.MANAGER_COM = '869701' THEN '860097' ELSE b.MANAGER_COM END AS COMCODE, NULL AS COMNAME, '3' AS COMLEVEL, SUBSTR(b.MANAGER_COM,1,4) AS PARENT_CODE, channel.CHANNEL_CODE, channel.CHANNEL_NAME, -- 针对每个渠道的聚合列计算 SUM(CASE WHEN channel.CHANNEL_CODE = 'YX' AND a.line_name IN ('L_200-营销首年佣金','L_215-中心城市首年佣金') THEN a.actual_used_of WHEN channel.CHANNEL_CODE = 'KJ' AND a.line_name = 'L_0-续期首年佣金' THEN a.actual_used_of -- ... 其他渠道条件 ELSE NULL END) AS FIRST_FEE_A, -- 类似地,为每个渠道计算其他聚合列... FROM MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a INNER JOIN MISOPER.T_SLFS_COM_MAP b ON a.company_code = b.OF_SEGMENT1_VALUE -- 使用一个渠道维度的辅助表(可以是内联的)来生成渠道标识 CROSS JOIN ( SELECT 'YX' AS CHANNEL_CODE, '营销' AS CHANNEL_NAME FROM DUAL UNION ALL SELECT 'KJ', '客经' FROM DUAL UNION ALL SELECT 'ZX', '振兴' FROM DUAL UNION ALL SELECT 'TXCJ', '团险BBC' FROM DUAL UNION ALL SELECT 'CSP', '银保CSP' FROM DUAL UNION ALL SELECT 'CT', '银保传统' FROM DUAL UNION ALL SELECT 'JD', '经代' FROM DUAL ) channel WHERE (b.MANAGER_COM != '' OR b.MANAGER_COM IS NOT NULL) AND LENGTH(b.MANAGER_COM) = 6 AND b.MANAGER_COM NOT IN ('863499','860000','869701','860606','860004') -- 同时,根据不同的渠道,我们还需要确保该行数据属于该渠道的过滤条件(如果有的话,但原查询没有额外的渠道过滤,所以主要靠聚合时的条件) GROUP BY b.MANAGER_COM, a.PERIOD_NAME, channel.CHANNEL_CODE, channel.CHANNEL_NAME -- 注意:这里增加了渠道分组 ``` 但是,这样写有一个问题:原本每个分支只扫描一次表,但这个查询由于CROSS JOIN了渠道维度表,会导致数据膨胀(即每行原始数据乘以7(渠道数)),然后再进行聚合。这样虽然只扫描了一次表,但数据量可能会暂时变大,而且聚合时也会增加负担。 ### 替代方案:使用UNION ALL但共享表扫描 另一种思路是使用WITH子句先获取基础数据,然后在每个分支中从这个公共结果集中过滤出各自渠道的数据并聚合。这样基础数据只扫描一次,然后各自分支进行聚合。 ```sql WITH base_data AS ( SELECT a.PERIOD_NAME, a.line_name, a.actual_used_of, -- 对b表的转换和过滤 CASE WHEN b.MANAGER_COM = '869701' THEN '860097' ELSE b.MANAGER_COM END AS MANAGER_COM, SUBSTR(b.MANAGER_COM,1,4) AS PARENT_CODE FROM MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a INNER JOIN MISOPER.T_SLFS_COM_MAP b ON a.company_code = b.OF_SEGMENT1_VALUE WHERE (b.MANAGER_COM != '' OR b.MANAGER_COM IS NOT NULL) AND LENGTH(b.MANAGER_COM) = 6 AND b.MANAGER_COM NOT IN ('863499','860000','869701','860606','860004') ) -- 然后为每个渠道写一个分支,从base_data中选取 SELECT LAST_DAY(TO_DATE(PERIOD_NAME,'YYYY-MM')) AS STATDATE, MANAGER_COM AS COMCODE, NULL AS COMNAME, '3' AS COMLEVEL, PARENT_CODE, 'YX' AS CHANNEL_CODE, '营销' AS CHANNEL_NAME, SUM(CASE WHEN line_name IN ('L_200-营销首年佣金','L_215-中心城市首年佣金') THEN actual_used_of END) AS FIRST_FEE_A, SUM(CASE WHEN line_name IN ('L_200-营销基本法','L_215-中心城市基本法') THEN actual_used_of END) AS FIRST_FEE_JBEN_A, ... -- 其他聚合列 FROM base_data GROUP BY MANAGER_COM, PERIOD_NAME, PARENT_CODE -- 注意:这里不需要分组CHANNEL_CODE因为它固定 UNION ALL SELECT LAST_DAY(TO_DATE(PERIOD_NAME,'YYYY-MM')) AS STATDATE, MANAGER_COM AS COMCODE, NULL AS COMNAME, '3' AS COMLEVEL, PARENT_CODE, 'KJ' AS CHANNEL_CODE, '客经' AS CHANNEL_NAME, SUM(CASE WHEN line_name = 'L_0-续期首年佣金' THEN actual_used_of END) AS FIRST_FEE_A, SUM(CASE WHEN line_name IN ('L_0-续期聘才费用','L_0-续期基本法成本','L_0-续期展业福利费') THEN actual_used_of END) AS FIRST_FEE_JBEN_A, ... -- 其他聚合列 FROM base_data GROUP BY MANAGER_COM, PERIOD_NAME, PARENT_CODE -- ... 其他渠道类似 ``` 这种方法的优点: - 基础数据只扫描一次,避免了多次扫描大表。 - 每个分支独立聚合,逻辑清晰,易于维护。 缺点: - 虽然基础表只扫描一次,但每个分支都要对base_data进行全量扫描(或者物化),如果base_data很大,那么可能会占用较多临时表空间。 ### 进一步的优化:使用GROUPING SETS 如果我们能够将所有的聚合条件都统一到一个SELECT中,并且使用GROUP BY GROUPING SETS来同时得到多个渠道的数据,那么就可以避免多次扫描base_data。但是,由于每个渠道的聚合条件不同(即不同的CASE WHEN表达式),我们无法直接在一个SELECT中完成所有聚合。 ### 结论 权衡之后,我们选择使用WITH子句的方案,因为它减少了原始表的扫描次数(只需一次),尽管需要多次扫描临时结果集(base_data),但临时结果集已经经过过滤,数据量可能会减少。另外,我们还可以考虑在base_data中只选择必要的列,尽量减少临时结果集的大小。 ### 优化后的完整SQL(示例部分分支,其他分支类似) ```sql WITH base_data AS ( SELECT a.PERIOD_NAME, a.line_name, a.actual_used_of, -- 对b表的转换和过滤 CASE WHEN b.MANAGER_COM = '869701' THEN '860097' ELSE b.MANAGER_COM END AS MANAGER_COM, SUBSTR(b.MANAGER_COM,1,4) AS PARENT_CODE FROM MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP a INNER JOIN MISOPER.T_SLFS_COM_MAP b ON a.company_code = b.OF_SEGMENT1_VALUE WHERE (b.MANAGER_COM != '' OR b.MANAGER_COM IS NOT NULL) AND LENGTH(b.MANAGER_COM) = 6 AND b.MANAGER_COM NOT IN ('863499','860000','869701','860606','860004') ) -- 营销渠道 SELECT LAST_DAY(TO_DATE(PERIOD_NAME,'YYYY-MM')) AS STATDATE, MANAGER_COM AS COMCODE, NULL AS COMNAME, '3' AS COMLEVEL, PARENT_CODE, 'YX' AS CHANNEL_CODE, '营销' AS CHANNEL_NAME, SUM(CASE WHEN line_name IN ('L_200-营销首年佣金','L_215-中心城市首年佣金') THEN actual_used_of END) AS FIRST_FEE_A, SUM(CASE WHEN line_name IN ('L_200-营销基本法','L_215-中心城市基本法') THEN actual_used_of END) AS FIRST_FEE_JBEN_A, SUM(CASE WHEN line_name IN ('L_215-中心城市业务费用','L_200-营销业务费用小计', 'L_200-营销培训费用小计', 'L_200-营销专项费用小计', 'L_200-营销聘才专项', 'L_200-营销将星/利剑/续航等', 'L_200-营销磐龙专项等') THEN actual_used_of END) AS FIRST_FEE_YWTDJY_A, SUM(CASE WHEN line_name IN ('L_200-营销业务推动费用','L_215-中心城市业务推动费用','L_215-中心城市协解费用专项','L_215-中心城市人力发展费用','L_200-营销人力发展费用','L_200-营销聘才专项', 'L_200-营销将星/利剑/续航等', 'L_200-营销磐龙专项等') THEN actual_used_of END) AS FIRST_FEE_JL_A, SUM(CASE WHEN line_name IN ('L_200-营销培训费用小计','L_215-中心城市培训费用小计') THEN actual_used_of END) AS FIRST_FEE_YWPX_A, SUM(CASE WHEN line_name IN ('L_200-营销专项费用小计','L_215-中心城市专项费用小计') THEN actual_used_of END) AS FIRST_FEE_QT_A, NULL AS FIRST_FEE_JX_A, NULL AS FIRST_FEE_SXF_A, SUM(CASE WHEN line_name IN ('L_200-营销首年佣金','L_215-中心城市首年佣金','L_200-营销基本法','L_215-中心城市基本法','L_215-中心城市业务费用','L_200-营销业务费用小计', 'L_200-营销培训费用小计', 'L_200-营销专项费用小计', 'L_200-营销聘才专项', 'L_200-营销将星/利剑/续航等', 'L_200-营销磐龙专项等') THEN actual_used_of END) AS FIRST_FEE_BDSJ_A FROM base_data GROUP BY MANAGER_COM, PERIOD_NAME, PARENT_CODE UNION ALL -- 客经渠道 SELECT LAST_DAY(TO_DATE(PERIOD_NAME,'YYYY-MM')) AS STATDATE, MANAGER_COM AS COMCODE, NULL AS COMNAME, '3' AS COMLEVEL, PARENT_CODE, 'KJ' AS CHANNEL_CODE, '客经' AS CHANNEL_NAME, SUM(CASE WHEN line_name = 'L_0-续期首年佣金' THEN actual_used_of END) AS FIRST_FEE_A, SUM(CASE WHEN line_name IN ('L_0-续期聘才费用','L_0-续期基本法成本','L_0-续期展业福利费') THEN actual_used_of END) AS FIRST_FEE_JBEN_A, SUM(CASE WHEN line_name = 'L_0-续期业务费用-其中展业' THEN actual_used_of END) AS FIRST_FEE_YWTDJY_A, SUM(CASE WHEN line_name IN ('L_0-客经业务推动','L_0-客经业推专项','L_0-客经协解专项','L_0-客经人力发展','L_0-客经人发专项') THEN actual_used_of END) AS FIRST_FEE_JL_A, SUM(CASE WHEN line_name = 'L_0-客经培训' THEN actual_used_of END) AS FIRST_FEE_YWPX_A, SUM(CASE WHEN line_name = 'L_0-客经社保' THEN actual_used_of END) AS FIRST_FEE_QT_A, NULL AS FIRST_FEE_JX_A, NULL AS FIRST_FEE_SXF_A, SUM(CASE WHEN line_name IN ('L_0-续期首年佣金','L_0-续期聘才费用','L_0-续期基本法成本','L_0-续期展业福利费','L_0-续期业务费用-其中展业') THEN actual_used_of END) AS FIRST_FEE_BDSJ_A FROM base_data GROUP BY MANAGER_COM, PERIOD_NAME, PARENT_CODE -- ... 其他渠道类似,按照原查询的分支逐个写出 ``` ### 其他优化点 1. **索引优化**:确保连接字段和过滤字段有索引。 - 在`MISOPER.T_SLFS_COM_MAP`表上,为连接字段`OF_SEGMENT1_VALUE`和过滤字段`MANAGER_COM`创建索引。 - 在`MISOPER.YGBX_REPORT_DETAILS_INTERFACE_TMP`表上,为连接字段`company_code`以及分组字段`PERIOD_NAME`创建索引。另外,根据每个分支中聚合条件中使用的`line_name`值,如果这些值是固定的,可以考虑创建一个函数索引或者位图索引(如果该列重复值多)来加速条件聚合。 2. **避免在WHERE子句中对列进行函数操作**:原查询中没有直接对表`a`的列使用函数,但在分组时使用了`TO_DATE`转换。注意,如果`PERIOD_NAME
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值