一些写ETL脚本常用的sql语句(一)

以下代码pk字段均为表的主键字段

1、在查询表的时候,往往需要left join另一张表,而有时候在left join之前又需要对该表先进行一层查询,再left join其结果集,例如:

A表存放人的收入信息,一个人对应多条收入信息。A表在left join 前需要先处理出人的总收入,故用()将select id,sum(sr) from A group by id包起来,并起别名为a,a代表select id,sum(sr) from A group by id执行后的结果集。

--id:人的ID,sr:收入,nl:年龄
select * from (

select id,sum(sr) from A group by id

) a left join B b on a.id = b.id 

where a.nl >35

在写完ETL脚本后,经常需要查询自己生成的主键是否是结果集中的唯一值。pk唯一,方可执行脚本进行数据抽取,这种情况也可以使用上述方法查询主键重复字段:

select pk,count(pk) from (
    select distinct
        A表.pk+B表.pk+B表.pk as pk,
        A表.一些字段,
        B表.一些字段,
        C表.一些字段
    from A A表
    left join B B表 on ...
    left join C C表 on ...
    where ...
) a 
group by pk 
having count(*)>1

 暂时没想到三层的用法,不过有时候可能有需要:

select aa.pk from (
	select a.pk from (
		select distinct
			A表.pk+B表.pk+B表.pk as pk,
			A表.一些字段,
			B表.一些字段,
			C表.一些字段
		from A A表
		left join B B表 on ...
		left join C C表 on ...
		where ...
	) a 
) aa

2、如果一张表中存在千万条数据,查看这张表的时候可以先查询表中前10条数据:

--oracle:

select * from A where rownum<=10

--sqlserver:

select top 10 * from A

3、如果一张表有一百多个字段,在查看数据时,可以将几个重要的字段提取到前面显示,例如:将靠后的字段放到第一个字段位置显示

--oracle:

select a.最后一个字段,a.* from A a

--sqlserver

select 最后一个字段,* from A

oracle中不能像sqlserver那样直接将字段名写在最前面,需要给表起别名

 

4、如果根据几张表联合查询后生成的结果集只能采用主键自增的方式生成主键,才能进行数据抽取,则可以根据某个字段自增生成pk,例如:

职工表中有职工ID,职工名称,工资。需要left join 职工的个人信息表、岗位详情表等等,最后查询结果集可以生成一张新的表,假设该新生成的表的主键字段需要采用自增方式才能使得主键唯一:

select DISTINCT
	row_number() over(order by s.id) as pk,
	s.id,
	s.name,
	s.salary,
    ...
from staff s
left join 其他表 

row_number() over(order by 某字段):先将某字段排序,然后从1开始,第一条记录为1,第二条记录为2,...。该函数的执行时间晚于where 条件 ,group  by ,order by 

 5、对于数据库中一张陌生的表,查看该表的有多少个字段:

--对于oracle:
--upper函数是为了将表名转换为大写字母
select count(*) from user_tab_columns where table_name=upper('表名')

--查看字段的名称
select a.COLUMN_NAME as 字段名称,a.* from user_tab_columns a where table_name=upper('表名')


--对于sql server,查看字段,需要在该表所在架构下打开sql查询窗口才能查到
select * from information_schema.COLUMNS where table_name = '表名';

6、存储过程:

假设职工的工资是月表,例如2019年1月是staff201901,该表存放2019年1月给哪个职工发放了多少工资,每个月表的表结构都是一样的,只有数据是不一样的。现在使用存储过程查询出2019年1到3月份所有发放工资信息(staff201901、staff201902、staff201903三张表在本地oracle与sqlserver中都存在):

对于sql server:

--不采用存储过程

select id as 职工ID,salary as 发放工资,CREATETIME as 发放时间 from STAFF201901
union 
select id as 职工ID,salary as 发放工资,CREATETIME as 发放时间 from STAFF201902
union 
select id as 职工ID,salary as 发放工资,CREATETIME as 发放时间 from STAFF201903

--使用存储过程

--定义变量tablename用于存放表名后面变化的年月,变量sql用于存放sql语句,rflag用于存放月份,lflag用于存放年份
declare @tablename varchar(20), @SQL varchar(8000),@rflag int,@lflag int
--初始化月份为0,表的年月为空,sql语句为空,lflag存放2019
set @rflag=0;
set @tablename='';
set @lflag=2019;
set @SQL='';
--当月份小于3时
while(@rflag<3)
begin
	--月份+1
	set @rflag = @rflag+1;
	--对于1-9的数字,处理成01-09
	if(@rflag<10)
		begin
		--将年份月份拼接起来存放到tablename变量
		set @tablename = 'staff'+CONVERT(varchar,@lflag)+'0'+convert(varchar,@rflag);
		end
	else
		begin
		--将年份月份拼接起来存放到tablename变量
		set @tablename = 'staff'+CONVERT(varchar,@lflag)+convert(varchar,@rflag);
		end
	--拼接sql语句
	set @SQL = @SQL + 'select id as 职工ID,salary as 发放工资,createtime as 发放时间 from '+convert(varchar,@tablename);
	if(@rflag<3)
		begin
		set @sql = @sql+'
		union
		';
		end;
