0%

mysql存储过程游标的嵌套和使用(统计局地区维度表的创建)

简介

之前主要使用oracle来实现存储过程,今天在写mysql存储过程时发现mysql并没有类似oracle的for循环语法,因此通过游标方式来实现类似功能,本过程通过正则切割地区id将统计局的全国到村和街道的数据装换成供数据仓库使用的宽表结构 (因为统计局提供的地区层次是通过id来区分的,code字段共有12个字符,第1、2位标识省份,第3、4位标识地市、第5、6位标识县区,第7-9位标识乡镇、第10-12位标识村。其数据来自http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/), 转化后的表结构如下 注意这里多了一列当前正在使用的id,这是为了应对后续存在的地区名字或结构变化,这里本人采用的是维度变化的类型6的变种,如果id和正在使用的id相同则代表当前地区是最新结构,否则通过子查询去寻找当前的正在使用的地区id,因为这张表中目前有70多万条数据,如果重新生成较为耗时,且这是一个通用维度,历史数据还是关联就的地区状态,所以需要保留地区维度表的历史信息,且地区信息是拉平的(数据仓库维度表中数据都是拉平的,以此表来说如果有些数据是关联在福建省下则,需要创建,福建省,福建市,福建县,福建镇,福建乡),因为如果维度不拉平则在统计分析时会漏掉直接关联在福建省下的数据.

id 当前正在使用的id
id 福建 福州 闽清 id

代码和注释如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
CREATE DEFINER=`root`@`%` PROCEDURE `F_AREA`()
BEGIN



declare v_sheng_code VARCHAR(20);

declare v_sheng_name VARCHAR(255);


declare v_shi_code VARCHAR(20);

declare v_shi_name VARCHAR(255);

declare v_shi_code_short VARCHAR(20);



declare v_xian_code VARCHAR(20);

declare v_xian_name VARCHAR(255);

declare v_xian_code_short VARCHAR(20);



declare v_zhen_code VARCHAR(20);

declare v_zhen_name VARCHAR(255);

declare v_zhen_code_short VARCHAR(20);


declare v_cun_code VARCHAR(20);

declare v_cun_name VARCHAR(255);


-- 游标变量必须在游标前声明
declare v_done int;


declare c_sheng cursor for SELECT code ,name from region_code4stat_2018 where code REGEXP '^[0-9][0-9]$' ;

-- 声明市游标
declare c_shi cursor for SELECT code ,name from region_code4stat_2018 where code REGEXP concat(concat('^(',v_sheng_code),')[0-9][0-9]0{8,8}$') ;

-- 声明县游标
declare c_xian cursor for SELECT code ,name from region_code4stat_2018 where code REGEXP concat(concat(concat('^(',v_sheng_code),v_shi_code_short),')[0-9][0-9][0]{6,6}$') and code!= concat(concat(v_sheng_code,v_shi_code_short),'00000000');

-- 声明镇游标

declare c_zhen cursor for SELECT code ,name from region_code4stat_2018 where code REGEXP concat(concat(concat(concat('^(',v_sheng_code),v_shi_code_short),v_xian_code_short),')[0-9][0-9][0-9][0]{3,3}$') and code!=concat(concat(concat(v_sheng_code,v_shi_code_short),v_xian_code_short),'000000');


-- 声明村游标

declare c_cun cursor for SELECT code ,name from region_code4stat_2018 where code REGEXP concat(concat(concat(concat(concat('^(',v_sheng_code),v_shi_code_short),v_xian_code_short),v_zhen_code_short),')[0-9]{3,3}$') and code!=concat(concat(concat(concat(v_sheng_code,v_shi_code_short),v_xian_code_short),v_zhen_code_short),'000') ;


-- 声明游标完成状态必须要在游标声明后

DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1;

-- ------------------------------------------------------------------------------------------------------------
-- 打开省游标

open c_sheng;

sheng_loop:LOOP

FETCH c_sheng INTO v_sheng_code,v_sheng_name;

IF v_done = 1 THEN
LEAVE sheng_loop;
END IF;

-- 省数据拉平(数据仓库维度表中数据都是拉平的,以此表来说如果有些数据是关联在福建省下则,需要创建,福建省,福建市,福建县,福建镇,福建乡)
INSERT INTO D_AREA(CODE_,PROVINCE_,CITY_,COUNTRY_,TOWN_,VILLAGE,CURR_CODE_) VALUES(v_sheng_code,v_sheng_name,v_sheng_name,v_sheng_name,v_sheng_name,v_sheng_name, v_sheng_code);

-- -----------------------------------------------------------------------------------------------------------


-- 打开市游标

open c_shi;

shi_loop:LOOP

FETCH c_shi INTO v_shi_code,v_shi_name;

IF v_done = 1 THEN
LEAVE shi_loop;
END IF;

-- 市数据拉平
INSERT INTO D_AREA(CODE_,PROVINCE_,CITY_,COUNTRY_,TOWN_,VILLAGE,CURR_CODE_) VALUES(v_shi_code,v_sheng_name,v_shi_name,v_shi_name,v_shi_name,v_shi_name, v_shi_code);


set v_shi_code_short=substring(v_shi_code,3,2);


-- ------------------------------------------------------------

-- 打开县游标

open c_xian;

xian_loop:LOOP

FETCH c_xian INTO v_xian_code,v_xian_name;

IF v_done = 1 THEN
LEAVE xian_loop;
END IF;

-- 县数据拉平
INSERT INTO D_AREA(CODE_,PROVINCE_,CITY_,COUNTRY_,TOWN_,VILLAGE,CURR_CODE_) VALUES(v_xian_code,v_sheng_name,v_shi_name,v_xian_name,v_xian_name,v_xian_name, v_xian_code);

set v_xian_code_short=substring(v_xian_code,5,2);


-- ---------------------------------------------
-- 打开镇游标


open c_zhen;

zhen_loop:LOOP

FETCH c_zhen INTO v_zhen_code,v_zhen_name;

IF v_done = 1 THEN
LEAVE zhen_loop;
END IF;

-- 镇数据拉平
INSERT INTO D_AREA(CODE_,PROVINCE_,CITY_,COUNTRY_,TOWN_,VILLAGE,CURR_CODE_) VALUES(v_zhen_code,v_sheng_name,v_shi_name,v_xian_name,v_zhen_name,v_zhen_name, v_zhen_code);

set v_zhen_code_short=substring(v_zhen_code,7,3);


-- ---------------------------------------------------------------------
-- 打开村游标

open c_cun;

cun_loop:LOOP

FETCH c_cun INTO v_cun_code,v_cun_name;

IF v_done = 1 THEN
LEAVE cun_loop;
END IF;

INSERT INTO D_AREA(CODE_,PROVINCE_,CITY_,COUNTRY_,TOWN_,VILLAGE,CURR_CODE_) VALUES(v_cun_code,v_sheng_name,v_shi_name,v_xian_name,v_zhen_name,v_cun_name, v_cun_code);


end LOOP cun_loop;
CLOSE c_cun;

-- 注意这里需要将v_done初始化,不然外层循环也将跳出
SET v_done=0;






end LOOP zhen_loop;
CLOSE c_zhen;
SET v_done=0;






end LOOP xian_loop;
CLOSE c_xian;
SET v_done=0;









end LOOP shi_loop;
CLOSE c_shi;
SET v_done=0;













end LOOP sheng_loop;
CLOSE c_sheng;

END

参考

游标嵌套部分参考代码
https://www.cnblogs.com/phao123/p/6006780.html