最近在做项目中,遇到一个SQL优化,去除distinct关键字。
distinct关键字作为去重,会将结果集全部查出,然后对其排序,最后去除重复的数据。一般多出现于left join之后的表对于索引条件(on后的条件)是一对多的情况。
现在要去除distinct关键字,首先需要做的就是找到对于索引列,哪些表是一对多的情况。此篇就是关于如何在数据库中找到对于索引列是一对多的表,然后做后续的删除关键字操作。
1. 首先我们要查找到所有包含索引列的表
--查询所有含有JOB_ID 字段的表
--JOB_ID为索引列
select t.table_name
from DBA_TAB_COLUMNS t
where COLUMN_NAME = 'JOB_ID'
2. 查找到以后,就应该为其分类判断,首先如果job_id 作为主键,是不可能存在重复的,所以要剔除为主键的情况,其中ORACLE数据库的系统表,字段信息多为大写,要注意。这里我们查找到了表名和主键名
--查询所有含有JOB_ID 字段 且JOB_ID 字段不是主键的表 的 表名及其主键
select a.TABLE_NAME,
c.column_name
-- DBA_TAB_COLUMNS数据库中所有字段记录表
from DBA_TAB_COLUMNS a
--user_constraints 数据库中主键信息表
left join user_constraints b
on a.TABLE_NAME = b.table_name
--user_cons_columns 字段约束信息表
left join user_cons_columns c
on c.constraint_name = b.constraint_name
where a.COLUMN_NAME = 'JOB_ID'
--constraint_type = 'P'为主键约束
and b.constraint_type = 'P'
--主键不能为JOB_ID
and c.column_name <> 'JOB_ID'
3.查询到的结果集,要对其进行循环判断。其中用到了数据库循环的方法,execute immediate的用法。
--对上面的结果集进行循环
--查找所有对于字段JOB_ID 包含多个的情况,即一个主键对应多个JOB_ID
declare
tab_name varchar2(100);
col_name varchar2(100);
v_sql varchar2(500);
conNum number;
begin
for item in (select a.TABLE_NAME,
c.column_name
from DBA_TAB_COLUMNS a -- DBA_TAB_COLUMNS数据库中所有字段记录表
left join user_constraints b --user_constraints 数据库中主键信息表
on a.TABLE_NAME = b.table_name
left join user_cons_columns c --字段约束表
on c.constraint_name = b.constraint_name
where a.COLUMN_NAME = 'JOB_ID'
and b.constraint_type = 'P' --constraint_type = 'P'为主键约束
and c.column_name <> 'JOB_ID') loop
tab_name := item.table_name; --结果集的表名
col_name := item.column_name; --结果集的主键名
--表名不能为变量,但可以将SQL语句定义成字符串,通过execute immediate来执行
--两个count分别计数主键字段个数,和去重后的外键个数,差不为0则表示对于外键,该表不是一对多的情况
execute immediate 'select count('||col_name||') - count(distinct job_id) from ' ||tab_name into conNum;
if conNum > 0 then
dbms_output.put_line(tab_name);
end if;
end loop;
end;
4.最后的执行结果是:
此方法只是将一对多的表查到,并不能直接解决去除distinct问题(除非不包含这些表,但是用了distinct),找到表之后,还应对SQL继续分析,找到最适合的方法。
——————————————————————————————————
重复数据
SELECT *
FROM JOB_AE_BL_PO PO
WHERE (PO.PO_NO, PO.ARTICLE_NO, PO.REF_NO1, PO.REF_NO5, PO.REF_NO8) IN
(SELECT PO_NO, ARTICLE_NO, REF_NO1, REF_NO5, REF_NO8
FROM JOB_AE_BL_PO
GROUP BY PO_NO, ARTICLE_NO, REF_NO1, REF_NO5, REF_NO8
HAVING COUNT(*) > 1)
上述代码查出的是PO_NO, ARTICLE_NO, REF_NO1, REF_NO5, REF_NO8这些字段的重复(全部相同才算一条重复数据)