【SQL练习题】根据表a表b写一句sql语句表c

题目如下:根据表a表b写一句sql语句表c

在这里插入图片描述

—1.建yinhang表

create table yinhang(
khyw varchar2(50)
);

—2.yinhang表中插入数据

insert into yinhang values('银行'||','||'证券'||','||'基金'||','||'信托');
insert into yinhang values('证券'||','||'信托'||','||'基金');
insert into yinhang values('基金'||','||'银行');
commit;

—3.建yewu表

create table yewu(
yw varchar2(20),
yid number
);

—4.yewu表中插入数据

insert into yewu values('银行','1');
insert into yewu values('证券','2');
insert into yewu values('基金','3');
insert into yewu values('信托','4');
commit;

思路如下:

–第一步:

select yinhang.*,yewu.* from yinhang join yewu on regexp_like(khyw, yw);

在这里插入图片描述

—5.查询语句

select khyw,
       listagg(yid, ',') within group(order by instr(khyw, yw)) as 结果
  from yinhang
  join yewu
    on regexp_like(khyw, yw)
 group by khyw
 order by length(结果) desc;

在这里插入图片描述

 listagg(yid, ',') within group(order by instr(khyw, yw)) as 结果

这个里面的order by 是对listagg括号里面值的排序,要注意这个