END
--打印sql变量
print @sql
--把sql变量的内容作为sql语句执行
EXEC (@sql)

对于oracle:

--不采用存储过程

select id as 职工ID,salary as 发放工资,CREATETIME as 发放时间 from STAFF201901
union 
select id as 职工ID,salary as 发放工资,CREATETIME as 发放时间 from STAFF201902
union 
select id as 职工ID,salary as 发放工资,CREATETIME as 发放时间 from STAFF201903

--使用存储过程

declare
--定义变量tablename用于存放表名后面变化的年月,变量mysql用于存放sql语句,rflag用于存放月份,lflag用于存放年份
tablename varchar(20);
mysql varchar(8000);
rflag int;
lflag int;
begin 
--初始化月份为0,表的年月为空,sql语句为空,lflag存放2019
rflag:=1;
tablename:='';
lflag:=2019;
mysql:='';
--循环开始
loop 
	--当满足条件rflag>3时,退出循环
	exit when rflag>3;
	--对于1-9的数字,处理成01-09
	if rflag<10
	----将年份月份拼接起来存放到tablename变量
	then tablename:=lflag||'0'||rflag;
	else tablename:=lflag||rflag;
	end if;
	mysql := mysql||'select id,salary,createtime from staff'||tablename;
	if rflag<3
		then 
			tablename:='0'||rflag;
			mysql:=mysql||'	union	';
	--请注意elsif 不是elseif
	elsif rflag=3
		then 
			tablename:='0'||rflag;
	end if;
	--月份+1
	rflag := rflag+1;
--结束循环
end loop;
--打印mysql变量的内容
dbms_output.put_line(mysql);
--动态执行sql语句
EXECUTE IMMEDIATE mysql;
end;

 

 动态执行完sql语句后并没有显示出结果,可以修改一下脚本,将结果集存储到一张表里去:

declare
--定义变量tablename用于存放表名后面变化的年月,变量mysql用于存放sql语句,rflag用于存放月份,lflag用于存放年份
tablename varchar(20);
mysql varchar(8000);
rflag int;
lflag int;
begin 
--初始化月份为0,表的年月为空,sql语句为空,lflag存放2019
rflag:=1;
tablename:='';
lflag:=2019;
mysql:='CREATE TABLE TEMP AS select * from ( ';
--循环开始
loop 
	--当满足条件rflag>3时,退出循环
	exit when rflag>3;
	--对于1-9的数字,处理成01-09
	if rflag<10
	----将年份月份拼接起来存放到tablename变量
	then tablename:=lflag||'0'||rflag;
	else tablename:=lflag||rflag;
	end if;
	mysql := mysql||'select id,salary,createtime from staff'||tablename;
	if rflag<3
		then 
			tablename:='0'||rflag;
			mysql:=mysql||'	union	';
	--请注意elsif 不是elseif
	elsif rflag=3
		then 
			tablename:='0'||rflag;
	end if;
	--月份+1
	rflag := rflag+1;
--结束循环
end loop;
mysql:=mysql||' ) ';
--打印mysql变量的内容
dbms_output.put_line(mysql);
--动态执行sql语句
EXECUTE IMMEDIATE mysql;
end;

 当然,对于EXECUTE IMMEDIATE动态执行sql语句主要还是应用在传递参数动态查询,感兴趣的可以自行百度,这里只是举个栗子~

7、将非字符串类型的数据转换为字符串并拼接:

oracle:

select '职工ID:'||to_char(id) as time from STAFF201901

--对于时间数据转换为字符串
select '发放时间:'||to_char(createtime,'yyyy-mm-dd hh24:mi:ss') as time from STAFF201901

 

sql server:

select '职工ID:'+convert(varchar,id) as time from STAFF201901

--对于时间数据转换为字符串
select '发放时间:'+convert(varchar,createtime,120) as time from STAFF201901

8、oracle中查看表的主键被哪些表所引用:

select a.table_name 子表,b.table_name 主表,a.constraint_name 外键名称 from user_constraints a
left join user_constraints b on a.r_constraint_name = b.constraint_name
where a.constraint_type='R' and a.table_name='表名'
发布了45 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/baidu_41327283/article/details/103636386