<think>我们正在分析一个SQL查询语句,该语句使用了正则达式匹配和字符串聚合功能。我们需要检查该查询的语法、逻辑以及可能的优化点。 查询语句如下: with t as ( select * from T_BANK_a a inner join t_bank b on regexp_like(a.khyw, b.yw) ) select t.khyw, listagg(t.yid, ',') within group (order by instr(t.khyw, t.yw)) res from t group by t.khyw order by length(t.khyw) desc; 步骤分析: 1. 首先,使用CTE(公共达式)定义了一个临时t,它是两个T_BANK_a(别名a)和t_bank(别名b)的内连接,连接条件为:a的khyw字段通过正则达式匹配b的yw字段(regexp_like(a.khyw, b.yw))。 2. 然后,从临时t中查询,按照khyw分组,对每个khyw,将其对应的多个yid用逗号连接起来(listagg),并且连接时按照yw在khyw中出现的位置(instr(t.khyw, t.yw))进行排序。 3. 最后,按照khyw的长度降序排列。 可能的问题点: 1. 正则达式匹配可能导致性能问题,尤其是当数据量大时。 2. 在连接条件中,如果b的yw字段包含正则达式特殊字符,可能会导致匹配不符合预期。 3. 在分组时,如果同一个khyw对应多个不同的yw,那么在listagg中排序时,instr(t.khyw, t.yw)可能会得到不同的位置,但注意在同一个khyw分组内,会有多个不同的t.yw吗? 实际上,由于我们按照khyw分组,而每个khyw在原始a中可能有多行(因为与b连接后,同一个khyw可能匹配了多个b.yw),所以每个khyw会对应多个yid(这些yid来自b,因为每个匹配的b.yw对应一个yid)。 但是,在同一个分组内,对于同一个khyw和同一个b.yw,可能会有多个匹配行吗?不会,因为不同的b.yw是不同的行。所以,每个匹配的b.yw在同一个khyw分组内只出现一次?不一定,因为同一个b.yw可能在a.khyw中出现多次?但是我们的连接条件只要匹配一次。实际上,只要a.khyw中包含b.yw,就会连接一次,所以同一个a.khyw和同一个b.yw只会连接一次(因为是一对一连接)?但是同一个a.khyw可能匹配多个b.yw,所以每个khyw分组内会有多个不同的b.yw。 注意:在同一个分组(同一个khyw)内,可能会有多个不同的b.yw,每个b.yw在khyw中出现的位置不同。因此,listagg中排序时,使用instr(t.khyw, t.yw)是合理的,它示按照匹配的字符串在khyw中首次出现的位置进行排序。 然而,这里有一个潜在问题:同一个khyw可能匹配了多个b.yw,而不同的b.yw在khyw中出现的位置可能相同(重叠)?那么排序的依据就会相同,此时排序不稳定,但listagg会按照连接条件给出的顺序(这里我们指定了顺序)进行拼接。 其他问题: 1. 在CTE中,使用了select *,这可能会导致列名冲突(特别是两个有同名列时),在后续的listagg中使用了t.yid,这里假设yid来自于b(因为a可能没有yid?)。我们需要确保两个中有一个有yid列,而且最好明确列来自哪个,避免歧义。 2. 在分组时只按照t.khyw分组,那么如果同一个khyw来自多个a中的行(即原始a中有多个相同的khyw)?实际上,在CTE中,由于我们连接了b,同一个a.khyw可能会匹配多个b.yw,从而产生多行。所以分组时,我们按照a.khyw分组,将同一个khyw的所有匹配(来自不同b.yw)的yid聚合起来。 优化建议: 1. 避免在连接条件中使用正则达式函数,因为这样会导致无法使用索引(如果存在索引的话),而且正则达式匹配通常较慢。如果匹配只是简单的字符串包含(即b.yw是a.khyw的子串),那么可以考虑使用instr(a.khyw, b.yw)>0,这样可能更快。但这里使用的是regexp_like,功能更强大(支持正则),但效率更低。 2. 如果业务允许,将正则匹配改为普通字符串包含(如果不需要正则的话),即:on a.khyw like '%' || b.yw || '%' 3. 注意数据量:如果T_BANK_a和t_bank都很大,那么内连接可能会产生非常大的结果集(笛卡尔积再过滤),效率可能很低。可以考虑在b上先过滤,或者使用其他优化手段。 语法检查: 1. 此查询使用了Oracle的listagg函数(因为MySQL没有listagg,而Oracle和PostgreSQL有,但PostgreSQL使用string_agg),所以该语句是针对Oracle的。 2. 在Oracle中,regexp_like函数是存在的,所以语法上应该没问题。 潜在错误: 1. 如果b中有多行匹配同一个a.khyw,那么同一个khyw分组内会有多个yid,用逗号连接起来。但需要注意的是,listagg有长度限制(默认4000字符),如果连接起来的字符串超过4000字符,会报错。可以使用ON OVERFLOW子句处理(Oracle 12c以上)。 修改建议: 1. 明确列出CTE中的列,避免使用*,特别是当两个有同名列时。例如: with t as ( select a.khyw, b.yid, b.yw -- 明确列出需要的列 from T_BANK_a a inner join t_bank b on regexp_like(a.khyw, b.yw) ) 2. 在listagg中,为了避免字符串过长,可以截断处理(如果业务允许)。例如: listagg(t.yid, ',') within group (order by instr(t.khyw, t.yw)) on overflow truncate 总结:该查询在语法上没有明显错误(针对Oracle数据库),但存在性能隐患和潜在的字符串长度问题。根据实际数据量和需,可以考虑优化连接条件以及处理listagg的溢出。 如果用户没有遇到具体错误,我们可以建议进行性能测试和长度检查。 现在,根据生成相关问题: </think>### SQL查询语句分析与优化 #### 查询语句分析 ```sql with t as ( select * from T_BANK_a a inner join t_bank b on regexp_like(a.khyw, b.yw) ) select t.khyw, listagg(t.yid, ',') within group (order by instr(t.khyw, t.yw)) res from t group by t.khyw order by length(t.khyw) desc; ``` #### 主要问题诊断 1. **正则达式性能问题**: - `regexp_like(a.khyw, b.yw)` 会导致全扫描和逐行正则匹配 - 当数据量大时,性能急剧下降(时间复杂度 $O(n^2)$)[^2] - 建议改为基本字符串函数:`instr(a.khyw, b.yw) > 0` 2. **列名歧义风险**: - `select *` 会返回所有列,若两有同名列(如 `id`),会导致 `t.yid` 引用歧义 - 应明确指定所需列名[^1] 3. **LISTAGG长度限制**: - Oracle中LISTAGG默认限制4000字符 - 超长时抛出 `ORA-01489` 错误 - 需添加 `on overflow` 子句处理溢出 4. **分组逻辑缺陷**: - 仅按 `khyw` 分组,当相同 `khyw` 匹配多个 `yw` 时 - `instr(t.khyw, t.yw)` 可能返回相同位置值,导致排序不稳定 #### 优化建议版本 ```sql with t as ( SELECT a.khyw, b.yid, b.yw -- 明确指定列名 FROM T_BANK_a a JOIN t_bank b ON instr(a.khyw, b.yw) > 0 -- 改用高效匹配 ) SELECT t.khyw, LISTAGG(t.yid, ',') WITHIN GROUP ( ORDER BY instr(t.khyw, t.yw), t.yid -- 添加二级排序保证稳定性 ) ON OVERFLOW TRUNCATE '...' -- 处理超长结果 AS res FROM t GROUP BY t.khyw ORDER BY length(t.khyw) DESC; ``` #### 性能优化说明 1. **索引建议**: - 在 `T_BANK_a(khyw)` 和 `t_bank(yw)` 创建函数索引: ```sql CREATE INDEX idx_khyw ON T_BANK_a(SUBSTR(khyw, 1, 50)); CREATE INDEX idx_yw ON t_bank(SUBSTR(yw, 1, 20)); ``` 2. **执行计划优化**: - 原方案扫描行数:$rows(T\_BANK\_a) \times rows(t\_bank)$ - 优化后扫描行数:$rows(T\_BANK\_a) + rows(t\_bank)$ 3. **分区策略**: ```sql ALTER TABLE T_BANK_a PARTITION BY RANGE (length(khyw)) ( PARTITION p_short VALUES LESS THAN (10), PARTITION p_medium VALUES LESS THAN (30), PARTITION p_long VALUES LESS THAN (MAXVALUE) ); ``` #### 适用场景说明 此查询适用于银行交易流水(`T_BANK_a`)与业务代码(`t_bank`)的关联分析,用于: 1. 识别交易描述(`khyw`)中出现的业务类型 2. 聚合关联的业务ID(`yid`) 3. 按交易描述长度降序展示
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值