execsql2 1.130.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- execsql/__init__.py +3 -0
- execsql/__main__.py +5 -0
- execsql/execsql.py +16627 -0
- execsql2-1.130.1.data/data/execsql2_extras/READ_ME.rst +129 -0
- execsql2-1.130.1.data/data/execsql2_extras/config_settings.sqlite +0 -0
- execsql2-1.130.1.data/data/execsql2_extras/example_config_prompt.sql +159 -0
- execsql2-1.130.1.data/data/execsql2_extras/execsql.conf +289 -0
- execsql2-1.130.1.data/data/execsql2_extras/make_config_db.sql +250 -0
- execsql2-1.130.1.data/data/execsql2_extras/md_compare.sql +630 -0
- execsql2-1.130.1.data/data/execsql2_extras/md_glossary.sql +327 -0
- execsql2-1.130.1.data/data/execsql2_extras/md_upsert.sql +2981 -0
- execsql2-1.130.1.data/data/execsql2_extras/pg_compare.sql +629 -0
- execsql2-1.130.1.data/data/execsql2_extras/pg_glossary.sql +291 -0
- execsql2-1.130.1.data/data/execsql2_extras/pg_upsert.sql +2792 -0
- execsql2-1.130.1.data/data/execsql2_extras/script_template.sql +300 -0
- execsql2-1.130.1.data/data/execsql2_extras/ss_compare.sql +639 -0
- execsql2-1.130.1.data/data/execsql2_extras/ss_glossary.sql +405 -0
- execsql2-1.130.1.data/data/execsql2_extras/ss_upsert.sql +2917 -0
- execsql2-1.130.1.dist-info/METADATA +418 -0
- execsql2-1.130.1.dist-info/RECORD +24 -0
- execsql2-1.130.1.dist-info/WHEEL +4 -0
- execsql2-1.130.1.dist-info/entry_points.txt +2 -0
- execsql2-1.130.1.dist-info/licenses/LICENSE.txt +12 -0
- execsql2-1.130.1.dist-info/licenses/NOTICE +10 -0
|
@@ -0,0 +1,2981 @@
|
|
|
1
|
+
-- md_upsert.sql
|
|
2
|
+
--
|
|
3
|
+
-- PURPOSE
|
|
4
|
+
-- A set of execsql scripts to check data in a staging table, or
|
|
5
|
+
-- a set of staging tables, and then update and insert rows of a base table
|
|
6
|
+
-- or base tables from the staging table(s) of the same name.
|
|
7
|
+
--
|
|
8
|
+
-- This script contains code specific to MariaDB/MySQL.
|
|
9
|
+
--
|
|
10
|
+
-- HOW TO USE THESE SCRIPTS
|
|
11
|
+
-- In the following steps, "call" means to use an execsql "execute script"
|
|
12
|
+
-- metacommand. Script names are displayed in uppercase to distinguish
|
|
13
|
+
-- them below, but execsql is not case-sensitive.
|
|
14
|
+
--
|
|
15
|
+
-- The simplest usage is:
|
|
16
|
+
-- 1. Call STAGED_TO_LOAD to create and initially populate a table
|
|
17
|
+
-- with the names of staging tables to be loaded, and initial
|
|
18
|
+
-- control variables used by other scripts.
|
|
19
|
+
-- 2. Call LOAD_STAGING to perform QA checks for erroneous nulls,
|
|
20
|
+
-- duplicated primary keys, and missing foreign keys, and to
|
|
21
|
+
-- load the data using update and insert statements if there were
|
|
22
|
+
-- no QA errors.
|
|
23
|
+
--
|
|
24
|
+
-- The control table that is produced in step 1 above can be edited to
|
|
25
|
+
-- add a list of columns to exclude from the update, or to change the
|
|
26
|
+
-- defaults for display of changed data. See the header notes for the
|
|
27
|
+
-- STAGED_TO_LOAD script.
|
|
28
|
+
--
|
|
29
|
+
-- The processes of performing QA checks and performing the upsert operations
|
|
30
|
+
-- can be further broken down into individual steps. See Note #1 below
|
|
31
|
+
-- for the other scripts that can be used to carry out these steps.
|
|
32
|
+
--
|
|
33
|
+
-- NOTES
|
|
34
|
+
-- 1. The scripts contained in this file that are intended to be called
|
|
35
|
+
-- directly by the user are:
|
|
36
|
+
-- STAGED_TO_LOAD : Initialize a control table to load multiple tables.
|
|
37
|
+
-- LOAD_STAGING : Perform all QA checks and load data from all staging tables.
|
|
38
|
+
-- QA_ALL : Perform null and foreign key checks on all staging tables.
|
|
39
|
+
-- UPSERT_ALL : Load data from all staging tables.
|
|
40
|
+
-- NULLQA_ONE : Perform null column checks on one staging table.
|
|
41
|
+
-- PKQA_ONE : Perform primary key checks on one staging table.
|
|
42
|
+
-- FKQA_ONE : Perform foreign key checks on one staging table.
|
|
43
|
+
-- UPSERT_ONE : Load data from one staging table.
|
|
44
|
+
-- This file contains other scripts that are intended to be used
|
|
45
|
+
-- only by one of the scripts listed above, and not called
|
|
46
|
+
-- directly by the user.
|
|
47
|
+
-- 2. These scripts query the information schema to obtain
|
|
48
|
+
-- the information needed to perform the checks and changes.
|
|
49
|
+
-- 3. These scripts create and delete tables in the active database.
|
|
50
|
+
-- Because MariaDB/MySQL does not (currently) support temporary
|
|
51
|
+
-- views, or views on temporary tables, most of the views and
|
|
52
|
+
-- tables that are created are potentially visible to other
|
|
53
|
+
-- database operations. See the header notes for invdividual
|
|
54
|
+
-- execsql scripts for names of the tables and views used.
|
|
55
|
+
-- 4. These scripts take arguments that control their functions. They
|
|
56
|
+
-- also use global variables pertinent to logging, if they are
|
|
57
|
+
-- defined. The logging-control variables are global because
|
|
58
|
+
-- they may also be used by other code that uses these scripts,
|
|
59
|
+
-- and some of that code may be older and only recognize global
|
|
60
|
+
-- variables rather than script arguments; logging is intended
|
|
61
|
+
-- to be compatible with them.
|
|
62
|
+
-- 5. The control table that is used to drive the loading of multiple
|
|
63
|
+
-- staging tables will be updated by the QA scripts with information
|
|
64
|
+
-- about any QA failures. This information consists of a list of
|
|
65
|
+
-- the names of the columns or constraints that failed the check,
|
|
66
|
+
-- with the number of failing rows in paretheses following the name.
|
|
67
|
+
-- 6. The control table that is used to drive the loading of multiple
|
|
68
|
+
-- staging tables will be updated by the upsert operation with
|
|
69
|
+
-- a count of the number of rows of the base table that are updated,
|
|
70
|
+
-- and a count of the number of rows that were inserted into the
|
|
71
|
+
-- base table.
|
|
72
|
+
-- 7. All of these scripts assume that schema, table, and column
|
|
73
|
+
-- names need not be quoted.
|
|
74
|
+
-- 8. These scripts create temporary tables and views. All of thes
|
|
75
|
+
-- have prefixes of "ups_". Scripts that include this file
|
|
76
|
+
-- should not use this prefix to avoid possible conflicts.
|
|
77
|
+
--
|
|
78
|
+
-- COPYRIGHT AND LICENSE
|
|
79
|
+
-- Copyright (c) 2019, R. Dreas Nielsen
|
|
80
|
+
-- This program is free software: you can redistribute it and/or modify it
|
|
81
|
+
-- under the terms of the GNU General Public License as published by the
|
|
82
|
+
-- Free Software Foundation, either version 3 of the License, or (at your
|
|
83
|
+
-- option) any later version. This program is distributed in the hope that
|
|
84
|
+
-- it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
85
|
+
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
86
|
+
-- GNU General Public License for more details. The GNU General Public
|
|
87
|
+
-- License is available at http://www.gnu.org/licenses/.
|
|
88
|
+
|
|
89
|
+
-- AUTHORS
|
|
90
|
+
-- Dreas Nielsen (RDN)
|
|
91
|
+
-- Elizabeth Shea (ES)
|
|
92
|
+
--
|
|
93
|
+
-- VERSION
|
|
94
|
+
-- 2.0.0
|
|
95
|
+
--
|
|
96
|
+
-- HISTORY
|
|
97
|
+
-- Date Remarks
|
|
98
|
+
-- ---------- -----------------------------------------------------
|
|
99
|
+
-- 2019-01-15 Began first component scripts. RDN.
|
|
100
|
+
-- 2019-01-30 Integrated separate scripts into this one file and
|
|
101
|
+
-- began modifications to set parameters and arguments. RDN.
|
|
102
|
+
-- 2019-01-31 Editing. RDN.
|
|
103
|
+
-- 2019-02-01 Completed revisions to set parameters and arguments.
|
|
104
|
+
-- Added scripts "staged_to_load", "upsert_all", and
|
|
105
|
+
-- "load_staging".
|
|
106
|
+
-- Added and modified documentation. RDN.
|
|
107
|
+
-- 2019-02-02 Debugging edits. RDN.
|
|
108
|
+
-- 2019-02-03 Edits from 2019-02-03 pg version for MariaDB/MySQL
|
|
109
|
+
-- compatibility. RDN.
|
|
110
|
+
-- 2019-02-05 Edits for MariaDB: conversion of staging schema to
|
|
111
|
+
-- a staging prefix. RDN.
|
|
112
|
+
-- 2019-02-14 Added where clause conditions for schema name equal
|
|
113
|
+
-- to the current database to prevent multiple null
|
|
114
|
+
-- checks when there are multiple databases with the
|
|
115
|
+
-- same table and column names. RDN.
|
|
116
|
+
-- 2019-02-15 Modified all internal table and view names to use a
|
|
117
|
+
-- prefix of "ups_". RDN.
|
|
118
|
+
-- 2019-02-16 Modified to include in the list of ordered tables all
|
|
119
|
+
-- tables that are not part of any foreign key relationship.
|
|
120
|
+
-- Modified to use an 'exclude_null_checks' setting. RDN.
|
|
121
|
+
-- 2019-02-17 Corrected the check to display changes in UPSERT_ONE. RDN.
|
|
122
|
+
-- 2019-02-21 Modifed QA_ALL_NULLLOOP and QA_ALL_FKLOOP to use local
|
|
123
|
+
-- variables and the new outer scope referent prefix for
|
|
124
|
+
-- the return values. RDN.
|
|
125
|
+
-- 2019-03-02 Changed to use 'autocommit with commit'. Modified
|
|
126
|
+
-- recursive CTE to order dependencies to protect against
|
|
127
|
+
-- multi-table cycles. RDN.
|
|
128
|
+
-- 2019-03-02 Modified to show the number of rows with each invalid
|
|
129
|
+
-- foreign key value, in both the GUI display and the
|
|
130
|
+
-- logfile. RDN.
|
|
131
|
+
-- 2019-03-03 Added the 'do_commit' argument to LOAD_STAGING. RDN.
|
|
132
|
+
-- 2019-03-09 Added FKQA_ONE with related changes from SS version
|
|
133
|
+
-- by ES. Modified addition of solo tables to the set
|
|
134
|
+
-- of ordered tables per ES revisions. Other fixes
|
|
135
|
+
-- following ES changes to pg_upsert.sql. Revised
|
|
136
|
+
-- recursive CTE for FK ordering to eliminate
|
|
137
|
+
-- hangs on referential cycles of >2 tables. RDN.
|
|
138
|
+
-- 2019-03-15 Added VALIDATE_ONE and calls to it. RDN.
|
|
139
|
+
-- 2019-03-24 Added constraints to PKQA_ONE to limit to the
|
|
140
|
+
-- current database. RDN.
|
|
141
|
+
-- 2019-06-08 Began addition of PK updating scripts. Complete
|
|
142
|
+
-- through QA check 8. RDN.
|
|
143
|
+
-- 2019-06-16 Nominally complete revisions of PK updating scripts. RDN.
|
|
144
|
+
-- 2019-06-23 Completed debugging of PK updating scripts. RDN.
|
|
145
|
+
-- 2020-04-28 Explicitly rolled back the changes if 'do_commit' = "No". RDN.
|
|
146
|
+
-- 2020-05-09 Moved the assignment of 'upsert_progress_denom' out of the
|
|
147
|
+
-- 'update_console_qa' script. RDN.
|
|
148
|
+
-- ==================================================================
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
-- ################################################################
|
|
153
|
+
-- Script VALIDATE_ONE
|
|
154
|
+
-- ===============================================================
|
|
155
|
+
--
|
|
156
|
+
-- Utility script to validate both base and staging versions of one table.
|
|
157
|
+
-- Halts script processing if either of the tables are not present.
|
|
158
|
+
--
|
|
159
|
+
-- Input parameters:
|
|
160
|
+
-- stage_pfx : The prefix for staging tables.
|
|
161
|
+
-- table_name : The name of the table.
|
|
162
|
+
-- script : The name of the script in which the
|
|
163
|
+
-- schemas and table were referenced
|
|
164
|
+
-- (for error reporting).
|
|
165
|
+
-- script_line : The script line in which they were referenced
|
|
166
|
+
-- (for error reporting).
|
|
167
|
+
-- ===============================================================
|
|
168
|
+
-- !x! BEGIN SCRIPT VALIDATE_ONE with parameters (stage_pfx, table, script, script_line)
|
|
169
|
+
|
|
170
|
+
-- Initialize the strings used to compile error information
|
|
171
|
+
-- !x! sub_empty ~err_info
|
|
172
|
+
-- !x! sub_empty ~error_list
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
-- !x! if(table_exists(ups_invl_table))
|
|
176
|
+
drop table if exists ups_invl_table cascade;
|
|
177
|
+
-- !x! endif
|
|
178
|
+
create table ups_invl_table
|
|
179
|
+
select
|
|
180
|
+
group_concat(concat(tt.table_name, ' (', tt.schema_type, ')') order by tt.table_name separator ';') as schema_table
|
|
181
|
+
from
|
|
182
|
+
(
|
|
183
|
+
select
|
|
184
|
+
'base' as schema_type,
|
|
185
|
+
'!!#table!!' as table_name
|
|
186
|
+
union
|
|
187
|
+
select
|
|
188
|
+
|
|
189
|
+
'staging' as schema_type,
|
|
190
|
+
'!!#stage_pfx!!!!#table!!' as table_name
|
|
191
|
+
) as tt
|
|
192
|
+
left join information_schema.tables as iss on tt.table_name=iss.table_name
|
|
193
|
+
where
|
|
194
|
+
iss.table_name is null
|
|
195
|
+
and iss.table_schema = '!!$DB_NAME!!'
|
|
196
|
+
having count(*) > 0
|
|
197
|
+
;
|
|
198
|
+
|
|
199
|
+
-- !x! if(hasrows(ups_invl_table))
|
|
200
|
+
-- !x! subdata ~err_info ups_invl_table
|
|
201
|
+
-- !x! sub ~error_list Non-existent table: !!~err_info!!
|
|
202
|
+
-- !x! endif
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
-- Halt script if any schemas or tables were found to be invalid
|
|
207
|
+
-- !x! if(not is_null("!!~error_list!!"))
|
|
208
|
+
|
|
209
|
+
-- !x! sub ~error_message ERROR - INVALID OBJECT IN SCRIPT ARGUMENT
|
|
210
|
+
|
|
211
|
+
-- !x! if(sub_defined(log_changes))
|
|
212
|
+
-- !x! andif(is_true(!!log_changes!!))
|
|
213
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
214
|
+
-- !x! write "!!$current_time!! -- !!~error_message!!" to !!logfile!!
|
|
215
|
+
-- !x! write "Script: !!#script!!; Line: !!#script_line!!" to !!logfile!!
|
|
216
|
+
-- !x! write "!!~error_list!!" to !!logfile!!
|
|
217
|
+
-- !x! endif
|
|
218
|
+
|
|
219
|
+
-- !x! sub_append ~error_message Script: !!#script!!; Line: !!#script_line!! -- !x! sub_append ~error_message !!~error_list!! -- !x! halt message "!!~error_message!!"
|
|
220
|
+
|
|
221
|
+
-- !x! endif
|
|
222
|
+
|
|
223
|
+
-- !x! if(table_exists(ups_invl_table))
|
|
224
|
+
drop table if exists ups_invl_table cascade;
|
|
225
|
+
-- !x! endif
|
|
226
|
+
|
|
227
|
+
-- !x! END SCRIPT
|
|
228
|
+
-- #################### End of VALIDATE_ONE #####################
|
|
229
|
+
-- ################################################################
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
-- ################################################################
|
|
234
|
+
-- Script VALIDATE_CONTROL
|
|
235
|
+
-- ===============================================================
|
|
236
|
+
--
|
|
237
|
+
-- Utility script to validate contents of control table against about
|
|
238
|
+
-- base and staging schema
|
|
239
|
+
--
|
|
240
|
+
-- Required input arguments:
|
|
241
|
+
-- stage_pfx : The name of the staging schema.
|
|
242
|
+
-- control_table : The name of a temporary table as created by the
|
|
243
|
+
-- script STAGED_TO_LOAD.
|
|
244
|
+
-- script : The name of the script in which the
|
|
245
|
+
-- schemas and control table were referenced
|
|
246
|
+
-- (for error reporting).
|
|
247
|
+
-- script_line : The script line in which they were referenced
|
|
248
|
+
-- (for error reporting).
|
|
249
|
+
-- ===============================================================
|
|
250
|
+
-- !x! BEGIN SCRIPT VALIDATE_CONTROL with parameters (stage_pfx, control_table, script, script_line)
|
|
251
|
+
|
|
252
|
+
-- Initialize the strings used to compile error information
|
|
253
|
+
-- !x! sub_empty ~err_info
|
|
254
|
+
-- !x! sub_empty ~error_list
|
|
255
|
+
|
|
256
|
+
-- !x! if(table_exists(ups_validate_control))
|
|
257
|
+
drop table if exists ups_validate_control cascade;
|
|
258
|
+
-- !x! endif
|
|
259
|
+
create table ups_validate_control
|
|
260
|
+
select
|
|
261
|
+
table_name,
|
|
262
|
+
False as base_exists,
|
|
263
|
+
False as staging_exists
|
|
264
|
+
from !!#control_table!!
|
|
265
|
+
;
|
|
266
|
+
|
|
267
|
+
-- Update the validation table
|
|
268
|
+
update ups_validate_control as vc, information_schema.tables as bt
|
|
269
|
+
set vc.base_exists = True
|
|
270
|
+
where
|
|
271
|
+
vc.table_name=bt.table_name
|
|
272
|
+
and bt.table_type='BASE TABLE'
|
|
273
|
+
and bt.table_schema = '!!$DB_NAME!!'
|
|
274
|
+
;
|
|
275
|
+
|
|
276
|
+
update ups_validate_control as vc, information_schema.tables as st
|
|
277
|
+
set vc.staging_exists = True
|
|
278
|
+
where
|
|
279
|
+
st.table_name= concat('!!#stage_pfx!!', vc.table_name)
|
|
280
|
+
and st.table_type='BASE TABLE'
|
|
281
|
+
and st.table_schema = '!!$DB_NAME!!'
|
|
282
|
+
;
|
|
283
|
+
|
|
284
|
+
-- !x! if(table_exists(ups_ctrl_invl_table))
|
|
285
|
+
drop table if exists ups_ctrl_invl_table cascade;
|
|
286
|
+
-- !x! endif
|
|
287
|
+
create table ups_ctrl_invl_table
|
|
288
|
+
select
|
|
289
|
+
group_concat(schema_table order by it.schema_table separator '; ') as schema_table
|
|
290
|
+
from
|
|
291
|
+
(
|
|
292
|
+
select table_name as schema_table
|
|
293
|
+
from ups_validate_control
|
|
294
|
+
where not base_exists
|
|
295
|
+
union
|
|
296
|
+
select concat('!!#stage_pfx!!', table_name) as schema_table
|
|
297
|
+
from ups_validate_control
|
|
298
|
+
where not staging_exists
|
|
299
|
+
) as it
|
|
300
|
+
having count(*) > 0
|
|
301
|
+
;
|
|
302
|
+
|
|
303
|
+
-- Any table is invalid
|
|
304
|
+
-- !x! if(hasrows(ups_ctrl_invl_table))
|
|
305
|
+
-- !x! subdata ~err_info ups_validate_control
|
|
306
|
+
-- !x! sub ~error_list Non-existent table(s): !!~err_info!!
|
|
307
|
+
-- !x! endif
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
-- Halt script if any invalid objects found in control table
|
|
311
|
+
-- !x! if(not is_null("!!~error_list!!"))
|
|
312
|
+
|
|
313
|
+
-- !x! sub ~error_message ERROR - INVALID OBJECTS IN CONTROL TABLE
|
|
314
|
+
|
|
315
|
+
-- !x! if(sub_defined(log_changes))
|
|
316
|
+
-- !x! andif(is_true(!!log_changes!!))
|
|
317
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
318
|
+
-- !x! write "!!$current_time!! -- !!~error_message!!" to !!logfile!!
|
|
319
|
+
-- !x! write "Script: !!#script!!; Line: !!#script_line!!" to !!logfile!!
|
|
320
|
+
-- !x! write "!!~error_list!!" to !!logfile!!
|
|
321
|
+
-- !x! endif
|
|
322
|
+
|
|
323
|
+
-- !x! sub_append ~error_message Script: !!#script!!; Line: !!#script_line!!
|
|
324
|
+
-- !x! sub_append ~error_message !!~error_list!!
|
|
325
|
+
-- !x! halt message "!!~error_message!!"
|
|
326
|
+
|
|
327
|
+
-- !x! endif
|
|
328
|
+
|
|
329
|
+
-- !x! if(table_exists(ups_validate_control))
|
|
330
|
+
drop table if exists ups_validate_control cascade;
|
|
331
|
+
-- !x! endif
|
|
332
|
+
-- !x! if(table_exists(ups_ctrl_invl_table))
|
|
333
|
+
drop table if exists ups_ctrl_invl_table cascade;
|
|
334
|
+
-- !x! endif
|
|
335
|
+
|
|
336
|
+
-- !x! END SCRIPT
|
|
337
|
+
-- #################### End of VALIDATE_CONTROL #################
|
|
338
|
+
-- ################################################################
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
-- ################################################################
|
|
342
|
+
-- Script STAGED_TO_LOAD
|
|
343
|
+
-- ===============================================================
|
|
344
|
+
--
|
|
345
|
+
-- Creates a table having the structure that is used to drive other
|
|
346
|
+
-- scripts that perform QA checks and the upsert operation on multiple
|
|
347
|
+
-- staging tables.
|
|
348
|
+
--
|
|
349
|
+
-- Input parameters:
|
|
350
|
+
-- control_table : The name of the table to be created.
|
|
351
|
+
-- In MariaDB/MySQL, this must *not* be a
|
|
352
|
+
-- temporary table.
|
|
353
|
+
-- table_list : A string of comma-separated table names,
|
|
354
|
+
-- identifying the staging tables to be
|
|
355
|
+
-- checked or loaded.
|
|
356
|
+
--
|
|
357
|
+
-- Columns in the table created:
|
|
358
|
+
-- table_name : The name of a base table that has a
|
|
359
|
+
-- corresponding table in a staging schema
|
|
360
|
+
-- containing data to be used to modify
|
|
361
|
+
-- the base table.
|
|
362
|
+
-- exclude_cols : Contains a comma-separated list of columns
|
|
363
|
+
-- in the base table that are not to be
|
|
364
|
+
-- updated from the staging table. This is
|
|
365
|
+
-- uninitialized.
|
|
366
|
+
-- exclude_null_checks :
|
|
367
|
+
-- Contains a comma-separated list of single-quoted
|
|
368
|
+
-- column names identifying column in the
|
|
369
|
+
-- staging table for which null checks
|
|
370
|
+
-- should not be performed. This is
|
|
371
|
+
-- uninitialized.
|
|
372
|
+
-- display_changes : A Boolean indicating whether the 'upsert'
|
|
373
|
+
-- operation should display the changes to
|
|
374
|
+
-- be made to the base table. A separate
|
|
375
|
+
-- GUI display is used for updates and inserts.
|
|
376
|
+
-- Initialized to True.
|
|
377
|
+
-- display_final : A Boolean indicating whether the 'upsert'
|
|
378
|
+
-- operation should display the entire base
|
|
379
|
+
-- table after updates and inserts have been
|
|
380
|
+
-- made. Initialized to False.
|
|
381
|
+
-- null_errors : Will contain a comma-separated list of
|
|
382
|
+
-- columns that are non-nullable in the base
|
|
383
|
+
-- table but that have nulls in the staging
|
|
384
|
+
-- table. Initialized to null; may be filled
|
|
385
|
+
-- by the QA routines.
|
|
386
|
+
-- pk_errors : Will contain a count of the number of distinct
|
|
387
|
+
-- primary key values having duplicate rows,
|
|
388
|
+
-- followed by the total row count for the
|
|
389
|
+
-- duplicated keys. Initialized to null; may
|
|
390
|
+
-- be filled by the QA routines.
|
|
391
|
+
-- fk_errors : Will contain a comma-separated list of
|
|
392
|
+
-- foreign-key constraint names that are
|
|
393
|
+
-- not met by data in the staging table.
|
|
394
|
+
-- Initialized to null; may be filled by the
|
|
395
|
+
-- QA routines.
|
|
396
|
+
-- rows_updated : Will contain a count of the rows updated
|
|
397
|
+
-- in the table by the upsert operation.
|
|
398
|
+
-- rows_inserted : Will contain a count of the rows inserted
|
|
399
|
+
-- in the table by the upsert operation.
|
|
400
|
+
--
|
|
401
|
+
-- Example:
|
|
402
|
+
-- -- !x! execute script staged_to_load with (control_table=stagingtables, table_list="tbla, tblb, tblc")
|
|
403
|
+
-- ===============================================================
|
|
404
|
+
|
|
405
|
+
-- !x! BEGIN SCRIPT STAGED_TO_LOAD with parameters (control_table, table_list)
|
|
406
|
+
|
|
407
|
+
drop table if exists !!#control_table!! cascade;
|
|
408
|
+
|
|
409
|
+
create table !!#control_table!! (
|
|
410
|
+
table_name varchar(150) not null unique,
|
|
411
|
+
exclude_cols varchar(255),
|
|
412
|
+
exclude_null_checks varchar(255),
|
|
413
|
+
display_changes varchar(3) not null default 'Yes',
|
|
414
|
+
display_final varchar(3) not null default 'No',
|
|
415
|
+
null_errors varchar(255),
|
|
416
|
+
pk_errors varchar(255),
|
|
417
|
+
fk_errors varchar(255),
|
|
418
|
+
rows_updated integer,
|
|
419
|
+
rows_inserted integer,
|
|
420
|
+
constraint ck_chgyn check (display_changes in ('Yes', 'No')),
|
|
421
|
+
constraint ck_finalyn check (display_final in ('Yes', 'No'))
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
insert into !!#control_table!!
|
|
425
|
+
(table_name)
|
|
426
|
+
with recursive itemtable as (
|
|
427
|
+
select
|
|
428
|
+
trim(substring_index(data, ',', 1)) as table_name,
|
|
429
|
+
right(data, length(data) - locate(',', data, 1)) as data
|
|
430
|
+
from (select '!!#table_list!!' as data) as input
|
|
431
|
+
union
|
|
432
|
+
select
|
|
433
|
+
trim(substring_index(data, ',', 1)) as table_name,
|
|
434
|
+
right(data, length(data) - locate(',', data, 1)) as data
|
|
435
|
+
from itemtable
|
|
436
|
+
)
|
|
437
|
+
select table_name as item
|
|
438
|
+
from itemtable;
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
-- !x! END SCRIPT
|
|
442
|
+
-- ################## End of STAGED_TO_LOAD #####################
|
|
443
|
+
-- ################################################################
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
-- ################################################################
|
|
448
|
+
-- Script LOAD_STAGING
|
|
449
|
+
-- ===============================================================
|
|
450
|
+
--
|
|
451
|
+
-- Performs QA checks for nulls in non-null columns, for duplicated
|
|
452
|
+
-- primary key values, and for invalid foreign keys in a set of staging
|
|
453
|
+
-- tables to be loaded into base tables. If there are failures in the
|
|
454
|
+
-- QA checks, loading is not attempted. If the loading step is
|
|
455
|
+
-- carried out, it is done within a transaction.
|
|
456
|
+
--
|
|
457
|
+
-- The "null_errors" and "fk_errors" columns of the control table
|
|
458
|
+
-- will be updated to identify any errors that occur, so that this
|
|
459
|
+
-- information is available to the caller.
|
|
460
|
+
--
|
|
461
|
+
-- The "rows_updated" and "rows_inserted" columns of the control table
|
|
462
|
+
-- will be updated with counts of the number of rows affected by the
|
|
463
|
+
-- upsert operation for each table.
|
|
464
|
+
--
|
|
465
|
+
-- When the upsert operation updates the base table, all columns of the
|
|
466
|
+
-- base table that are also in the staging table are updated. The
|
|
467
|
+
-- update operation does not test to see if column contents are different,
|
|
468
|
+
-- and so does not update only those values that are different.
|
|
469
|
+
--
|
|
470
|
+
-- Input parameters:
|
|
471
|
+
-- stage_pfg : The prefix on staging tables that distinguish
|
|
472
|
+
-- them from the corresponding based table
|
|
473
|
+
-- (e.g., "stg_").
|
|
474
|
+
-- control_table : The name of a table as created by the
|
|
475
|
+
-- script STAGED_TO_LOAD.
|
|
476
|
+
-- do_commit : Whether or not the script should commit
|
|
477
|
+
-- the changes; should be 'Yes' or 'No'.
|
|
478
|
+
-- Global variables:
|
|
479
|
+
-- logfile : The name of a log file to which error
|
|
480
|
+
-- messages will be written. Optional.
|
|
481
|
+
-- log_sql : A value of 'Yes' or 'No' to indicate whether
|
|
482
|
+
-- the SQL that is generated for each foreign
|
|
483
|
+
-- key check, and for each update and insert
|
|
484
|
+
-- statement, is written to the logfile. Optional.
|
|
485
|
+
-- log_errors : A value of 'Yes' or 'No' to indicate whether
|
|
486
|
+
-- foreign key errors are written to the logfile.
|
|
487
|
+
-- Optional.
|
|
488
|
+
-- log_changes : A value of 'Yes' or 'No' indicating whether
|
|
489
|
+
-- the updated and inserted data should be
|
|
490
|
+
-- written to the logfile. Optional.
|
|
491
|
+
--
|
|
492
|
+
-- Tables and views created or modified:
|
|
493
|
+
-- ups_qa_fails : view
|
|
494
|
+
-- ===============================================================
|
|
495
|
+
|
|
496
|
+
-- !x! BEGIN SCRIPT LOAD_STAGING with parameters (stage_pfx, control_table, do_commit)
|
|
497
|
+
|
|
498
|
+
-- Clear the columns of return values from the control table, in case this control
|
|
499
|
+
-- table has been used previously.
|
|
500
|
+
update !!#control_table!!
|
|
501
|
+
set
|
|
502
|
+
null_errors = null,
|
|
503
|
+
pk_errors = null,
|
|
504
|
+
fk_errors = null,
|
|
505
|
+
rows_updated = null,
|
|
506
|
+
rows_inserted = null
|
|
507
|
+
;
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
-- Run null checks, PK checks, and FK checks.
|
|
511
|
+
-- !x! execute script QA_ALL with arguments (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
512
|
+
-- !x! if(view_exists(ups_qa_fails))
|
|
513
|
+
drop view if exists ups_qa_fails cascade;
|
|
514
|
+
-- !x! endif
|
|
515
|
+
create view ups_qa_fails as
|
|
516
|
+
select *
|
|
517
|
+
from !!#control_table!!
|
|
518
|
+
where null_errors is not null or pk_errors is not null or fk_errors is not null;
|
|
519
|
+
-- !x! if(not hasrows(ups_qa_fails))
|
|
520
|
+
-- !x! sub ~preautocommit !!$autocommit_state!!
|
|
521
|
+
-- !x! autocommit off
|
|
522
|
+
-- !x! execute script UPSERT_ALL with arguments (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
523
|
+
-- !x! if(is_true(!!#do_commit!!))
|
|
524
|
+
-- !x! autocommit on with commit
|
|
525
|
+
-- !x! write "CHANGES COMMITTED."
|
|
526
|
+
-- !x! if(sub_defined(log_changes))
|
|
527
|
+
-- !x! andif(is_true(!!log_changes!!))
|
|
528
|
+
-- !x! write "" to !!logfile!!
|
|
529
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
530
|
+
-- !x! write "!!$current_time!! -- CHANGES COMMITTED." to !!logfile!!
|
|
531
|
+
-- !x! endif
|
|
532
|
+
-- !x! else
|
|
533
|
+
-- !x! autocommit on with rollback
|
|
534
|
+
-- !x! write "CHANGES NOT COMMITTED ('do_commit' argument = !!#do_commit!!)"
|
|
535
|
+
-- !x! if(sub_defined(log_changes))
|
|
536
|
+
-- !x! andif(is_true(!!log_changes!!))
|
|
537
|
+
-- !x! write "" to !!logfile!!
|
|
538
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
539
|
+
-- !x! write "!!$current_time!! -- CHANGES NOT COMMITTED ('do_commit' argument = !!#do_commit!!)" to !!logfile!!
|
|
540
|
+
-- !x! endif
|
|
541
|
+
-- !x! endif
|
|
542
|
+
-- !x! autocommit !!~preautocommit!!
|
|
543
|
+
-- !x! endif
|
|
544
|
+
|
|
545
|
+
-- Clean up.
|
|
546
|
+
drop view if exists ups_qa_fails cascade;
|
|
547
|
+
|
|
548
|
+
-- !x! END SCRIPT
|
|
549
|
+
-- ################### End of LOAD_STAGING ######################
|
|
550
|
+
-- ################################################################
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
-- ################################################################
|
|
556
|
+
-- Script NULLQA_ONE
|
|
557
|
+
-- ===============================================================
|
|
558
|
+
--
|
|
559
|
+
-- Checks that non-nullable columns are fully populated in a
|
|
560
|
+
-- staging table that is an image of the base table.
|
|
561
|
+
-- Reports any non-conforming columns to the console and optionally
|
|
562
|
+
-- to a log file.
|
|
563
|
+
--
|
|
564
|
+
-- Required input arguments:
|
|
565
|
+
-- stage_pfx : The name of the staging schema.
|
|
566
|
+
-- table : The table name--same for base and staging.
|
|
567
|
+
-- Optional input arguments:
|
|
568
|
+
-- exclude_null_checks : A comma-separated list of singly-quoted
|
|
569
|
+
-- column names to be excluded from null checks.
|
|
570
|
+
--
|
|
571
|
+
-- Output parameters:
|
|
572
|
+
-- error_list : The name of the variable to receive a comma-
|
|
573
|
+
-- delimited list of the names of non-null
|
|
574
|
+
-- columns that contain nulls; each column name
|
|
575
|
+
-- will be followed by the number of rows with
|
|
576
|
+
-- nulls, in parentheses.
|
|
577
|
+
--
|
|
578
|
+
-- Global variables:
|
|
579
|
+
-- logfile : The name of a log file to which error
|
|
580
|
+
-- messages will be written. Optional.
|
|
581
|
+
--
|
|
582
|
+
-- Tables and views created or modified:
|
|
583
|
+
-- ups_nonnull_columns : table
|
|
584
|
+
-- ups_next_column : view
|
|
585
|
+
-- ups_null_error_list : view
|
|
586
|
+
-- ups_qa_nonnull_col : view
|
|
587
|
+
-- ===============================================================
|
|
588
|
+
|
|
589
|
+
-- !x! BEGIN SCRIPT NULLQA_ONE with parameters (stage_pfx, table, error_list)
|
|
590
|
+
|
|
591
|
+
-- Write an initial header to the logfile.
|
|
592
|
+
-- !x! if(sub_defined(logfile))
|
|
593
|
+
-- !x! write "" to !!logfile!!
|
|
594
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
595
|
+
-- !x! write "!!$current_time!! -- Non-null QA checks on table !!#stage_pfx!!!!#table!!" to !!logfile!!
|
|
596
|
+
-- !x! endif
|
|
597
|
+
|
|
598
|
+
-- !x! write "Conducting non-null QA checks on table !!#stage_pfx!!!!#table!!"
|
|
599
|
+
|
|
600
|
+
-- Validate input table specifications.
|
|
601
|
+
-- !x! execute script validate_one with args (stage_pfx=!!#stage_pfx!!, table=!!#table!!, script=!!$CURRENT_SCRIPT!!, script_line=!!$SCRIPT_LINE!!)
|
|
602
|
+
|
|
603
|
+
-- Initialize the return value to empty (no foreign key errors)
|
|
604
|
+
-- !x! sub_empty !!#error_list!!
|
|
605
|
+
|
|
606
|
+
-- Create a table listing the columns of the base table that must
|
|
607
|
+
-- be non-null and that do not have a default expression.
|
|
608
|
+
-- Include a column for the number of rows with nulls in the staging table.
|
|
609
|
+
-- Include a 'processed' column for loop control.
|
|
610
|
+
-- !x! if(sub_defined(#exclude_null_checks))
|
|
611
|
+
-- !x! sub ~omitnull and column_name not in (!!#exclude_null_checks!!)
|
|
612
|
+
-- !x! else
|
|
613
|
+
-- !x! sub_empty ~omitnull
|
|
614
|
+
-- !x! endif
|
|
615
|
+
-- !x! if(table_exists(ups_nonnull_columns))
|
|
616
|
+
drop table if exists ups_nonnull_columns cascade;
|
|
617
|
+
-- !x! endif
|
|
618
|
+
create table ups_nonnull_columns
|
|
619
|
+
select
|
|
620
|
+
column_name,
|
|
621
|
+
0 as null_rows,
|
|
622
|
+
0 as processed
|
|
623
|
+
from
|
|
624
|
+
information_schema.columns
|
|
625
|
+
where
|
|
626
|
+
table_schema = '!!$DB_NAME!!'
|
|
627
|
+
and table_name = '!!#table!!'
|
|
628
|
+
and is_nullable = 'NO'
|
|
629
|
+
and column_default is null
|
|
630
|
+
!!~omitnull!!
|
|
631
|
+
;
|
|
632
|
+
|
|
633
|
+
-- Create a view to select one column to process.
|
|
634
|
+
create or replace view ups_next_column as
|
|
635
|
+
select column_name
|
|
636
|
+
from ups_nonnull_columns
|
|
637
|
+
where processed = 0
|
|
638
|
+
limit 1;
|
|
639
|
+
|
|
640
|
+
-- Process all non-nullable columns.
|
|
641
|
+
-- !x! execute script nullqa_one_innerloop with (stage_pfx=!!#stage_pfx!!, table=!!#table!!)
|
|
642
|
+
|
|
643
|
+
-- Create the return value.
|
|
644
|
+
create or replace view ups_null_error_list as
|
|
645
|
+
select
|
|
646
|
+
group_concat(concat(column_name, ' (', cast(null_rows as varchar(100)), ')') separator ', ') as null_errors
|
|
647
|
+
from
|
|
648
|
+
ups_nonnull_columns
|
|
649
|
+
where
|
|
650
|
+
coalesce(null_rows, 0) > 0;
|
|
651
|
+
-- !x! if(hasrows(ups_null_error_list))
|
|
652
|
+
-- !x! subdata !!#error_list!! ups_null_error_list
|
|
653
|
+
-- !x! endif
|
|
654
|
+
|
|
655
|
+
-- Clean up.
|
|
656
|
+
drop view if exists ups_null_error_list;
|
|
657
|
+
drop view if exists ups_next_column cascade;
|
|
658
|
+
drop table if exists ups_nonnull_columns cascade;
|
|
659
|
+
|
|
660
|
+
-- !x! END SCRIPT
|
|
661
|
+
-- End of NULLQA_ONE
|
|
662
|
+
-- ****************************************************************
|
|
663
|
+
-- ****************************************************************
|
|
664
|
+
-- Script NULLQA_ONE_INNERLOOP
|
|
665
|
+
-- ---------------------------------------------------------------
|
|
666
|
+
-- !x! BEGIN SCRIPT NULLQA_ONE_INNERLOOP with parameters (stage_pfx, table)
|
|
667
|
+
|
|
668
|
+
-- !x! if(hasrows(ups_next_column))
|
|
669
|
+
-- !x! subdata ~column_name ups_next_column
|
|
670
|
+
|
|
671
|
+
-- !x! if(sub_defined(logfile))
|
|
672
|
+
-- !x! write "Checking column !!~column_name!!." to !!logfile!!
|
|
673
|
+
-- !x! endif
|
|
674
|
+
|
|
675
|
+
create or replace view ups_qa_nonnull_col as
|
|
676
|
+
select nrows
|
|
677
|
+
from (
|
|
678
|
+
select count(*) as nrows
|
|
679
|
+
from !!#stage_pfx!!!!#table!!
|
|
680
|
+
where !!~column_name!! is null
|
|
681
|
+
) as nullcount
|
|
682
|
+
where nrows > 0
|
|
683
|
+
limit 1;
|
|
684
|
+
-- !x! if(hasrows(ups_qa_nonnull_col))
|
|
685
|
+
-- !x! subdata ~nullrows ups_qa_nonnull_col
|
|
686
|
+
-- !x! write " Column !!~column_name!! has !!~nullrows!! nulls."
|
|
687
|
+
-- !x! if(sub_defined(logfile))
|
|
688
|
+
-- !x! write " Column !!~column_name!! has !!~nullrows!! nulls." to !!logfile!!
|
|
689
|
+
-- !x! endif
|
|
690
|
+
update ups_nonnull_columns
|
|
691
|
+
set null_rows = (select nrows from ups_qa_nonnull_col limit 1)
|
|
692
|
+
where column_name = '!!~column_name!!';
|
|
693
|
+
-- !x! endif
|
|
694
|
+
|
|
695
|
+
-- Mark this constraint as processed.
|
|
696
|
+
update ups_nonnull_columns
|
|
697
|
+
set processed = 1
|
|
698
|
+
where column_name = '!!~column_name!!';
|
|
699
|
+
|
|
700
|
+
-- Loop.
|
|
701
|
+
-- !x! execute script nullqa_one_innerloop with (stage_pfx=!!#stage_pfx!!, table=!!#table!!)
|
|
702
|
+
|
|
703
|
+
-- !x! endif
|
|
704
|
+
|
|
705
|
+
-- Clean up.
|
|
706
|
+
-- !x! if(view_exists(ups_qa_nonnull_col))
|
|
707
|
+
drop view if exists ups_qa_nonnull_col;
|
|
708
|
+
-- !x! endif
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
-- !x! END SCRIPT
|
|
712
|
+
-- ################### End of NULL_QA_ONE #######################
|
|
713
|
+
-- ################################################################
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
-- ################################################################
|
|
718
|
+
-- Script PKQA_ONE
|
|
719
|
+
--
|
|
720
|
+
-- Check data in a staging table for violations of the primary key
|
|
721
|
+
-- of the corresponding base table.
|
|
722
|
+
-- Reports any PK violations found to the console and optionally
|
|
723
|
+
-- to a log file.
|
|
724
|
+
--
|
|
725
|
+
-- Input parameters:
|
|
726
|
+
-- stage_pfx : The name of the staging schema.
|
|
727
|
+
-- table : The table name--same for base and staging.
|
|
728
|
+
-- display_errors : A value of 'Yes' or 'No' to indicate whether
|
|
729
|
+
-- unrecognized values should be displayed
|
|
730
|
+
-- in a GUI.
|
|
731
|
+
-- Output parameters:
|
|
732
|
+
-- error_list : The name of the variable to receive a count
|
|
733
|
+
-- of the total number of distinct PK values
|
|
734
|
+
-- having violations, followed by a count of
|
|
735
|
+
-- the total rows associated with each.
|
|
736
|
+
--
|
|
737
|
+
-- Global variables:
|
|
738
|
+
-- logfile : The name of a log file to which update
|
|
739
|
+
-- messages will be written. Optional.
|
|
740
|
+
-- log_sql : A value of 'Yes' or 'No' to indicate whether
|
|
741
|
+
-- the SQL that is generated for each foreign
|
|
742
|
+
-- key check is written to the logfile. Optional.
|
|
743
|
+
-- log_errors : A value of 'Yes' or 'No' to indicate whether
|
|
744
|
+
-- foreign key errors are written to the logfile.
|
|
745
|
+
-- Optional.
|
|
746
|
+
--
|
|
747
|
+
-- Tables and views created or modified:
|
|
748
|
+
-- ups_primary_key_columns : table
|
|
749
|
+
-- ups_pk_check : table
|
|
750
|
+
-- ups_ercnt : view
|
|
751
|
+
-- ===============================================================
|
|
752
|
+
|
|
753
|
+
-- !x! BEGIN SCRIPT PKQA_ONE with parameters (stage_pfx, table, display_errors, error_list)
|
|
754
|
+
|
|
755
|
+
-- Write an initial header to the logfile.
|
|
756
|
+
-- !x! if(sub_defined(logfile))
|
|
757
|
+
-- !x! write "" to !!logfile!!
|
|
758
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
759
|
+
-- !x! write "!!$current_time!! -- Primary key QA checks on table !!#stage_pfx!!!!#table!!" to !!logfile!!
|
|
760
|
+
-- !x! endif
|
|
761
|
+
|
|
762
|
+
-- !x! write "Conducting primary key QA checks on table !!#stage_pfx!!!!#table!!"
|
|
763
|
+
|
|
764
|
+
-- Validate input table specifications.
|
|
765
|
+
-- !x! execute script validate_one with args (stage_pfx=!!#stage_pfx!!, table=!!#table!!, script=!!$CURRENT_SCRIPT!!, script_line=!!$SCRIPT_LINE!!)
|
|
766
|
+
|
|
767
|
+
-- Initialize the return value to False (no primary key errors)
|
|
768
|
+
-- !x! sub_empty !!#error_list!!
|
|
769
|
+
|
|
770
|
+
-- Create a table of primary key columns on this table
|
|
771
|
+
-- !x! if(table_exists(ups_primary_key_columns))
|
|
772
|
+
drop table ups_primary_key_columns cascade;
|
|
773
|
+
-- !x! endif
|
|
774
|
+
create table ups_primary_key_columns
|
|
775
|
+
select k.constraint_name, k.column_name, k.ordinal_position
|
|
776
|
+
from information_schema.table_constraints as tc
|
|
777
|
+
inner join information_schema.key_column_usage as k
|
|
778
|
+
on tc.constraint_type = 'PRIMARY KEY'
|
|
779
|
+
and tc.constraint_name = k.constraint_name
|
|
780
|
+
and tc.constraint_catalog = k.constraint_catalog
|
|
781
|
+
and tc.constraint_schema = k.constraint_schema
|
|
782
|
+
and tc.table_schema = k.table_schema
|
|
783
|
+
and tc.table_name = k.table_name
|
|
784
|
+
and tc.constraint_name = k.constraint_name
|
|
785
|
+
where
|
|
786
|
+
k.table_name = '!!#table!!'
|
|
787
|
+
and tc.constraint_schema = '!!$db_name!!'
|
|
788
|
+
order by k.ordinal_position
|
|
789
|
+
;
|
|
790
|
+
|
|
791
|
+
-- !x! if(hasrows(ups_primary_key_columns))
|
|
792
|
+
-- !x! subdata ~constraint_name ups_primary_key_columns
|
|
793
|
+
|
|
794
|
+
-- !x! if(sub_defined(logfile))
|
|
795
|
+
-- !x! write "Checking constraint !!~constraint_name!!." to !!logfile!!
|
|
796
|
+
-- !x! endif
|
|
797
|
+
|
|
798
|
+
-- Get a comma-delimited list of primary key columns to build SQL selection for duplicate keys
|
|
799
|
+
-- !x! sub_empty ~pkcollist
|
|
800
|
+
-- !x! if(view_exists(ups_pkcollist))
|
|
801
|
+
drop view if exists ups_pkcollist cascade;
|
|
802
|
+
-- !x! endif
|
|
803
|
+
create view ups_pkcollist as
|
|
804
|
+
select group_concat(column_name separator ', ') as col_list
|
|
805
|
+
from ups_primary_key_columns
|
|
806
|
+
order by ordinal_position;
|
|
807
|
+
-- !x! subdata ~pkcollist ups_pkcollist
|
|
808
|
+
|
|
809
|
+
-- Construct a query to test for duplicate values for pk columns.
|
|
810
|
+
-- !x! sub ~pk_check select !!~pkcollist!!, count(*) as row_count
|
|
811
|
+
-- !x! sub_append ~pk_check from !!#stage_pfx!!!!#table!! as s
|
|
812
|
+
-- !x! sub_append ~pk_check group by !!~pkcollist!!
|
|
813
|
+
-- !x! sub_append ~pk_check having count(*) > 1
|
|
814
|
+
|
|
815
|
+
-- Write the SQL to the log file if requested.
|
|
816
|
+
-- !x! if(sub_defined(logfile))
|
|
817
|
+
-- !x! andif(sub_defined(log_sql))
|
|
818
|
+
-- !x! andif(is_true(!!log_sql!!))
|
|
819
|
+
-- !x! write "SQL for primary key check:" to !!logfile!!
|
|
820
|
+
-- !x! write [!!~pk_check!!] to !!logfile!!
|
|
821
|
+
-- !x! endif
|
|
822
|
+
|
|
823
|
+
-- Run the check.
|
|
824
|
+
-- !x! if(table_exists(ups_pk_check))
|
|
825
|
+
drop table if exists ups_pk_check cascade;
|
|
826
|
+
-- !x! endif
|
|
827
|
+
create table ups_pk_check
|
|
828
|
+
!!~pk_check!!;
|
|
829
|
+
-- !x! if(hasrows(ups_pk_check))
|
|
830
|
+
-- !x! write " Duplicate key error on columns: !!~pkcollist!!."
|
|
831
|
+
-- !x! if(view_exists(ups_ercnt))
|
|
832
|
+
drop view if exists ups_ercnt cascade;
|
|
833
|
+
-- !x! endif
|
|
834
|
+
create view ups_ercnt
|
|
835
|
+
select count(*) as errcnt, sum(row_count) as total_rows
|
|
836
|
+
from ups_pk_check;
|
|
837
|
+
-- !x! select_sub ups_ercnt
|
|
838
|
+
-- !x! sub !!#error_list!! !!@errcnt!! duplicated key(s) (!!@total_rows!! rows)
|
|
839
|
+
-- !x! if(sub_defined(logfile))
|
|
840
|
+
-- !x! write "Duplicate primary key values in !!#table!!" to !!logfile!!
|
|
841
|
+
-- !x! if(sub_defined(log_errors))
|
|
842
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
843
|
+
-- !x! export ups_pk_check append to !!logfile!! as txt
|
|
844
|
+
-- !x! endif
|
|
845
|
+
-- !x! endif
|
|
846
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
847
|
+
-- !x! prompt message "Primary key violations in !!stage_pfx!!!!#table!!" display ups_pk_check
|
|
848
|
+
-- !x! endif
|
|
849
|
+
-- !x! endif
|
|
850
|
+
-- !x! endif
|
|
851
|
+
|
|
852
|
+
-- Clean up.
|
|
853
|
+
drop view if exists ups_pkcollist cascade;
|
|
854
|
+
drop table if exists ups_primary_key_columns cascade;
|
|
855
|
+
drop table if exists ups_pk_check cascade;
|
|
856
|
+
-- !x! if(view_exists(ups_ercnt))
|
|
857
|
+
drop view if exists ups_ercnt cascade;
|
|
858
|
+
-- !x! endif
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
-- !x! END SCRIPT
|
|
862
|
+
-- #################### End of PKQA_ONE ########################
|
|
863
|
+
-- ################################################################
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
-- ################################################################
|
|
868
|
+
-- Script FKQA_ONE
|
|
869
|
+
--
|
|
870
|
+
-- Checks foreign keys from a staging table against a base table
|
|
871
|
+
-- and, if it exists, another staging table that is an image of the
|
|
872
|
+
-- base table.
|
|
873
|
+
-- Reports any bad references found to the console and optionally
|
|
874
|
+
-- to a log file.
|
|
875
|
+
--
|
|
876
|
+
-- Input parameters:
|
|
877
|
+
-- stage_pfx : The prefix for staging table names.
|
|
878
|
+
-- table : The table name--same for base and staging.
|
|
879
|
+
-- display_errors : A value of 'Yes' or 'No' to indicate whether
|
|
880
|
+
-- unrecognized values should be displayed
|
|
881
|
+
-- in a GUI. If not defined, unrecognized
|
|
882
|
+
-- values are not displayed.
|
|
883
|
+
-- Output parameters:
|
|
884
|
+
-- error_list : The name of the variable to receive a comma-
|
|
885
|
+
-- delimited list of the names of foreign key
|
|
886
|
+
-- constraints that are not met.
|
|
887
|
+
--
|
|
888
|
+
-- Global variables:
|
|
889
|
+
-- logfile : The name of a log file to which update
|
|
890
|
+
-- messages will be written. Optional.
|
|
891
|
+
-- log_sql : A value of 'Yes' or 'No' to indicate whether
|
|
892
|
+
-- the SQL that is generated for each foreign
|
|
893
|
+
-- key check is written to the logfile. Optional.
|
|
894
|
+
-- log_errors : A value of 'Yes' or 'No' to indicate whether
|
|
895
|
+
-- foreign key errors are written to the logfile.
|
|
896
|
+
-- Optional.
|
|
897
|
+
--
|
|
898
|
+
-- Tables and views created or modified:
|
|
899
|
+
-- ups_foreign_key_columns : table
|
|
900
|
+
-- ups_sel_fks : table
|
|
901
|
+
-- ups_fk_constraints : table
|
|
902
|
+
-- ups_next_constraint : view
|
|
903
|
+
-- ups_error_list : view
|
|
904
|
+
-- ups_one_fk : table
|
|
905
|
+
-- ups_fk_joins : view
|
|
906
|
+
-- ups_fk_check : view
|
|
907
|
+
-- ups_ercnt : view
|
|
908
|
+
-- ===============================================================
|
|
909
|
+
|
|
910
|
+
-- !x! BEGIN SCRIPT FKQA_ONE with parameters (stage_pfx, table, display_errors, error_list)
|
|
911
|
+
|
|
912
|
+
-- Write an initial header to the logfile.
|
|
913
|
+
-- !x! if(sub_defined(logfile))
|
|
914
|
+
-- !x! write "" to !!logfile!!
|
|
915
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
916
|
+
-- !x! write "!!$current_time!! -- Foreign key QA checks on table !!#stage_pfx!!!!#table!!" to !!logfile!!
|
|
917
|
+
-- !x! endif
|
|
918
|
+
|
|
919
|
+
-- !x! write "Conducting foreign key QA checks on table !!#stage_pfx!!!!#table!!"
|
|
920
|
+
|
|
921
|
+
-- Validate input table specifications.
|
|
922
|
+
-- !x! execute script validate_one with args (stage_pfx=!!#stage_pfx!!, table=!!#table!!, script=!!$CURRENT_SCRIPT!!, script_line=!!$SCRIPT_LINE!!)
|
|
923
|
+
|
|
924
|
+
-- Initialize the return value to False (no foreign key errors)
|
|
925
|
+
-- !x! sub_empty !!#error_list!!
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
-- Create a table of *all* foreign key dependencies in this database.
|
|
929
|
+
-- Because this may be an expensive operation (in terms of time), the
|
|
930
|
+
-- table is not re-created if it already exists. "Already exists"
|
|
931
|
+
-- means that a table with the expected name exists. No check is
|
|
932
|
+
-- done to ensure that this table has the correct structure. The
|
|
933
|
+
-- goal is to create the table of all foreign keys only once to
|
|
934
|
+
-- minimize the time required if QA checks are to be run on multiple
|
|
935
|
+
-- staging tables.
|
|
936
|
+
-- !x! if(not table_exists(ups_foreign_key_columns))
|
|
937
|
+
create table ups_foreign_key_columns
|
|
938
|
+
select
|
|
939
|
+
rc.constraint_name,
|
|
940
|
+
cu.table_schema,
|
|
941
|
+
cu.table_name,
|
|
942
|
+
cu.column_name,
|
|
943
|
+
cu.ordinal_position,
|
|
944
|
+
cu_uq.table_schema as uq_schema,
|
|
945
|
+
cu_uq.table_name as uq_table,
|
|
946
|
+
cu_uq.column_name as uq_column,
|
|
947
|
+
cu_uq.ordinal_position as uq_position
|
|
948
|
+
from
|
|
949
|
+
(select constraint_catalog, constraint_schema, constraint_name,
|
|
950
|
+
table_name,
|
|
951
|
+
unique_constraint_catalog, unique_constraint_schema, unique_constraint_name,
|
|
952
|
+
referenced_table_name
|
|
953
|
+
from information_schema.referential_constraints
|
|
954
|
+
where constraint_schema = '!!$db_name!!'
|
|
955
|
+
) as rc
|
|
956
|
+
inner join (select * from information_schema.table_constraints
|
|
957
|
+
where constraint_type = 'FOREIGN KEY' and constraint_schema = '!!$db_name!!'
|
|
958
|
+
) as tc
|
|
959
|
+
on tc.constraint_catalog = rc.constraint_catalog
|
|
960
|
+
and tc.constraint_schema = rc.constraint_schema
|
|
961
|
+
and tc.constraint_name = rc.constraint_name
|
|
962
|
+
and tc.table_name = rc.table_name
|
|
963
|
+
inner join (select * from information_schema.table_constraints
|
|
964
|
+
where constraint_type not in ('FOREIGN KEY', 'CHECK')
|
|
965
|
+
and constraint_schema = '!!$db_name!!'
|
|
966
|
+
) as tc_uq
|
|
967
|
+
on tc_uq.constraint_catalog = rc.unique_constraint_catalog
|
|
968
|
+
and tc_uq.constraint_schema = rc.unique_constraint_schema
|
|
969
|
+
and tc_uq.constraint_name = rc.unique_constraint_name
|
|
970
|
+
and tc_uq.table_name = rc.referenced_table_name
|
|
971
|
+
inner join information_schema.key_column_usage as cu
|
|
972
|
+
on cu.constraint_catalog = tc.constraint_catalog
|
|
973
|
+
and cu.constraint_schema = tc.constraint_schema
|
|
974
|
+
and cu.constraint_name = tc.constraint_name
|
|
975
|
+
and cu.table_schema = tc.table_schema
|
|
976
|
+
and cu.table_name = tc.table_name
|
|
977
|
+
inner join information_schema.key_column_usage as cu_uq
|
|
978
|
+
on cu_uq.constraint_catalog = tc_uq.constraint_catalog
|
|
979
|
+
and cu_uq.constraint_schema = tc_uq.constraint_schema
|
|
980
|
+
and cu_uq.constraint_name = tc_uq.constraint_name
|
|
981
|
+
and cu_uq.table_schema = tc_uq.table_schema
|
|
982
|
+
and cu_uq.table_name = tc_uq.table_name
|
|
983
|
+
and cu_uq.ordinal_position = cu.ordinal_position
|
|
984
|
+
;
|
|
985
|
+
-- !x! endif
|
|
986
|
+
|
|
987
|
+
-- Create a temporary table of just the foreign key relationships for the base
|
|
988
|
+
-- table corresponding to the staging table to check.
|
|
989
|
+
-- !x! if(table_exists(ups_sel_fks))
|
|
990
|
+
drop table if exists ups_sel_fks cascade;
|
|
991
|
+
-- !x! endif
|
|
992
|
+
create table ups_sel_fks
|
|
993
|
+
select
|
|
994
|
+
constraint_name, table_schema, table_name, column_name,
|
|
995
|
+
ordinal_position,
|
|
996
|
+
uq_schema, uq_table, uq_column
|
|
997
|
+
from
|
|
998
|
+
ups_foreign_key_columns
|
|
999
|
+
where
|
|
1000
|
+
table_schema = '!!$DB_NAME!!'
|
|
1001
|
+
and table_name = '!!#table!!';
|
|
1002
|
+
|
|
1003
|
+
-- Create a table of all unique constraint names for
|
|
1004
|
+
-- this table, with an integer column to be populated with the
|
|
1005
|
+
-- number of rows failing the foreign key check, and a 'processed'
|
|
1006
|
+
-- flag to control looping.
|
|
1007
|
+
-- !x! if(table_exists(ups_fk_constraints))
|
|
1008
|
+
drop table if exists ups_fk_constraints cascade;
|
|
1009
|
+
-- !x! endif
|
|
1010
|
+
create table ups_fk_constraints
|
|
1011
|
+
select distinct
|
|
1012
|
+
constraint_name,
|
|
1013
|
+
0 as fkerror_values,
|
|
1014
|
+
0 as processed
|
|
1015
|
+
from ups_sel_fks;
|
|
1016
|
+
|
|
1017
|
+
-- Create a view to select one constraint to process.
|
|
1018
|
+
create or replace view ups_next_constraint as
|
|
1019
|
+
select constraint_name
|
|
1020
|
+
from ups_fk_constraints
|
|
1021
|
+
where processed = 0
|
|
1022
|
+
limit 1;
|
|
1023
|
+
|
|
1024
|
+
-- Process all constraints: check every foreign key.
|
|
1025
|
+
-- !x! execute script fk_qa_one_innerloop with (stage_pfx=!!#stage_pfx!!, table=!!#table!!, display_errors=!!#display_errors!!)
|
|
1026
|
+
|
|
1027
|
+
-- Create the return value.
|
|
1028
|
+
create or replace view ups_error_list as
|
|
1029
|
+
select
|
|
1030
|
+
group_concat(concat(constraint_name, ' (', fkerror_values, ')') separator ', ') as fk_errors
|
|
1031
|
+
from
|
|
1032
|
+
ups_fk_constraints
|
|
1033
|
+
where
|
|
1034
|
+
coalesce(fkerror_values, 0) > 0;
|
|
1035
|
+
-- !x! if(hasrows(ups_error_list))
|
|
1036
|
+
-- !x! subdata !!#error_list!! ups_error_list
|
|
1037
|
+
-- !x! endif
|
|
1038
|
+
|
|
1039
|
+
-- Clean up.
|
|
1040
|
+
drop view if exists ups_error_list cascade;
|
|
1041
|
+
drop view if exists ups_next_constraint cascade;
|
|
1042
|
+
drop table if exists ups_fk_constraints cascade;
|
|
1043
|
+
drop table if exists ups_sel_fks;
|
|
1044
|
+
|
|
1045
|
+
-- !x! END SCRIPT
|
|
1046
|
+
-- End of FK_QA_ONE
|
|
1047
|
+
-- ****************************************************************
|
|
1048
|
+
-- ****************************************************************
|
|
1049
|
+
-- Script FK_QA_ONE_INNERLOOP
|
|
1050
|
+
-- ----------------------------------------------------------------
|
|
1051
|
+
-- !x! BEGIN SCRIPT FK_QA_ONE_INNERLOOP with parameters (stage_pfx, table, display_errors)
|
|
1052
|
+
|
|
1053
|
+
-- !x! if(hasrows(ups_next_constraint))
|
|
1054
|
+
-- !x! subdata constraint_name ups_next_constraint
|
|
1055
|
+
|
|
1056
|
+
-- !x! if(sub_defined(logfile))
|
|
1057
|
+
-- !x! write "Checking constraint !!constraint_name!!." to !!logfile!!
|
|
1058
|
+
-- !x! endif
|
|
1059
|
+
|
|
1060
|
+
-- !x! if(table_exists(ups_one_fk))
|
|
1061
|
+
drop table if exists ups_one_fk cascade;
|
|
1062
|
+
-- !x! endif
|
|
1063
|
+
create table ups_one_fk
|
|
1064
|
+
select column_name, ordinal_position, uq_schema, uq_table, uq_column
|
|
1065
|
+
from ups_sel_fks
|
|
1066
|
+
where constraint_name = '!!constraint_name!!';
|
|
1067
|
+
|
|
1068
|
+
-- Get the unique table schema and name into data variables.
|
|
1069
|
+
-- !x! select_sub ups_one_fk
|
|
1070
|
+
|
|
1071
|
+
-- Create join expressions from staging table (s) to unique table (u)
|
|
1072
|
+
-- and to staging table equivalent to unique table (su) (though we
|
|
1073
|
+
-- don't know yet if the latter exists). Also create a 'where'
|
|
1074
|
+
-- condition to ensure that all columns being matched are non-null.
|
|
1075
|
+
-- Also create a comma-separated list of the columns being checked.
|
|
1076
|
+
create or replace view ups_fk_joins as
|
|
1077
|
+
select
|
|
1078
|
+
group_concat(concat('s.', column_name, ' = u.', uq_column) separator ' and ') as u_join,
|
|
1079
|
+
group_concat(concat('s.', column_name, ' = su.', uq_column) separator ' and ') as su_join,
|
|
1080
|
+
group_concat(concat('s.', column_name, ' is not null') separator ' and ') as s_not_null,
|
|
1081
|
+
group_concat(concat('s.', column_name) separator ', ') as s_checked
|
|
1082
|
+
from
|
|
1083
|
+
(select * from ups_one_fk order by ordinal_position) as fkcols;
|
|
1084
|
+
-- !x! select_sub ups_fk_joins
|
|
1085
|
+
|
|
1086
|
+
-- Determine whether a staging-table equivalent of the unique table exists.
|
|
1087
|
+
-- !x! sub su_exists No
|
|
1088
|
+
-- !x! if(table_exists(!!#stage_pfx!!!!@uq_table!!))
|
|
1089
|
+
-- !x! sub su_exists Yes
|
|
1090
|
+
-- !x! endif
|
|
1091
|
+
|
|
1092
|
+
-- Construct a query to test for missing unique values for fk columns.
|
|
1093
|
+
-- !x! sub ~fk_check select !!@s_checked!!, count(*) as row_count
|
|
1094
|
+
-- !x! sub_append ~fk_check from !!#stage_pfx!!!!#table!! as s
|
|
1095
|
+
-- !x! sub_append ~fk_check left join !!@uq_table!! as u on !!@u_join!!
|
|
1096
|
+
-- !x! if(is_true(!!su_exists!!))
|
|
1097
|
+
-- !x! sub_append ~fk_check left join !!#stage_pfx!!!!@uq_table!! as su on !!@su_join!!
|
|
1098
|
+
-- !x! endif
|
|
1099
|
+
-- !x! sub_append ~fk_check where u.!!@uq_column!! is null
|
|
1100
|
+
-- !x! if(is_true(!!su_exists!!))
|
|
1101
|
+
-- !x! sub_append ~fk_check and su.!!@uq_column!! is null
|
|
1102
|
+
-- !x! endif
|
|
1103
|
+
-- !x! sub_append ~fk_check and !!@s_not_null!!
|
|
1104
|
+
-- !x! sub_append ~fk_check group by !!@s_checked!!
|
|
1105
|
+
|
|
1106
|
+
-- Write the SQL to the log file if requested.
|
|
1107
|
+
-- !x! if(sub_defined(logfile))
|
|
1108
|
+
-- !x! andif(sub_defined(log_sql))
|
|
1109
|
+
-- !x! andif(is_true(!!log_sql!!))
|
|
1110
|
+
-- !x! write "SQL for foreign key check:" to !!logfile!!
|
|
1111
|
+
-- !x! write [!!~fk_check!!] to !!logfile!!
|
|
1112
|
+
-- !x! endif
|
|
1113
|
+
|
|
1114
|
+
-- Run the check.
|
|
1115
|
+
create or replace view ups_fk_check as !!~fk_check!!;
|
|
1116
|
+
-- !x! if(hasrows(ups_fk_check))
|
|
1117
|
+
-- !x! write " Foreign key error referencing !!@uq_table!!."
|
|
1118
|
+
create or replace view ups_ercnt as select count(*) from ups_fk_check;
|
|
1119
|
+
-- !x! subdata ~errcnt ups_ercnt
|
|
1120
|
+
update ups_fk_constraints
|
|
1121
|
+
set fkerror_values = !!~errcnt!!
|
|
1122
|
+
where constraint_name = '!!constraint_name!!';
|
|
1123
|
+
-- !x! if(sub_defined(logfile))
|
|
1124
|
+
-- !x! write " Foreign key errors in !!#table!! referencing !!@uq_table!!" to !!logfile!!
|
|
1125
|
+
-- !x! if(sub_defined(log_errors))
|
|
1126
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
1127
|
+
-- !x! export ups_fk_check append to !!logfile!! as txt
|
|
1128
|
+
-- !x! endif
|
|
1129
|
+
-- !x! endif
|
|
1130
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
1131
|
+
-- !x! prompt message "Foreign key errors in !!#table!! referencing !!@uq_table!!" display ups_fk_check
|
|
1132
|
+
-- !x! endif
|
|
1133
|
+
-- !x! endif
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
-- Mark this constraint as processed.
|
|
1137
|
+
update ups_fk_constraints
|
|
1138
|
+
set processed = 1
|
|
1139
|
+
where constraint_name = '!!constraint_name!!';
|
|
1140
|
+
|
|
1141
|
+
-- Loop.
|
|
1142
|
+
-- !x! execute script fk_qa_one_innerloop with (stage_pfx=!!#stage_pfx!!, table=!!#table!!, display_errors=!!#display_errors!!)
|
|
1143
|
+
|
|
1144
|
+
-- !x! endif
|
|
1145
|
+
|
|
1146
|
+
-- Clean up.
|
|
1147
|
+
-- !x! if(view_exists(ups_fk_check))
|
|
1148
|
+
drop view if exists ups_fk_check cascade;
|
|
1149
|
+
-- !x! endif
|
|
1150
|
+
-- !x! if(view_exists(ups_fk_joins))
|
|
1151
|
+
drop view if exists ups_fk_joins cascade;
|
|
1152
|
+
-- !x! endif
|
|
1153
|
+
-- !x! if(table_exists(ups_foreign_key_columns))
|
|
1154
|
+
drop table if exists ups_foreign_key_columns cascade;
|
|
1155
|
+
-- !x! endif
|
|
1156
|
+
|
|
1157
|
+
-- Clean up.
|
|
1158
|
+
-- !x! if(table_exists(ups_one_fk))
|
|
1159
|
+
drop table if exists ups_one_fk cascade;
|
|
1160
|
+
-- !x! endif
|
|
1161
|
+
|
|
1162
|
+
-- !x! END SCRIPT
|
|
1163
|
+
-- #################### End of FK_QA_ONE ########################
|
|
1164
|
+
-- ################################################################
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
-- ################################################################
|
|
1170
|
+
-- Script UPSERT_ONE
|
|
1171
|
+
--
|
|
1172
|
+
-- Adds data from a staging table to a base table, using UPDATE
|
|
1173
|
+
-- and INSERT statements. Displays data to be modified to the
|
|
1174
|
+
-- user before any modifications are done. Reports the changes
|
|
1175
|
+
-- made to the console and optionally to a log file.
|
|
1176
|
+
--
|
|
1177
|
+
-- Input parameters:
|
|
1178
|
+
-- stage_pfx : The name of the staging schema.
|
|
1179
|
+
-- table : The table name--same for base and staging.
|
|
1180
|
+
-- exclude_cols : A comma-delimited list of single-quoted
|
|
1181
|
+
-- column names identifying the columns
|
|
1182
|
+
-- of the base table that are not to be
|
|
1183
|
+
-- modified. These may be autonumber
|
|
1184
|
+
-- columns or columns filled by triggers.
|
|
1185
|
+
-- display_changes : A boolean variable indicating whether
|
|
1186
|
+
-- or not the changes to be made to the
|
|
1187
|
+
-- base table should be displayed in a GUI.
|
|
1188
|
+
-- Optional. If not defined, the changes
|
|
1189
|
+
-- will be defined.
|
|
1190
|
+
-- display_final : A boolean variable indicating whether or
|
|
1191
|
+
-- not the base table should be displayed
|
|
1192
|
+
-- after updates and inserts are completed.
|
|
1193
|
+
-- Optional. If not defined, the final
|
|
1194
|
+
-- base table will not be displayed.
|
|
1195
|
+
-- updcntvar : The name of a substitution variable that
|
|
1196
|
+
-- will be set to the number of rows updated.
|
|
1197
|
+
-- inscntvar : The name of a substitution variable that
|
|
1198
|
+
-- will be set to the number of rows inserted.
|
|
1199
|
+
--
|
|
1200
|
+
-- Global variables:
|
|
1201
|
+
-- logfile : The name of a log file to which update
|
|
1202
|
+
-- messages will be written. Optional.
|
|
1203
|
+
-- log_sql : A value of 'Yes' or 'No' indicating whether
|
|
1204
|
+
-- the update and insert statements should
|
|
1205
|
+
-- also be written to the logfile. Optional.
|
|
1206
|
+
-- log_changes : A value of 'Yes' or 'No' indicating whether
|
|
1207
|
+
-- the updated and inserted data should be
|
|
1208
|
+
-- written to the logfile. Optional.
|
|
1209
|
+
--
|
|
1210
|
+
-- Tables and views created or modified:
|
|
1211
|
+
-- ups_cols : table
|
|
1212
|
+
-- ups_pks : table
|
|
1213
|
+
-- ups_allcollist : temporary view
|
|
1214
|
+
-- ups_allbasecollist : temporary view
|
|
1215
|
+
-- ups_allstgcollist : temporary view
|
|
1216
|
+
-- ups_pkcollist : temporary view
|
|
1217
|
+
-- ups_joinexpr : temporary view
|
|
1218
|
+
-- ups_basematches : temporary view
|
|
1219
|
+
-- ups_stgmatches : temporary view
|
|
1220
|
+
-- ups_assexpr : temporary view
|
|
1221
|
+
-- ups_newrows : temporary view
|
|
1222
|
+
-- ===============================================================
|
|
1223
|
+
|
|
1224
|
+
-- !x! BEGIN SCRIPT UPSERT_ONE with parameters (stage_pfx, table, exclude_cols, display_changes, display_final, updcntvar, inscntvar)
|
|
1225
|
+
|
|
1226
|
+
-- Remove substitution variables that will contain the generated
|
|
1227
|
+
-- update and insert statements so that the existence of valid
|
|
1228
|
+
-- statements can be later tested based on the existence of these variables.
|
|
1229
|
+
-- !x! rm_sub ~updatestmt
|
|
1230
|
+
-- !x! rm_sub ~insertstmt
|
|
1231
|
+
|
|
1232
|
+
-- !x! sub ~do_updates Yes
|
|
1233
|
+
-- !x! sub ~do_inserts Yes
|
|
1234
|
+
|
|
1235
|
+
-- !x! if(sub_defined(logfile))
|
|
1236
|
+
-- !x! write "" to !!logfile!!
|
|
1237
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
1238
|
+
-- !x! write "!!$current_time!! -- Performing upsert on table !!#table!!" to !!logfile!!
|
|
1239
|
+
-- !x! endif
|
|
1240
|
+
|
|
1241
|
+
-- !x! write "Performing upsert on table !!#table!!"
|
|
1242
|
+
|
|
1243
|
+
-- Validate input table specifications.
|
|
1244
|
+
-- !x! execute script validate_one with args (stage_pfx=!!#stage_pfx!!, table=!!#table!!, script=!!$CURRENT_SCRIPT!!, script_line=!!$SCRIPT_LINE!!)
|
|
1245
|
+
|
|
1246
|
+
-- Populate a (temporary) table with the names of the columns
|
|
1247
|
+
-- in the base table that are to be updated from the staging table.
|
|
1248
|
+
-- !x! if(is_null("!!#exclude_cols!!"))
|
|
1249
|
+
-- !x! sub_empty ~col_excl
|
|
1250
|
+
-- !x! else
|
|
1251
|
+
-- !x! sub ~col_excl and column_name not in (!!#exclude_cols!!)
|
|
1252
|
+
-- !x! endif
|
|
1253
|
+
-- !x! if(table_exists(ups_cols))
|
|
1254
|
+
drop table if exists ups_cols cascade;
|
|
1255
|
+
-- !x! endif
|
|
1256
|
+
create table ups_cols
|
|
1257
|
+
select column_name
|
|
1258
|
+
from information_schema.columns
|
|
1259
|
+
where
|
|
1260
|
+
table_name = '!!#stage_pfx!!!!#table!!'
|
|
1261
|
+
and table_schema = '!!$DB_NAME!!'
|
|
1262
|
+
!!~col_excl!!
|
|
1263
|
+
order by ordinal_position;
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
-- Populate a (temporary) table with the names of the primary key
|
|
1267
|
+
-- columns of the base table.
|
|
1268
|
+
-- !x! if(table_exists(ups_pks))
|
|
1269
|
+
drop table if exists ups_pks cascade;
|
|
1270
|
+
-- !x! endif
|
|
1271
|
+
create table ups_pks
|
|
1272
|
+
select k.column_name
|
|
1273
|
+
from information_schema.table_constraints as tc
|
|
1274
|
+
inner join information_schema.key_column_usage as k
|
|
1275
|
+
on tc.constraint_type = 'PRIMARY KEY'
|
|
1276
|
+
and tc.constraint_name = k.constraint_name
|
|
1277
|
+
and tc.constraint_catalog = k.constraint_catalog
|
|
1278
|
+
and tc.constraint_schema = k.constraint_schema
|
|
1279
|
+
and tc.table_schema = k.table_schema
|
|
1280
|
+
and tc.table_name = k.table_name
|
|
1281
|
+
and tc.constraint_name = k.constraint_name
|
|
1282
|
+
where
|
|
1283
|
+
k.table_name = '!!#table!!'
|
|
1284
|
+
and k.table_schema = '!!$DB_NAME!!'
|
|
1285
|
+
order by k.ordinal_position;
|
|
1286
|
+
|
|
1287
|
+
-- Get all base table columns that are to be updated into a comma-delimited list.
|
|
1288
|
+
-- !x! if(view_exists(ups_allcollist))
|
|
1289
|
+
drop view ups_allcollist cascade;
|
|
1290
|
+
-- !x! endif
|
|
1291
|
+
create view ups_allcollist as
|
|
1292
|
+
select group_concat(column_name separator ', ')
|
|
1293
|
+
from ups_cols;
|
|
1294
|
+
-- !x! subdata ~allcollist ups_allcollist;
|
|
1295
|
+
|
|
1296
|
+
|
|
1297
|
+
-- Get all base table columns that are to be updated into a comma-delimited list
|
|
1298
|
+
-- with a "b." prefix.
|
|
1299
|
+
-- !x! if(view_exists(ups_allbasecollist))
|
|
1300
|
+
drop view ups_allbasecollist cascade;
|
|
1301
|
+
-- !x! endif
|
|
1302
|
+
create view ups_allbasecollist as
|
|
1303
|
+
select group_concat(concat('b.', column_name) separator ', ')
|
|
1304
|
+
from ups_cols;
|
|
1305
|
+
-- !x! subdata ~allbasecollist ups_allbasecollist;
|
|
1306
|
+
|
|
1307
|
+
-- Get all staging table column names for columns that are to be updated
|
|
1308
|
+
-- into a comma-delimited list with an "s." prefix.
|
|
1309
|
+
-- !x! if(view_exists(ups_allstgcollist))
|
|
1310
|
+
drop view ups_allstgcollist cascade;
|
|
1311
|
+
-- !x! endif
|
|
1312
|
+
create view ups_allstgcollist as
|
|
1313
|
+
select group_concat(concat('s.', column_name) separator ', ')
|
|
1314
|
+
from ups_cols;
|
|
1315
|
+
-- !x! subdata ~allstgcollist ups_allstgcollist;
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
-- Get the primary key columns in a comma-delimited list.
|
|
1319
|
+
-- !x! if(view_exists(ups_pkcollist))
|
|
1320
|
+
drop view ups_pkcollist cascade;
|
|
1321
|
+
-- !x! endif
|
|
1322
|
+
create view ups_pkcollist as
|
|
1323
|
+
select group_concat(column_name separator ', ')
|
|
1324
|
+
from ups_pks;
|
|
1325
|
+
-- !x! subdata ~pkcollist ups_pkcollist;
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
-- Create a join expression for key columns of the base (b) and
|
|
1329
|
+
-- staging (s) tables.
|
|
1330
|
+
-- !x! if(view_exists(ups_joinexpr))
|
|
1331
|
+
drop view ups_joinexpr cascade;
|
|
1332
|
+
-- !x! endif
|
|
1333
|
+
create view ups_joinexpr as
|
|
1334
|
+
select
|
|
1335
|
+
group_concat(concat('b.', column_name, ' = s.', column_name) separator ' and ')
|
|
1336
|
+
from
|
|
1337
|
+
ups_pks;
|
|
1338
|
+
-- !x! subdata ~joinexpr ups_joinexpr
|
|
1339
|
+
|
|
1340
|
+
|
|
1341
|
+
-- Create a FROM clause for an inner join between base and staging
|
|
1342
|
+
-- tables on the primary key column(s).
|
|
1343
|
+
-- !x! sub ~fromclause FROM !!#table!! as b INNER JOIN !!#stage_pfx!!!!#table!! as s ON !!~joinexpr!!
|
|
1344
|
+
|
|
1345
|
+
-- Create SELECT queries to pull all columns with matching keys from both
|
|
1346
|
+
-- base and staging tables.
|
|
1347
|
+
-- !x! if(view_exists(ups_basematches))
|
|
1348
|
+
drop view ups_basematches cascade;
|
|
1349
|
+
-- !x! endif
|
|
1350
|
+
create view ups_basematches as select !!~allbasecollist!! !!~fromclause!!;
|
|
1351
|
+
|
|
1352
|
+
-- !x! if(view_exists(ups_stgmatches))
|
|
1353
|
+
drop view ups_stgmatches cascade;
|
|
1354
|
+
-- !x! endif
|
|
1355
|
+
create view ups_stgmatches as select !!~allstgcollist!! !!~fromclause!!;
|
|
1356
|
+
|
|
1357
|
+
-- Get non-key columns to be updated.
|
|
1358
|
+
-- !x! if(view_exists(ups_nk))
|
|
1359
|
+
drop view if exists ups_nk cascade;
|
|
1360
|
+
-- !x! endif
|
|
1361
|
+
create view ups_nk as
|
|
1362
|
+
select cols.column_name
|
|
1363
|
+
from
|
|
1364
|
+
ups_cols as cols
|
|
1365
|
+
left join ups_pks as pks on pks.column_name = cols.column_name
|
|
1366
|
+
where
|
|
1367
|
+
pks.column_name is null;
|
|
1368
|
+
|
|
1369
|
+
-- Prompt user to examine matching data and commit, don't commit, or quit.
|
|
1370
|
+
-- !x! if(hasrows(ups_stgmatches))
|
|
1371
|
+
-- !x! andif(hasrows(ups_nk))
|
|
1372
|
+
-- !x! if(is_true(!!#display_changes!!))
|
|
1373
|
+
-- !x! prompt ask "Do you want to make these changes? For table !!#table!!, new data are shown in the top table below; existing data are in the lower table." sub ~do_updates compare ups_stgmatches and ups_basematches key (!!~pkcollist!!)
|
|
1374
|
+
-- !x! endif
|
|
1375
|
+
|
|
1376
|
+
-- !x! if(is_true(!!~do_updates!!))
|
|
1377
|
+
-- Create an assignment expression to update non-key columns of the
|
|
1378
|
+
-- base table (un-aliased) from columns of the staging table (as s).
|
|
1379
|
+
-- !x! if(view_exists(ups_assexpr))
|
|
1380
|
+
drop view ups_assexpr cascade;
|
|
1381
|
+
-- !x! endif
|
|
1382
|
+
create view ups_assexpr as
|
|
1383
|
+
select
|
|
1384
|
+
group_concat(concat('b.', column_name, ' = s.', column_name) separator ', ') as col
|
|
1385
|
+
from
|
|
1386
|
+
ups_nk;
|
|
1387
|
+
-- !x! subdata ~assexpr ups_assexpr
|
|
1388
|
+
|
|
1389
|
+
-- Create an UPDATE statement to update the base table with
|
|
1390
|
+
-- non-key columns from the staging table. No semicolon terminating generated SQL.
|
|
1391
|
+
-- !x! sub ~updatestmt UPDATE !!#table!! as b, !!#stage_pfx!!!!#table!! as s SET !!~assexpr!! WHERE !!~joinexpr!!
|
|
1392
|
+
-- !x! endif
|
|
1393
|
+
-- !x! endif
|
|
1394
|
+
|
|
1395
|
+
|
|
1396
|
+
-- Create a select statement to find all rows of the staging table
|
|
1397
|
+
-- that are not in the base table.
|
|
1398
|
+
-- !x! if(view_exists(ups_newrows))
|
|
1399
|
+
drop view ups_newrows cascade;
|
|
1400
|
+
-- !x! endif
|
|
1401
|
+
create view ups_newrows as
|
|
1402
|
+
with newpks as (
|
|
1403
|
+
select !!~pkcollist!! from !!#stage_pfx!!!!#table!!
|
|
1404
|
+
except
|
|
1405
|
+
select !!~pkcollist!! from !!#table!!
|
|
1406
|
+
)
|
|
1407
|
+
select
|
|
1408
|
+
s.*
|
|
1409
|
+
from
|
|
1410
|
+
!!#stage_pfx!!!!#table!! as s
|
|
1411
|
+
inner join newpks using (!!~pkcollist!!);
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
-- Prompt user to examine new data and continue or quit.
|
|
1415
|
+
-- !x! if(hasrows(ups_newrows))
|
|
1416
|
+
-- !x! if(is_true(!!#display_changes!!))
|
|
1417
|
+
-- !x! prompt ask "Do you want to add these new data to the !!#table!! table?" sub ~do_inserts display ups_newrows
|
|
1418
|
+
-- !x! endif
|
|
1419
|
+
|
|
1420
|
+
-- !x! if(is_true(!!~do_inserts!!))
|
|
1421
|
+
-- Create an insert statement. No semicolon terminating generated SQL.
|
|
1422
|
+
-- !x! sub ~insertstmt INSERT INTO !!#table!! (!!~allcollist!!) SELECT !!~allcollist!! FROM ups_newrows
|
|
1423
|
+
-- !x! endif
|
|
1424
|
+
-- !x! endif
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
-- Run the update and insert statements.
|
|
1428
|
+
|
|
1429
|
+
-- !x! if(sub_defined(~updatestmt))
|
|
1430
|
+
-- !x! andif(is_true(!!~do_updates!!))
|
|
1431
|
+
-- !x! write "Updating !!#table!!"
|
|
1432
|
+
-- !x! if(sub_defined(logfile))
|
|
1433
|
+
-- !x! write "" to !!logfile!!
|
|
1434
|
+
-- !x! if(sub_defined(log_sql))
|
|
1435
|
+
-- !x! andif(is_true(!!log_sql!!))
|
|
1436
|
+
-- !x! write "UPDATE statement for !!#table!!:" to !!logfile!!
|
|
1437
|
+
-- !x! write [!!~updatestmt!!] to !!logfile!!
|
|
1438
|
+
-- !x! endif
|
|
1439
|
+
-- !x! if(sub_defined(log_changes))
|
|
1440
|
+
-- !x! andif(is_true(!!log_changes!!))
|
|
1441
|
+
-- !x! write "Updates:" to !!logfile!!
|
|
1442
|
+
-- !x! export ups_stgmatches append to !!logfile!! as txt
|
|
1443
|
+
-- !x! endif
|
|
1444
|
+
-- !x! write "" to !!logfile!!
|
|
1445
|
+
-- !x! endif
|
|
1446
|
+
!!~updatestmt!!;
|
|
1447
|
+
-- !x! sub !!#updcntvar!! !!$last_rowcount!!
|
|
1448
|
+
-- !x! if(sub_defined(logfile))
|
|
1449
|
+
-- !x! write "!!$last_rowcount!! rows of !!#table!! updated." to !!logfile!!
|
|
1450
|
+
-- !x! endif
|
|
1451
|
+
-- !x! write " !!$last_rowcount!! rows updated."
|
|
1452
|
+
-- !x! endif
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
-- !x! if(sub_defined(~insertstmt))
|
|
1456
|
+
-- !x! andif(is_true(!!~do_inserts!!))
|
|
1457
|
+
-- !x! write "Adding data to !!#table!!"
|
|
1458
|
+
-- !x! if(sub_defined(logfile))
|
|
1459
|
+
-- !x! write "" to !!logfile!!
|
|
1460
|
+
-- !x! if(sub_defined(log_sql))
|
|
1461
|
+
-- !x! andif(is_true(!!log_sql!!))
|
|
1462
|
+
-- !x! write "INSERT statement for !!#table!!:" to !!logfile!!
|
|
1463
|
+
-- !x! write [!!~insertstmt!!] to !!logfile!!
|
|
1464
|
+
-- !x! endif
|
|
1465
|
+
-- !x! if(sub_defined(log_changes))
|
|
1466
|
+
-- !x! andif(is_true(!!log_changes!!))
|
|
1467
|
+
-- !x! write "New data:" to !!logfile!!
|
|
1468
|
+
-- !x! export ups_newrows append to !!logfile!! as txt
|
|
1469
|
+
-- !x! endif
|
|
1470
|
+
-- !x! write "" to !!logfile!!
|
|
1471
|
+
-- !x! endif
|
|
1472
|
+
!!~insertstmt!!;
|
|
1473
|
+
-- !x! sub !!#inscntvar!! !!$last_rowcount!!
|
|
1474
|
+
-- !x! if(sub_defined(logfile))
|
|
1475
|
+
-- !x! write "!!$last_rowcount!! rows added to !!#table!!." to !!logfile!!
|
|
1476
|
+
-- !x! endif
|
|
1477
|
+
-- !x! write " !!$last_rowcount!! rows added."
|
|
1478
|
+
-- !x! endif
|
|
1479
|
+
|
|
1480
|
+
|
|
1481
|
+
-- !x! if(is_true(!!#display_final!!))
|
|
1482
|
+
-- !x! prompt message "Table !!#table!! after updates and inserts." display !!#table!!
|
|
1483
|
+
-- !x! endif
|
|
1484
|
+
|
|
1485
|
+
-- Clean up.
|
|
1486
|
+
drop view if exists ups_newrows cascade;
|
|
1487
|
+
-- !x! if(view_exists(ups_assexpr))
|
|
1488
|
+
drop view ups_assexpr cascade;
|
|
1489
|
+
-- !x! endif
|
|
1490
|
+
drop view if exists ups_stgmatches cascade;
|
|
1491
|
+
drop view if exists ups_basematches cascade;
|
|
1492
|
+
drop view if exists ups_joinexpr cascade;
|
|
1493
|
+
drop view if exists ups_pkcollist cascade;
|
|
1494
|
+
drop view if exists ups_allstgcollist cascade;
|
|
1495
|
+
drop view if exists ups_allbasecollist cascade;
|
|
1496
|
+
drop view if exists ups_allcollist cascade;
|
|
1497
|
+
drop view if exists ups_nk cascade;
|
|
1498
|
+
drop table if exists ups_pks cascade;
|
|
1499
|
+
drop table if exists ups_cols cascade;
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
-- !x! END SCRIPT
|
|
1503
|
+
-- ################### End of UPSERT_ONE ########################
|
|
1504
|
+
-- ################################################################
|
|
1505
|
+
|
|
1506
|
+
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
-- ################################################################
|
|
1510
|
+
-- Script UPSERT_ALL
|
|
1511
|
+
--
|
|
1512
|
+
-- Updates multiple base tables with new or revised data from
|
|
1513
|
+
-- staging tables, using the UPSERT_ONE script.
|
|
1514
|
+
--
|
|
1515
|
+
-- Input parameters:
|
|
1516
|
+
-- stage_pfx : The name of the staging schema.
|
|
1517
|
+
-- control_table : The name of a table containing at least the
|
|
1518
|
+
-- following four columns:
|
|
1519
|
+
-- table_name : The name of a table
|
|
1520
|
+
-- to be updated.
|
|
1521
|
+
-- exclude_cols : A comma-delimited
|
|
1522
|
+
-- list of single-
|
|
1523
|
+
-- quoted column
|
|
1524
|
+
-- names, as required
|
|
1525
|
+
-- by UPDATE_ANY.
|
|
1526
|
+
-- display_changes : A value of "Yes" or
|
|
1527
|
+
-- "No" indicating
|
|
1528
|
+
-- whether the changes
|
|
1529
|
+
-- for the table should
|
|
1530
|
+
-- be displayed.
|
|
1531
|
+
-- display_final : A value of "Yes" or
|
|
1532
|
+
-- "No" indicating
|
|
1533
|
+
-- whether the final
|
|
1534
|
+
-- state of the table
|
|
1535
|
+
-- should be displayed.
|
|
1536
|
+
-- A table with these columns will be created
|
|
1537
|
+
-- by the script STAGED_TO_LOAD.
|
|
1538
|
+
--
|
|
1539
|
+
-- Global variables:
|
|
1540
|
+
-- logfile : The name of a log file to which update
|
|
1541
|
+
-- messages will be written. Optional.
|
|
1542
|
+
-- log_sql : A boolean variable indicating whether
|
|
1543
|
+
-- the update and insert statements should
|
|
1544
|
+
-- also be written to the logfile.
|
|
1545
|
+
--
|
|
1546
|
+
-- Tables and view used:
|
|
1547
|
+
-- ups_dependencies : table
|
|
1548
|
+
-- ups_ordered_tables : table
|
|
1549
|
+
-- ups_proctables : table
|
|
1550
|
+
-- ups_toprocess : view
|
|
1551
|
+
-- ups_upsert_rows : view
|
|
1552
|
+
-- ===============================================================
|
|
1553
|
+
|
|
1554
|
+
-- !x! BEGIN SCRIPT UPSERT_ALL with parameters (stage_pfx, control_table)
|
|
1555
|
+
|
|
1556
|
+
-- Validate contents of control table
|
|
1557
|
+
-- !x! execute script validate_control with (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!, script=!!$CURRENT_SCRIPT_NAME!!, script_line=!!$SCRIPT_LINE!!)
|
|
1558
|
+
|
|
1559
|
+
-- Initialize the status and progress bars if the console is running.
|
|
1560
|
+
-- !x! if(console_on)
|
|
1561
|
+
-- !x! reset counter 221585944
|
|
1562
|
+
-- !x! console status "Merging data"
|
|
1563
|
+
-- !x! console progress 0
|
|
1564
|
+
-- !x! if(view_exists(ups_upsert_rows))
|
|
1565
|
+
drop view if exists ups_upsert_rows;
|
|
1566
|
+
-- !x! endif
|
|
1567
|
+
create view ups_upsert_rows as
|
|
1568
|
+
select count(*) + 1 as upsert_rows
|
|
1569
|
+
from !!#control_table!!;
|
|
1570
|
+
-- !x! subdata upsert_progress_denom ups_upsert_rows
|
|
1571
|
+
-- !x! endif
|
|
1572
|
+
|
|
1573
|
+
|
|
1574
|
+
-- Get a table of all dependencies for the base schema.
|
|
1575
|
+
-- !x! if(table_exists(ups_dependencies))
|
|
1576
|
+
drop table if exists ups_dependencies cascade;
|
|
1577
|
+
-- !x! endif
|
|
1578
|
+
create table ups_dependencies
|
|
1579
|
+
select distinct
|
|
1580
|
+
tc.table_name as child,
|
|
1581
|
+
tc_uq.table_name as parent
|
|
1582
|
+
from
|
|
1583
|
+
(select distinct constraint_catalog, constraint_schema, constraint_name,
|
|
1584
|
+
table_name,
|
|
1585
|
+
unique_constraint_catalog, unique_constraint_schema, unique_constraint_name,
|
|
1586
|
+
referenced_table_name
|
|
1587
|
+
from information_schema.referential_constraints
|
|
1588
|
+
where constraint_schema = '!!$DB_NAME!!') as rc
|
|
1589
|
+
inner join (select * from information_schema.table_constraints
|
|
1590
|
+
where constraint_type = 'FOREIGN KEY') as tc
|
|
1591
|
+
on tc.constraint_catalog = rc.constraint_catalog
|
|
1592
|
+
and tc.constraint_schema = rc.constraint_schema
|
|
1593
|
+
and tc.constraint_name = rc.constraint_name
|
|
1594
|
+
and tc.table_name = rc.table_name
|
|
1595
|
+
inner join (select * from information_schema.table_constraints
|
|
1596
|
+
where constraint_type not in ('FOREIGN KEY', 'CHECK') ) as tc_uq
|
|
1597
|
+
on tc_uq.constraint_catalog = rc.unique_constraint_catalog
|
|
1598
|
+
and tc_uq.constraint_schema = rc.unique_constraint_schema
|
|
1599
|
+
and tc_uq.constraint_name = rc.unique_constraint_name
|
|
1600
|
+
and tc_uq.table_name = rc.referenced_table_name
|
|
1601
|
+
;
|
|
1602
|
+
|
|
1603
|
+
-- Create a list of tables in the base schema ordered by dependency.
|
|
1604
|
+
-- !x! if(table_exists(ups_ordered_tables))
|
|
1605
|
+
drop table if exists ups_ordered_tables cascade;
|
|
1606
|
+
-- !x! endif
|
|
1607
|
+
create table ups_ordered_tables
|
|
1608
|
+
with recursive dep_depth as (
|
|
1609
|
+
select
|
|
1610
|
+
dep.child as first_child,
|
|
1611
|
+
dep.child,
|
|
1612
|
+
dep.parent,
|
|
1613
|
+
1 as lvl
|
|
1614
|
+
from
|
|
1615
|
+
ups_dependencies as dep
|
|
1616
|
+
union all
|
|
1617
|
+
select
|
|
1618
|
+
dd.first_child,
|
|
1619
|
+
dep.child,
|
|
1620
|
+
dep.parent,
|
|
1621
|
+
dd.lvl + 1 as lvl
|
|
1622
|
+
from
|
|
1623
|
+
dep_depth as dd
|
|
1624
|
+
inner join ups_dependencies as dep on dep.parent = dd.child
|
|
1625
|
+
and dep.child <> dd.parent
|
|
1626
|
+
and not (dep.parent = dd.first_child and dd.lvl > 2)
|
|
1627
|
+
)
|
|
1628
|
+
select
|
|
1629
|
+
table_name,
|
|
1630
|
+
table_order
|
|
1631
|
+
from (
|
|
1632
|
+
-- All parents
|
|
1633
|
+
select
|
|
1634
|
+
dd.parent as table_name,
|
|
1635
|
+
max(lvl) as table_order
|
|
1636
|
+
from
|
|
1637
|
+
dep_depth as dd
|
|
1638
|
+
group by
|
|
1639
|
+
table_name
|
|
1640
|
+
union
|
|
1641
|
+
-- Children that are not parents
|
|
1642
|
+
select
|
|
1643
|
+
dd.child as table_name,
|
|
1644
|
+
max(lvl) + 1 as level
|
|
1645
|
+
from
|
|
1646
|
+
dep_depth as dd
|
|
1647
|
+
left join ups_dependencies as dp on dp.parent = dd.child
|
|
1648
|
+
where
|
|
1649
|
+
dp.parent is null
|
|
1650
|
+
group by
|
|
1651
|
+
dd.child
|
|
1652
|
+
union
|
|
1653
|
+
-- Neither parents nor children
|
|
1654
|
+
select distinct
|
|
1655
|
+
t.table_name,
|
|
1656
|
+
0 as level
|
|
1657
|
+
from
|
|
1658
|
+
information_schema.tables as t
|
|
1659
|
+
left join ups_dependencies as p on t.table_name=p.parent
|
|
1660
|
+
left join ups_dependencies as c on t.table_name=c.child
|
|
1661
|
+
where
|
|
1662
|
+
t.table_schema = '!!$DB_NAME!!'
|
|
1663
|
+
and t.table_type = 'BASE TABLE'
|
|
1664
|
+
and p.parent is null
|
|
1665
|
+
and c.child is null
|
|
1666
|
+
) as all_levels;
|
|
1667
|
+
|
|
1668
|
+
|
|
1669
|
+
-- Create a list of the selected tables with ordering information.
|
|
1670
|
+
-- !x! if(table_exists(ups_proctables))
|
|
1671
|
+
drop table if exists ups_proctables cascade;
|
|
1672
|
+
-- !x! endif
|
|
1673
|
+
create table ups_proctables
|
|
1674
|
+
select
|
|
1675
|
+
ot.table_order,
|
|
1676
|
+
tl.table_name,
|
|
1677
|
+
tl.exclude_cols,
|
|
1678
|
+
tl.display_changes,
|
|
1679
|
+
tl.display_final,
|
|
1680
|
+
tl.rows_updated,
|
|
1681
|
+
tl.rows_inserted,
|
|
1682
|
+
0 as processed
|
|
1683
|
+
from
|
|
1684
|
+
!!#control_table!! as tl
|
|
1685
|
+
inner join ups_ordered_tables as ot on ot.table_name = tl.table_name
|
|
1686
|
+
;
|
|
1687
|
+
|
|
1688
|
+
-- Create a view returning a single unprocessed table, in order.
|
|
1689
|
+
-- !x! if(view_exists(ups_toprocess))
|
|
1690
|
+
drop view if exists ups_toprocess cascade;
|
|
1691
|
+
-- !x! endif
|
|
1692
|
+
create view ups_toprocess as
|
|
1693
|
+
select
|
|
1694
|
+
table_name, exclude_cols,
|
|
1695
|
+
display_changes, display_final,
|
|
1696
|
+
rows_updated, rows_inserted
|
|
1697
|
+
from ups_proctables
|
|
1698
|
+
where processed = 0
|
|
1699
|
+
order by table_order
|
|
1700
|
+
limit 1;
|
|
1701
|
+
|
|
1702
|
+
-- Process all tables in order.
|
|
1703
|
+
-- !x! execute script upsert_all_innerloop with (stage_pfx=!!#stage_pfx!!)
|
|
1704
|
+
|
|
1705
|
+
-- Move the update/insert counts back into the control table.
|
|
1706
|
+
update !!#control_table!! as ct, ups_proctables as pt
|
|
1707
|
+
set
|
|
1708
|
+
ct.rows_updated = pt.rows_updated,
|
|
1709
|
+
ct.rows_inserted = pt.rows_inserted
|
|
1710
|
+
where
|
|
1711
|
+
pt.table_name = ct.table_name;
|
|
1712
|
+
|
|
1713
|
+
|
|
1714
|
+
-- Clean up
|
|
1715
|
+
drop table if exists ups_proctables cascade;
|
|
1716
|
+
drop view if exists ups_toprocess cascade;
|
|
1717
|
+
drop table if exists ups_ordered_tables cascade;
|
|
1718
|
+
drop table if exists ups_dependencies cascade;
|
|
1719
|
+
-- !x! if(view_exists(ups_upsert_rows))
|
|
1720
|
+
drop view if exists ups_upsert_rows;
|
|
1721
|
+
-- !x! endif
|
|
1722
|
+
|
|
1723
|
+
|
|
1724
|
+
-- Update the status bar if the console is running.
|
|
1725
|
+
-- !x! if(console_on)
|
|
1726
|
+
-- !x! console status "Data merge complete"
|
|
1727
|
+
-- !x! console progress 0
|
|
1728
|
+
-- !x! endif
|
|
1729
|
+
|
|
1730
|
+
|
|
1731
|
+
-- !x! END SCRIPT
|
|
1732
|
+
-- UPSERT_ALL
|
|
1733
|
+
-- ****************************************************************
|
|
1734
|
+
-- ****************************************************************
|
|
1735
|
+
-- Script UPSERT_ALL_INNERLOOP
|
|
1736
|
+
-- ---------------------------------------------------------------
|
|
1737
|
+
|
|
1738
|
+
-- !x! BEGIN SCRIPT UPSERT_ALL_INNERLOOP with parameters (stage_pfx)
|
|
1739
|
+
|
|
1740
|
+
-- Update the status bar if the console is running.
|
|
1741
|
+
-- !x! if(console_on)
|
|
1742
|
+
-- !x! console progress !!$counter_221585944!! / !!upsert_progress_denom!!
|
|
1743
|
+
-- !x! endif
|
|
1744
|
+
|
|
1745
|
+
-- !x! if(hasrows(ups_toprocess))
|
|
1746
|
+
-- Create variables to store the row counts from updates and inserts.
|
|
1747
|
+
-- !x! sub ~rows_updated 0
|
|
1748
|
+
-- !x! sub ~rows_inserted 0
|
|
1749
|
+
|
|
1750
|
+
-- !x! select_sub ups_toprocess
|
|
1751
|
+
-- !x! execute script upsert_one with (stage_pfx=!!#stage_pfx!!, table=!!@table_name!!, exclude_cols="!!@exclude_cols!!", display_changes=!!@display_changes!!, display_final=!!@display_final!!, updcntvar=+rows_updated, inscntvar=+rows_inserted)
|
|
1752
|
+
|
|
1753
|
+
update ups_proctables
|
|
1754
|
+
set rows_updated = !!~rows_updated!!,
|
|
1755
|
+
rows_inserted = !!~rows_inserted!!
|
|
1756
|
+
where table_name = '!!@table_name!!';
|
|
1757
|
+
|
|
1758
|
+
update ups_proctables
|
|
1759
|
+
set processed = 1
|
|
1760
|
+
where table_name = '!!@table_name!!';
|
|
1761
|
+
-- !x! execute script upsert_all_innerloop with (stage_pfx=!!#stage_pfx!!)
|
|
1762
|
+
-- !x! endif
|
|
1763
|
+
|
|
1764
|
+
-- !x! END SCRIPT
|
|
1765
|
+
-- ############### End of UPSERT_ALL_INNERLOOP ##################
|
|
1766
|
+
-- ################################################################
|
|
1767
|
+
|
|
1768
|
+
|
|
1769
|
+
|
|
1770
|
+
|
|
1771
|
+
-- ################################################################
|
|
1772
|
+
-- Script QA_ALL
|
|
1773
|
+
--
|
|
1774
|
+
-- Conducts null, primary key, and foreign key checks on multiple
|
|
1775
|
+
-- staging tables containing new or revised data for staging tables,
|
|
1776
|
+
-- using the NULLQA_ONE, PKQA_ONE, and FKQA_ONE scripts.
|
|
1777
|
+
--
|
|
1778
|
+
-- Input parameters:
|
|
1779
|
+
-- stage_pfx : The name of the staging schema.
|
|
1780
|
+
-- control_table : The name of a table containing at least the
|
|
1781
|
+
-- following four columns:
|
|
1782
|
+
-- table_name : The name of a table
|
|
1783
|
+
-- to be updated.
|
|
1784
|
+
-- null_errors : For a comma-separated
|
|
1785
|
+
-- list of columns that
|
|
1786
|
+
-- are non-nullable in
|
|
1787
|
+
-- the base table but
|
|
1788
|
+
-- null in the staging
|
|
1789
|
+
-- table.
|
|
1790
|
+
-- pk_errors : For a count of the number
|
|
1791
|
+
-- of distinct primary key
|
|
1792
|
+
-- values that are duplicated,
|
|
1793
|
+
-- followed by the total row
|
|
1794
|
+
-- count for the duplicated
|
|
1795
|
+
-- keys.
|
|
1796
|
+
-- fk_errors : For a comma-separated
|
|
1797
|
+
-- list of foreign-key
|
|
1798
|
+
-- constraint names that
|
|
1799
|
+
-- are not met by the
|
|
1800
|
+
-- staging table.
|
|
1801
|
+
-- A table with these columns will be created
|
|
1802
|
+
-- by the script STAGED_TO_LOAD.
|
|
1803
|
+
--
|
|
1804
|
+
-- Global variables:
|
|
1805
|
+
-- logfile : The name of a log file to which error
|
|
1806
|
+
-- messages will be written. Optional.
|
|
1807
|
+
-- log_sql : A value of 'Yes' or 'No' to indicate whether
|
|
1808
|
+
-- the SQL that is generated for each foreign
|
|
1809
|
+
-- key check is written to the logfile. Optional.
|
|
1810
|
+
-- log_errors : A value of 'Yes' or 'No' to indicate whether
|
|
1811
|
+
-- foreign key errors are written to the logfile.
|
|
1812
|
+
-- Optional.
|
|
1813
|
+
--
|
|
1814
|
+
-- Tables and views used:
|
|
1815
|
+
-- ups_proctables : temporary table
|
|
1816
|
+
-- ups_toprocess : temporary table
|
|
1817
|
+
-- ups_upsert_rows : temporary table
|
|
1818
|
+
--
|
|
1819
|
+
-- Counters used:
|
|
1820
|
+
-- 221585944 : Progress bar position
|
|
1821
|
+
--
|
|
1822
|
+
-- Global variables modified:
|
|
1823
|
+
-- upsert_progress_denom : Created or redefined.
|
|
1824
|
+
--
|
|
1825
|
+
-- ===============================================================
|
|
1826
|
+
|
|
1827
|
+
-- !x! BEGIN SCRIPT QA_ALL with parameters (stage_pfx, control_table)
|
|
1828
|
+
|
|
1829
|
+
-- Get denominator for progress bar if console is on.
|
|
1830
|
+
-- !x! if(console_on)
|
|
1831
|
+
-- !x! if(view_exists(ups_upsert_rows))
|
|
1832
|
+
drop view if exists ups_upsert_rows;
|
|
1833
|
+
-- !x! endif
|
|
1834
|
+
create view ups_upsert_rows as
|
|
1835
|
+
select count(*) + 1 as upsert_rows
|
|
1836
|
+
from !!#control_table!!;
|
|
1837
|
+
-- !x! subdata upsert_progress_denom ups_upsert_rows
|
|
1838
|
+
-- !x! endif
|
|
1839
|
+
|
|
1840
|
+
-- Initialize the status and progress bars if the console is running.
|
|
1841
|
+
-- !x! begin script update_console_qa with parameters (check_type)
|
|
1842
|
+
-- !x! if(console_on)
|
|
1843
|
+
-- !x! reset counter 221585944
|
|
1844
|
+
-- !x! console status "Performing !!#check_type!! QA checks"
|
|
1845
|
+
-- !x! console progress 0
|
|
1846
|
+
-- !x! endif
|
|
1847
|
+
-- !x! end script
|
|
1848
|
+
|
|
1849
|
+
-- Create a list of the selected tables with a loop control flag.
|
|
1850
|
+
-- !x! if(table_exists(ups_proctables))
|
|
1851
|
+
drop table if exists ups_proctables cascade;
|
|
1852
|
+
-- !x! endif
|
|
1853
|
+
create table ups_proctables
|
|
1854
|
+
select
|
|
1855
|
+
tl.table_name,
|
|
1856
|
+
tl.exclude_null_checks,
|
|
1857
|
+
tl.display_changes,
|
|
1858
|
+
0 as processed
|
|
1859
|
+
from
|
|
1860
|
+
!!#control_table!! as tl
|
|
1861
|
+
;
|
|
1862
|
+
|
|
1863
|
+
-- Create a view returning a single unprocessed table, in order.
|
|
1864
|
+
-- !x! if(table_exists(ups_toprocess))
|
|
1865
|
+
drop view if exists ups_toprocess;
|
|
1866
|
+
-- !x! endif
|
|
1867
|
+
create view ups_toprocess as
|
|
1868
|
+
select table_name, exclude_null_checks, display_changes
|
|
1869
|
+
from ups_proctables
|
|
1870
|
+
where processed = 0
|
|
1871
|
+
limit 1;
|
|
1872
|
+
|
|
1873
|
+
-- Perform null QA checks on all tables.
|
|
1874
|
+
-- !x! execute script update_console_qa with args (check_type=NULL)
|
|
1875
|
+
-- !x! execute script qa_all_nullloop with (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
1876
|
+
|
|
1877
|
+
-- Perform primary key QA checks on all tables.
|
|
1878
|
+
update ups_proctables set processed = 0;
|
|
1879
|
+
-- !x! execute script update_console_qa with args (check_type="primary key")
|
|
1880
|
+
-- !x! execute script qa_all_pkloop with (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
1881
|
+
|
|
1882
|
+
-- Perform foreign key QA checks on all tables.
|
|
1883
|
+
update ups_proctables set processed = 0;
|
|
1884
|
+
-- !x! execute script update_console_qa with args (check_type=foreign key)
|
|
1885
|
+
-- !x! execute script qa_all_fkloop with (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
1886
|
+
|
|
1887
|
+
|
|
1888
|
+
-- Update the status bar if the console is running.
|
|
1889
|
+
-- !x! if(console_on)
|
|
1890
|
+
-- !x! console status "Data QA checks complete"
|
|
1891
|
+
-- !x! console progress 0
|
|
1892
|
+
-- !x! endif
|
|
1893
|
+
|
|
1894
|
+
-- Clean up.
|
|
1895
|
+
drop table if exists ups_proctables cascade;
|
|
1896
|
+
drop view if exists ups_toprocess;
|
|
1897
|
+
-- !x! if(view_exists(ups_upsert_rows))
|
|
1898
|
+
drop view if exists ups_upsert_rows;
|
|
1899
|
+
-- !x! endif
|
|
1900
|
+
|
|
1901
|
+
|
|
1902
|
+
-- !x! END SCRIPT
|
|
1903
|
+
-- QA_ALL
|
|
1904
|
+
-- ****************************************************************
|
|
1905
|
+
-- ****************************************************************
|
|
1906
|
+
-- Script QA_ALL_NULLLOOP
|
|
1907
|
+
-- ---------------------------------------------------------------
|
|
1908
|
+
|
|
1909
|
+
-- !x! BEGIN SCRIPT QA_ALL_NULLLOOP with parameters (stage_pfx, control_table)
|
|
1910
|
+
|
|
1911
|
+
-- !x! sub_empty ~ups_null_error_list
|
|
1912
|
+
|
|
1913
|
+
-- Update the status bar if the console is running.
|
|
1914
|
+
-- !x! if(console_on)
|
|
1915
|
+
-- !x! console progress !!$counter_221585944!! / !!upsert_progress_denom!!
|
|
1916
|
+
-- !x! endif
|
|
1917
|
+
|
|
1918
|
+
-- !x! if(hasrows(ups_toprocess))
|
|
1919
|
+
-- !x! select_sub ups_toprocess
|
|
1920
|
+
-- !x! if(is_null("!!@exclude_null_checks!!"))
|
|
1921
|
+
-- !x! execute script nullqa_one with (stage_pfx=!!#stage_pfx!!, table=!!@table_name!!, error_list=+ups_null_error_list)
|
|
1922
|
+
-- !x! else
|
|
1923
|
+
-- !x! execute script nullqa_one with (stage_pfx=!!#stage_pfx!!, table=!!@table_name!!, error_list=+ups_null_error_list, exclude_null_checks=[!!@exclude_null_checks!!])
|
|
1924
|
+
-- !x! endif
|
|
1925
|
+
-- !x! if(not is_null("!!~ups_null_error_list!!"))
|
|
1926
|
+
update !!#control_table!!
|
|
1927
|
+
set null_errors = '!!~ups_null_error_list!!'
|
|
1928
|
+
where table_name = '!!@table_name!!';
|
|
1929
|
+
-- !x! endif
|
|
1930
|
+
|
|
1931
|
+
update ups_proctables
|
|
1932
|
+
set processed = 1
|
|
1933
|
+
where table_name = '!!@table_name!!';
|
|
1934
|
+
-- !x! execute script qa_all_nullloop with (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
1935
|
+
-- !x! endif
|
|
1936
|
+
|
|
1937
|
+
-- !x! END SCRIPT
|
|
1938
|
+
-- QA_ALL_NULLLOOP
|
|
1939
|
+
-- ****************************************************************
|
|
1940
|
+
-- ****************************************************************
|
|
1941
|
+
-- Script QA_ALL_PKLOOP
|
|
1942
|
+
-- ---------------------------------------------------------------
|
|
1943
|
+
|
|
1944
|
+
-- !x! BEGIN SCRIPT QA_ALL_PKLOOP with parameters (stage_pfx, control_table)
|
|
1945
|
+
|
|
1946
|
+
-- !x! sub_empty ~ups_pk_error_list
|
|
1947
|
+
-- Update the status bar if the console is running.
|
|
1948
|
+
-- !x! if(console_on)
|
|
1949
|
+
-- !x! console progress !!$counter_221585944!! / !!upsert_progress_denom!!
|
|
1950
|
+
-- !x! endif
|
|
1951
|
+
|
|
1952
|
+
-- !x! if(hasrows(ups_toprocess))
|
|
1953
|
+
-- !x! select_sub ups_toprocess
|
|
1954
|
+
-- !x! execute script pkqa_one with (stage_pfx=!!#stage_pfx!!, table=!!@table_name!!, display_errors=!!@display_changes!!, error_list=+ups_pk_error_list)
|
|
1955
|
+
-- !x! if(not is_null("!!~ups_pk_error_list!!"))
|
|
1956
|
+
update !!#control_table!!
|
|
1957
|
+
set pk_errors = '!!~ups_pk_error_list!!'
|
|
1958
|
+
where table_name = '!!@table_name!!';
|
|
1959
|
+
-- !x! endif
|
|
1960
|
+
|
|
1961
|
+
update ups_proctables
|
|
1962
|
+
set processed = 1
|
|
1963
|
+
where table_name = '!!@table_name!!';
|
|
1964
|
+
-- !x! execute script qa_all_pkloop with (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
1965
|
+
-- !x! endif
|
|
1966
|
+
|
|
1967
|
+
|
|
1968
|
+
-- !x! END SCRIPT
|
|
1969
|
+
-- QA_ALL_PKLOOP
|
|
1970
|
+
-- ****************************************************************
|
|
1971
|
+
-- ****************************************************************
|
|
1972
|
+
-- Script QA_ALL_FKLOOP
|
|
1973
|
+
-- ---------------------------------------------------------------
|
|
1974
|
+
|
|
1975
|
+
-- !x! BEGIN SCRIPT QA_ALL_FKLOOP with parameters (stage_pfx, control_table)
|
|
1976
|
+
|
|
1977
|
+
-- !x! sub_empty ~ups_error_list
|
|
1978
|
+
|
|
1979
|
+
-- Update the status bar if the console is running.
|
|
1980
|
+
-- !x! if(console_on)
|
|
1981
|
+
-- !x! console progress !!$counter_221585944!! / !!upsert_progress_denom!!
|
|
1982
|
+
-- !x! endif
|
|
1983
|
+
|
|
1984
|
+
-- !x! if(hasrows(ups_toprocess))
|
|
1985
|
+
-- !x! select_sub ups_toprocess
|
|
1986
|
+
-- !x! execute script fkqa_one with (stage_pfx=!!#stage_pfx!!, table=!!@table_name!!, display_errors=!!@display_changes!!, error_list=+ups_error_list)
|
|
1987
|
+
-- !x! if(not is_null("!!~ups_error_list!!"))
|
|
1988
|
+
update !!#control_table!!
|
|
1989
|
+
set fk_errors = '!!~ups_error_list!!'
|
|
1990
|
+
where table_name = '!!@table_name!!';
|
|
1991
|
+
-- !x! endif
|
|
1992
|
+
|
|
1993
|
+
update ups_proctables
|
|
1994
|
+
set processed = 1
|
|
1995
|
+
where table_name = '!!@table_name!!';
|
|
1996
|
+
-- !x! execute script qa_all_fkloop with (stage_pfx=!!#stage_pfx!!, control_table=!!#control_table!!)
|
|
1997
|
+
-- !x! endif
|
|
1998
|
+
|
|
1999
|
+
-- !x! END SCRIPT
|
|
2000
|
+
-- ##################### End of QA_ALL ###########################
|
|
2001
|
+
-- #################################################################
|
|
2002
|
+
|
|
2003
|
+
|
|
2004
|
+
|
|
2005
|
+
|
|
2006
|
+
-- ################################################################
|
|
2007
|
+
-- Script UPDTPK_ONE
|
|
2008
|
+
--
|
|
2009
|
+
-- Updates primary keys in the base table, based on new and existing
|
|
2010
|
+
-- values of PK columns in a staging table, using UPDATE
|
|
2011
|
+
-- statements. Displays data to be modified to the
|
|
2012
|
+
-- user before any modifications are done. Reports the changes
|
|
2013
|
+
-- made to the console and optionally to a log file.
|
|
2014
|
+
--
|
|
2015
|
+
-- Input parameters:
|
|
2016
|
+
-- stage_pfx : The prefix to the name of the staging table.
|
|
2017
|
+
-- table : The table name--same for base and staging,
|
|
2018
|
+
-- except for the prefix on the staging table.
|
|
2019
|
+
-- display_errors : A value of 'Yes' or 'No' to indicate whether
|
|
2020
|
+
-- any errors should be displayed in a GUI.
|
|
2021
|
+
-- display_changes : A value of 'Yes' or 'No' to indicate whether
|
|
2022
|
+
-- or not the changes to be made to the
|
|
2023
|
+
-- base table should be displayed in a GUI.
|
|
2024
|
+
--
|
|
2025
|
+
-- Global variables:
|
|
2026
|
+
-- logfile : The name of a log file to which update
|
|
2027
|
+
-- messages will be written. Optional.
|
|
2028
|
+
-- log_sql : A value of 'Yes' or 'No' indicating whether
|
|
2029
|
+
-- the update and insert statements should
|
|
2030
|
+
-- also be written to the logfile. Optional.
|
|
2031
|
+
-- log_changes : A value of 'Yes' or 'No' indicating whether
|
|
2032
|
+
-- the updated and inserted data should be
|
|
2033
|
+
-- written to the logfile. Optional.
|
|
2034
|
+
--
|
|
2035
|
+
-- Tables and views created or modified:
|
|
2036
|
+
-- ups_pkqa_errors : temporary table
|
|
2037
|
+
-- ups_pkcol_info : temporary table
|
|
2038
|
+
-- ups_pkupdates : temporary table
|
|
2039
|
+
-- ups_pkupdate_strings : temporary view
|
|
2040
|
+
-- ups_pkupdates : temporary table
|
|
2041
|
+
-- ===============================================================
|
|
2042
|
+
|
|
2043
|
+
-- !x! BEGIN SCRIPT UPDTPK_ONE with parameters (stage_pfx, table, display_errors, display_changes)
|
|
2044
|
+
|
|
2045
|
+
-- !x! if(console_on)
|
|
2046
|
+
-- !x! console status "Primary key updates"
|
|
2047
|
+
-- !x! endif
|
|
2048
|
+
|
|
2049
|
+
|
|
2050
|
+
-- Validate inputs: base/staging schemas and table
|
|
2051
|
+
-- !x! execute script validate_one with args (stage_pfx=!!#stage_pfx!!, table=!!#table!!, script=!!$CURRENT_SCRIPT!!, script_line=!!$SCRIPT_LINE!!)
|
|
2052
|
+
|
|
2053
|
+
-- Write an initial header to the logfile.
|
|
2054
|
+
-- !x! if(sub_defined(logfile))
|
|
2055
|
+
-- !x! write "" to !!logfile!!
|
|
2056
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
2057
|
+
-- !x! write "!!$current_time!! -- Performing primary key updates on table !!#table!! from !!#stage_pfx!!!!#table!!" to !!logfile!!
|
|
2058
|
+
-- !x! endif
|
|
2059
|
+
|
|
2060
|
+
-- !x! write "Performing primary key updates on table !!#table!! from !!#stage_pfx!!!!#table!!"
|
|
2061
|
+
|
|
2062
|
+
-- Create a temp table to store the results of the PK update QA checks
|
|
2063
|
+
-- !x! if(table_exists(ups_pkqa_errors))
|
|
2064
|
+
drop table if exists ups_pkqa_errors cascade;
|
|
2065
|
+
-- !x! endif
|
|
2066
|
+
create table ups_pkqa_errors (
|
|
2067
|
+
error_code varchar(40),
|
|
2068
|
+
error_description varchar(500)
|
|
2069
|
+
);
|
|
2070
|
+
|
|
2071
|
+
|
|
2072
|
+
-- Populate a (temporary) table with the names of the primary key columns of the base table.
|
|
2073
|
+
-- Get the old and new primary key columns from staging table into various formats
|
|
2074
|
+
-- to use later to construct SQL statement to select records in various ways for both updates and QA checks.
|
|
2075
|
+
-- Include column lists, join expression, and where clause
|
|
2076
|
+
-- !x! if(table_exists(ups_pkcol_info))
|
|
2077
|
+
drop table if exists ups_pkcol_info cascade;
|
|
2078
|
+
-- !x! endif
|
|
2079
|
+
create table ups_pkcol_info
|
|
2080
|
+
select
|
|
2081
|
+
k.table_schema,
|
|
2082
|
+
k.table_name,
|
|
2083
|
+
k.column_name,
|
|
2084
|
+
cast(concat('b.', column_name) as varchar(2000)) as base_aliased,
|
|
2085
|
+
cast(concat('s.', column_name) as varchar(2000)) as staging_aliased,
|
|
2086
|
+
cast(concat('s.', column_name, ' as staging_', column_name) as varchar(2000)) as staging_aliased_prefix,
|
|
2087
|
+
cast(concat('b.', column_name, ' = s.', column_name) as varchar(2000)) as join_expr,
|
|
2088
|
+
cast(concat('new_', column_name) as varchar(2000)) as newpk_col,
|
|
2089
|
+
cast(concat('s.new_', column_name) as varchar(2000)) as newpk_col_aliased,
|
|
2090
|
+
cast(concat('new_', column_name, ' is null') as varchar(2000)) as newpk_col_empty,
|
|
2091
|
+
cast(concat('new_', column_name, ' is not null') as varchar(2000)) as newpk_col_not_empty,
|
|
2092
|
+
cast(concat('b.', column_name, ' = s.new_', column_name) as varchar(2000)) as assmt_expr,
|
|
2093
|
+
cast(concat('b.', column_name, ' = s.new_', column_name) as varchar(2000)) as join_expr_oldnew,
|
|
2094
|
+
cast(concat('s.new_', column_name, ' = b.new_', column_name) as varchar(2000)) as join_expr_new,
|
|
2095
|
+
k.ordinal_position
|
|
2096
|
+
from information_schema.table_constraints as tc
|
|
2097
|
+
inner join information_schema.key_column_usage as k
|
|
2098
|
+
on tc.constraint_type = 'PRIMARY KEY'
|
|
2099
|
+
and tc.constraint_name = k.constraint_name
|
|
2100
|
+
and tc.constraint_catalog = k.constraint_catalog
|
|
2101
|
+
and tc.constraint_schema = k.constraint_schema
|
|
2102
|
+
and tc.table_schema = k.table_schema
|
|
2103
|
+
and tc.table_name = k.table_name
|
|
2104
|
+
and tc.constraint_name = k.constraint_name
|
|
2105
|
+
where
|
|
2106
|
+
k.table_name = '!!#table!!'
|
|
2107
|
+
and k.table_schema = '!!$DB_NAME!!'
|
|
2108
|
+
;
|
|
2109
|
+
|
|
2110
|
+
|
|
2111
|
+
-- Run QA checks
|
|
2112
|
+
-- !x! execute script UPDTPKQA_ONE with arguments(stage_pfx=!!#stage_pfx!!, table=!!#table!!, pkinfo_table=ups_pkcol_info, qaerror_table=ups_pkqa_errors, display_errors=!!#display_errors!!)
|
|
2113
|
+
|
|
2114
|
+
|
|
2115
|
+
-- Run the PK update ONLY if QA check script returned no errors
|
|
2116
|
+
-- !x! if(not hasrows(ups_pkqa_errors))
|
|
2117
|
+
-- !x! rm_sub ~updatestmt
|
|
2118
|
+
|
|
2119
|
+
-- !x! sub ~do_updates Yes
|
|
2120
|
+
|
|
2121
|
+
-- !x! if(sub_defined(logfile))
|
|
2122
|
+
-- !x! write "" to !!logfile!!
|
|
2123
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
2124
|
+
-- !x! write "!!$current_time!! -- Performing primary key update on table !!#table!!" to !!logfile!!
|
|
2125
|
+
-- !x! endif
|
|
2126
|
+
|
|
2127
|
+
-- !x! if(console_on)
|
|
2128
|
+
-- !x! console status "Performing PK updates"
|
|
2129
|
+
-- !x! console progress 0
|
|
2130
|
+
-- !x! endif
|
|
2131
|
+
|
|
2132
|
+
-- !x! write "Performing primary key update on table !!#table!!"
|
|
2133
|
+
|
|
2134
|
+
-- Create strings necessary to construct SQL to perform the updates
|
|
2135
|
+
-- !x! if(view_exists(ups_pkupdate_strings))
|
|
2136
|
+
drop view if exists ups_pkupdate_strings cascade;
|
|
2137
|
+
-- !x! endif
|
|
2138
|
+
create view ups_pkupdate_strings as
|
|
2139
|
+
select
|
|
2140
|
+
group_concat(base_aliased order by ordinal_position separator ', ') as oldpk_cols,
|
|
2141
|
+
group_concat(newpk_col order by ordinal_position separator ', ') as newpk_cols,
|
|
2142
|
+
group_concat(join_expr order by ordinal_position separator ' and ') as joinexpr,
|
|
2143
|
+
group_concat(newpk_col_not_empty order by ordinal_position separator ' and ') as all_newpk_col_not_empty,
|
|
2144
|
+
group_concat(assmt_expr order by ordinal_position separator ', ') as assmt_expr
|
|
2145
|
+
from ups_pkcol_info
|
|
2146
|
+
group by table_name
|
|
2147
|
+
;
|
|
2148
|
+
-- !x! select_sub ups_pkupdate_strings
|
|
2149
|
+
|
|
2150
|
+
-- Create a FROM clause for an inner join between base and staging
|
|
2151
|
+
-- tables on the primary key column(s).
|
|
2152
|
+
-- !x! sub ~fromclause FROM !!#table!! as b INNER JOIN !!#stage_pfx!!!!#table!! as s ON !!@joinexpr!!
|
|
2153
|
+
|
|
2154
|
+
-- Create a WHERE clause for the rows to include in the selection (only those having new PK columns populated in the staging table)
|
|
2155
|
+
-- !x! sub ~whereclause WHERE !!@all_newpk_col_not_empty!!
|
|
2156
|
+
|
|
2157
|
+
-- Select all matches for PK update into temp table
|
|
2158
|
+
-- !x! if(table_exists(ups_pkupdates))
|
|
2159
|
+
drop table if exists ups_pkupdates cascade;
|
|
2160
|
+
-- !x! endif
|
|
2161
|
+
create table ups_pkupdates
|
|
2162
|
+
select
|
|
2163
|
+
!!@oldpk_cols!!,
|
|
2164
|
+
!!@newpk_cols!!
|
|
2165
|
+
!!~fromclause!!
|
|
2166
|
+
!!~whereclause!!
|
|
2167
|
+
;
|
|
2168
|
+
|
|
2169
|
+
-- Prompt user to examine matching data and commit, don't commit, or quit.
|
|
2170
|
+
-- !x! if(hasrows(ups_pkupdates))
|
|
2171
|
+
-- !x! if(is_true(!!#display_changes!!))
|
|
2172
|
+
-- !x! prompt ask "Do you want to make these changes to primary key values for table !!#table!!?" sub ~do_updates display ups_pkupdates
|
|
2173
|
+
-- !x! endif
|
|
2174
|
+
-- !x! if(is_true(!!~do_updates!!))
|
|
2175
|
+
|
|
2176
|
+
-- Create an UPDATE statement to update PK columns of the base table with
|
|
2177
|
+
-- "new" PK columns from the staging table. No semicolon terminating generated SQL.
|
|
2178
|
+
-- !x! sub ~updatestmt UPDATE !!#table!! as b, !!#stage_pfx!!!!#table!! as s SET !!@assmt_expr!! WHERE !!@joinexpr!! and !!@all_newpk_col_not_empty!!
|
|
2179
|
+
|
|
2180
|
+
-- !x! write "Updating !!#table!!"
|
|
2181
|
+
-- !x! if(sub_defined(logfile))
|
|
2182
|
+
-- !x! write "" to !!logfile!!
|
|
2183
|
+
-- !x! if(sub_defined(log_sql))
|
|
2184
|
+
-- !x! andif(is_true(!!log_sql!!))
|
|
2185
|
+
-- !x! write "UPDATE statement for !!#table!!:" to !!logfile!!
|
|
2186
|
+
-- !x! write [!!~updatestmt!!] to !!logfile!!
|
|
2187
|
+
-- !x! endif
|
|
2188
|
+
-- !x! if(sub_defined(log_changes))
|
|
2189
|
+
-- !x! andif(is_true(!!log_changes!!))
|
|
2190
|
+
-- !x! write "Updates:" to !!logfile!!
|
|
2191
|
+
-- !x! export ups_pkupdates append to !!logfile!! as txt
|
|
2192
|
+
-- !x! endif
|
|
2193
|
+
-- !x! write "" to !!logfile!!
|
|
2194
|
+
-- !x! endif
|
|
2195
|
+
!!~updatestmt!!;
|
|
2196
|
+
-- !x! if(sub_defined(logfile))
|
|
2197
|
+
-- !x! write "!!$last_rowcount!! rows of !!#table!! updated." to !!logfile!!
|
|
2198
|
+
-- !x! endif
|
|
2199
|
+
-- !x! write " !!$last_rowcount!! rows updated."
|
|
2200
|
+
-- !x! endif
|
|
2201
|
+
-- !x! else
|
|
2202
|
+
--!x! write "No primary key updates specified for existing records in !!#table!!"
|
|
2203
|
+
-- !x! endif
|
|
2204
|
+
-- !x! endif
|
|
2205
|
+
|
|
2206
|
+
|
|
2207
|
+
-- !x! if(table_exists(ups_pkqa_errors))
|
|
2208
|
+
drop table if exists ups_pkqa_errors cascade;
|
|
2209
|
+
-- !x! endif
|
|
2210
|
+
-- !x! if(table_exists(ups_pkcol_info))
|
|
2211
|
+
drop table if exists ups_pkcol_info cascade;
|
|
2212
|
+
-- !x! endif
|
|
2213
|
+
-- !x! if(view_exists(ups_pkupdate_strings))
|
|
2214
|
+
drop view if exists ups_pkupdate_strings cascade;
|
|
2215
|
+
-- !x! endif
|
|
2216
|
+
-- !x! if(table_exists(ups_pkupdates))
|
|
2217
|
+
drop table if exists ups_pkupdates cascade;
|
|
2218
|
+
-- !x! endif
|
|
2219
|
+
|
|
2220
|
+
|
|
2221
|
+
-- !x! END SCRIPT
|
|
2222
|
+
-- ################### End of UPDTPK_ONE ########################
|
|
2223
|
+
-- ################################################################
|
|
2224
|
+
|
|
2225
|
+
|
|
2226
|
+
-- ################################################################
|
|
2227
|
+
-- Script UPDTPKQA_ONE
|
|
2228
|
+
--
|
|
2229
|
+
-- Performs QA checks on requested primary key updates to a table,
|
|
2230
|
+
-- based on old and new values of the table's primary key columns
|
|
2231
|
+
-- in a staging table.
|
|
2232
|
+
--
|
|
2233
|
+
-- Input parameters:
|
|
2234
|
+
-- stage_pfx : The prefix to the staging table name.
|
|
2235
|
+
-- table : The table name--same for base and staging,
|
|
2236
|
+
-- except for the prefix of the staging table.
|
|
2237
|
+
-- pkinfo_table : The name of a temporary table to be passed by
|
|
2238
|
+
-- the caller that contains information about the table PK,
|
|
2239
|
+
-- including strings to be used in constructing
|
|
2240
|
+
-- SQL for checks
|
|
2241
|
+
-- qaerror_table : The name of a temporary table to
|
|
2242
|
+
-- store any errors found by QA checks.
|
|
2243
|
+
-- display_errors : A value of 'Yes' or 'No' to indicate whether
|
|
2244
|
+
-- any errors should be displayed in a GUI.
|
|
2245
|
+
-- Output parameters:
|
|
2246
|
+
-- error_list : The name of the variable to receive FILL IN.
|
|
2247
|
+
--
|
|
2248
|
+
-- Global variables:
|
|
2249
|
+
-- logfile : The name of a log file to which update
|
|
2250
|
+
-- messages will be written. Optional.
|
|
2251
|
+
-- log_sql : A value of 'Yes' or 'No' indicating whether
|
|
2252
|
+
-- the update and insert statements should
|
|
2253
|
+
-- also be written to the logfile. Optional.
|
|
2254
|
+
-- Currently only writes SQL for foreign key checks
|
|
2255
|
+
-- (final check) to log.
|
|
2256
|
+
-- log_errors : A value of 'Yes' or 'No' to indicate whether
|
|
2257
|
+
-- errors are written to the logfile. Optional.
|
|
2258
|
+
--
|
|
2259
|
+
-- Tables and views created or modified:
|
|
2260
|
+
-- ups_missing_pk_cols : temporary table
|
|
2261
|
+
-- ups_pkqa_str_lib : tempoarary table
|
|
2262
|
+
-- ups_any_pk_cols : temporary table
|
|
2263
|
+
-- ups_empty_pk_cols : temporary table
|
|
2264
|
+
-- ups_empty_pk_cols_rwcnt : temporary view
|
|
2265
|
+
-- ups_old_pks_wc : temporary table
|
|
2266
|
+
-- ups_invalid_old_pks : temporary table
|
|
2267
|
+
-- ups_invld_pk_rwcnt : temporary view
|
|
2268
|
+
-- ups_existing_new_pks : temporary table
|
|
2269
|
+
-- ups_exst_nwpk_rwcnt : temporary view
|
|
2270
|
+
-- ups_pk_mapping_conflict : temporary table
|
|
2271
|
+
-- ups_map_conf_rwcnt : temporary view
|
|
2272
|
+
-- ups_pk_duplicate_keys : temporary table
|
|
2273
|
+
-- ups_dup_key_rwcnt : temporary view
|
|
2274
|
+
-- ups_fkcol_refs : temporary table
|
|
2275
|
+
-- ups_pkcol_deps : temporary table
|
|
2276
|
+
-- ups_pkfk_ctrl : temporary table
|
|
2277
|
+
-- ===============================================================
|
|
2278
|
+
|
|
2279
|
+
-- !x! BEGIN SCRIPT UPDTPKQA_ONE with parameters (stage_pfx, table, pkinfo_table, qaerror_table, display_errors)
|
|
2280
|
+
|
|
2281
|
+
-- Write an initial header to the logfile.
|
|
2282
|
+
-- !x! if(sub_defined(logfile))
|
|
2283
|
+
-- !x! write "" to !!logfile!!
|
|
2284
|
+
-- !x! write "==================================================================" to !!logfile!!
|
|
2285
|
+
-- !x! write "!!$current_time!! -- QA checks for primary key updates on table !!#table!!" to !!logfile!!
|
|
2286
|
+
-- !x! endif
|
|
2287
|
+
|
|
2288
|
+
-- !x! write "Conducting QA checks on table !!#stage_pfx!!!!#table!! for primary key updates to table !!#table!!"
|
|
2289
|
+
|
|
2290
|
+
-- Initialize the status and progress bars if the console is running.
|
|
2291
|
+
-- !x! if(console_on)
|
|
2292
|
+
-- !x! console status "QA checks for PK updates on !!#table!!"
|
|
2293
|
+
-- !x! endif
|
|
2294
|
+
|
|
2295
|
+
|
|
2296
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2297
|
+
-- Check 1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2298
|
+
-- No primary key constraint on base table
|
|
2299
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2300
|
+
-- !x! if(not hasrows(!!#pkinfo_table!!))
|
|
2301
|
+
|
|
2302
|
+
-- !x! sub ~error_description No primary key constraint on base table !!#table!!
|
|
2303
|
+
-- !x! write " !!~error_description!!"
|
|
2304
|
+
-- !x! if(sub_defined(logfile))
|
|
2305
|
+
-- !x! write "" to !!logfile!!
|
|
2306
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2307
|
+
-- !x! endif
|
|
2308
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2309
|
+
values ('No PK on base table', '!!~error_description!!')
|
|
2310
|
+
;
|
|
2311
|
+
|
|
2312
|
+
-- No other QA checks are conducted if this check fails:
|
|
2313
|
+
-- Remaining QA checks are conducted ONLY if base table has PK
|
|
2314
|
+
-- !x! else
|
|
2315
|
+
|
|
2316
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2317
|
+
-- Check 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2318
|
+
-- A "new" PK column exists in staging table for every PK column of base table
|
|
2319
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2320
|
+
|
|
2321
|
+
-- Find any MISSING PK columns in staging table
|
|
2322
|
+
-- !x! if(table_exists(ups_missing_pk_cols))
|
|
2323
|
+
drop table if exists ups_missing_pk_cols cascade;
|
|
2324
|
+
-- !x! endif
|
|
2325
|
+
create table ups_missing_pk_cols
|
|
2326
|
+
select
|
|
2327
|
+
group_concat(newpk_col order by ordinal_position separator ', ') as missing_newpk_cols
|
|
2328
|
+
from
|
|
2329
|
+
--Base table PK columns, with expected name in staging table ("new_" prepended to column name)
|
|
2330
|
+
!!#pkinfo_table!! as pk
|
|
2331
|
+
--Staging table columns
|
|
2332
|
+
left join
|
|
2333
|
+
(
|
|
2334
|
+
select table_name, column_name
|
|
2335
|
+
from information_schema.columns
|
|
2336
|
+
where
|
|
2337
|
+
table_schema = '!!$DB_NAME!!'
|
|
2338
|
+
and table_name = '!!#stage_pfx!!!!#table!!'
|
|
2339
|
+
) as stag on pk.newpk_col=stag.column_name
|
|
2340
|
+
where
|
|
2341
|
+
stag.column_name is null
|
|
2342
|
+
having count(*)>0
|
|
2343
|
+
;
|
|
2344
|
+
|
|
2345
|
+
-- !x! if(hasrows(ups_missing_pk_cols))
|
|
2346
|
+
|
|
2347
|
+
-- !x! subdata ~error_info ups_missing_pk_cols
|
|
2348
|
+
|
|
2349
|
+
-- !x! sub ~error_description New primary key column(s) missing from staging table: !!~error_info!!
|
|
2350
|
+
|
|
2351
|
+
-- !x! write " !!~error_description!!"
|
|
2352
|
+
-- !x! if(sub_defined(logfile))
|
|
2353
|
+
-- !x! write "" to !!logfile!!
|
|
2354
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2355
|
+
-- !x! endif
|
|
2356
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2357
|
+
values ('Missing new PK column(s)', '!!~error_description!!')
|
|
2358
|
+
;
|
|
2359
|
+
|
|
2360
|
+
-- No other QA checks are conducted if this check fails:
|
|
2361
|
+
-- Remaining QA checks are all conducted ONLY if all expected "new PK" columns exist in staging table
|
|
2362
|
+
-- !x! else
|
|
2363
|
+
|
|
2364
|
+
-- Library of aggregated strings used to construct SQL for the remaining checks
|
|
2365
|
+
|
|
2366
|
+
-- Just base table
|
|
2367
|
+
-- !x! sub ~base_table !!#table!!
|
|
2368
|
+
|
|
2369
|
+
-- Just staging table
|
|
2370
|
+
-- !x! sub ~staging_table !!#stage_pfx!!!!#table!!
|
|
2371
|
+
|
|
2372
|
+
-- !x! if(table_exists(ups_pkqa_str_lib))
|
|
2373
|
+
drop table if exists ups_pkqa_str_lib;
|
|
2374
|
+
-- !x! endif
|
|
2375
|
+
create table ups_pkqa_str_lib
|
|
2376
|
+
select
|
|
2377
|
+
group_concat(column_name order by ordinal_position separator ', ') as old_pkcol,
|
|
2378
|
+
group_concat(staging_aliased order by ordinal_position separator ', ') as old_pkcol_aliased,
|
|
2379
|
+
group_concat(staging_aliased_prefix order by ordinal_position separator ', ') as old_pkcol_aliased_prefix,
|
|
2380
|
+
group_concat(newpk_col order by ordinal_position separator ', ') as new_pkcol,
|
|
2381
|
+
group_concat(newpk_col_aliased order by ordinal_position separator ', ') as new_pkcol_aliased,
|
|
2382
|
+
group_concat(join_expr order by ordinal_position separator ' and ') as joincond_origorig,
|
|
2383
|
+
group_concat(join_expr_oldnew order by ordinal_position separator ' and ') as joincond_oldnew,
|
|
2384
|
+
group_concat(join_expr_new order by ordinal_position separator ' and ') as joincond_newnew,
|
|
2385
|
+
group_concat(newpk_col_not_empty order by ordinal_position separator ' or ') as any_newpk_col_not_empty,
|
|
2386
|
+
group_concat(newpk_col_not_empty order by ordinal_position separator ' and ') as all_newpk_col_not_empty,
|
|
2387
|
+
group_concat(newpk_col_empty order by ordinal_position separator ' or ') as any_newpk_col_empty,
|
|
2388
|
+
group_concat(newpk_col_empty order by ordinal_position separator ' and ') as all_newpk_col_empty
|
|
2389
|
+
from !!#pkinfo_table!!
|
|
2390
|
+
;
|
|
2391
|
+
-- !x! select_sub ups_pkqa_str_lib
|
|
2392
|
+
|
|
2393
|
+
|
|
2394
|
+
|
|
2395
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2396
|
+
-- Check 3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2397
|
+
-- There are any rows with PK updates specified.
|
|
2398
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2399
|
+
|
|
2400
|
+
-- Find any populated new PK columns in staging table
|
|
2401
|
+
-- !x! if(table_exists(ups_any_pk_cols))
|
|
2402
|
+
drop table if exists ups_any_pk_cols cascade;
|
|
2403
|
+
-- !x! endif
|
|
2404
|
+
create table ups_any_pk_cols
|
|
2405
|
+
select *
|
|
2406
|
+
from !!~staging_table!!
|
|
2407
|
+
where !!@any_newpk_col_not_empty!!
|
|
2408
|
+
;
|
|
2409
|
+
-- !x! if(not hasrows(ups_any_pk_cols))
|
|
2410
|
+
-- !x! sub ~error_description No primary key updates specified in !!#stage_pfx!!!!#table!!
|
|
2411
|
+
-- !x! write " !!~error_description!!"
|
|
2412
|
+
-- !x! if(sub_defined(logfile))
|
|
2413
|
+
-- !x! write "" to !!logfile!!
|
|
2414
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2415
|
+
-- !x! endif
|
|
2416
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2417
|
+
values ('No PK updates specified in staging table', '!!~error_description!!')
|
|
2418
|
+
;
|
|
2419
|
+
-- No other QA checks are conducted if this check fails
|
|
2420
|
+
-- !x! else
|
|
2421
|
+
|
|
2422
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2423
|
+
-- Check 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2424
|
+
-- Where any "new" PK column is populated in the staging table, they are all populated.
|
|
2425
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2426
|
+
|
|
2427
|
+
-- Construct SQL statement looking for any NULLs in "new" PK columns in rows where any PK columns are populated
|
|
2428
|
+
-- Find any EMPTY PK columns in staging table
|
|
2429
|
+
-- !x! if(table_exists(ups_empty_pk_cols))
|
|
2430
|
+
drop table if exists ups_empty_pk_cols cascade;
|
|
2431
|
+
-- !x! endif
|
|
2432
|
+
create table ups_empty_pk_cols
|
|
2433
|
+
select
|
|
2434
|
+
!!@old_pkcol!!,
|
|
2435
|
+
!!@new_pkcol!!
|
|
2436
|
+
from
|
|
2437
|
+
!!~staging_table!!
|
|
2438
|
+
where
|
|
2439
|
+
not (!!@all_newpk_col_empty!!)
|
|
2440
|
+
and (!!@any_newpk_col_empty!!)
|
|
2441
|
+
;
|
|
2442
|
+
|
|
2443
|
+
-- !x! if(hasrows(ups_empty_pk_cols))
|
|
2444
|
+
-- !x! if(view_exists(ups_empty_pk_cols_rwcnt))
|
|
2445
|
+
drop view if exists ups_empty_pk_cols_rwcnt cascade;
|
|
2446
|
+
-- !x! endif
|
|
2447
|
+
create view ups_empty_pk_cols_rwcnt as
|
|
2448
|
+
select count(*) as rwcnt
|
|
2449
|
+
from ups_empty_pk_cols
|
|
2450
|
+
;
|
|
2451
|
+
-- !x! subdata ~rowcount ups_empty_pk_cols_rwcnt
|
|
2452
|
+
-- !x! sub ~error_description Missing values in new PK columns in !!#stage_pfx!!!!#table!!: !!~rowcount!! row(s)
|
|
2453
|
+
-- !x! write " !!~error_description!!"
|
|
2454
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2455
|
+
values ('Incomplete mapping', '!!~error_description!!')
|
|
2456
|
+
;
|
|
2457
|
+
-- !x! if(sub_defined(logfile))
|
|
2458
|
+
-- !x! write "" to !!logfile!!
|
|
2459
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2460
|
+
-- !x! if(sub_defined(log_errors))
|
|
2461
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
2462
|
+
-- !x! export ups_empty_pk_cols append to !!logfile!! as txt
|
|
2463
|
+
-- !x! endif
|
|
2464
|
+
-- !x! endif
|
|
2465
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
2466
|
+
-- !x! prompt message "Missing values in new PK columns in !!#stage_pfx!!!!#table!!" display ups_empty_pk_cols
|
|
2467
|
+
-- !x! endif
|
|
2468
|
+
-- !x! endif
|
|
2469
|
+
|
|
2470
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2471
|
+
-- Check 5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2472
|
+
-- Where any "new" PK column is populated in the staging table, the value of the original PK for that row is valid
|
|
2473
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2474
|
+
|
|
2475
|
+
-- New PK col in staging table are not empty
|
|
2476
|
+
-- !x! if(table_exists(ups_old_pks_wc))
|
|
2477
|
+
drop table if exists ups_old_pks_wc cascade;
|
|
2478
|
+
-- !x! endif
|
|
2479
|
+
create table ups_old_pks_wc
|
|
2480
|
+
select base_aliased
|
|
2481
|
+
from !!#pkinfo_table!!
|
|
2482
|
+
order by ordinal_position
|
|
2483
|
+
limit 1;
|
|
2484
|
+
-- !x! subdata ~old_pk_firstcol ups_old_pks_wc
|
|
2485
|
+
|
|
2486
|
+
-- !x! if(table_exists(ups_invalid_old_pks))
|
|
2487
|
+
drop table if exists ups_invalid_old_pks cascade;
|
|
2488
|
+
-- !x! endif
|
|
2489
|
+
create table ups_invalid_old_pks
|
|
2490
|
+
select
|
|
2491
|
+
!!@old_pkcol_aliased!!,
|
|
2492
|
+
!!@new_pkcol!!
|
|
2493
|
+
from !!~staging_table!! as s
|
|
2494
|
+
left join !!~base_table!! as b on !!@joincond_origorig!!
|
|
2495
|
+
where !!@all_newpk_col_not_empty!! and !!~old_pk_firstcol!! is null
|
|
2496
|
+
;
|
|
2497
|
+
|
|
2498
|
+
-- !x! if(hasrows(ups_invalid_old_pks))
|
|
2499
|
+
-- !x! if(view_exists(ups_invalid_pk_rwcnt))
|
|
2500
|
+
drop view if exists ups_invld_pk_rwcnt cascade;
|
|
2501
|
+
-- !x! endif
|
|
2502
|
+
create view ups_invld_pk_rwcnt as
|
|
2503
|
+
select count(*) as rwcnt
|
|
2504
|
+
from ups_invalid_old_pks
|
|
2505
|
+
;
|
|
2506
|
+
-- !x! subdata ~rowcount ups_invld_pk_rwcnt
|
|
2507
|
+
-- !x! sub ~error_description Invalid original PK in !!#stage_pfx!!!!#table!!: !!~rowcount!! row(s)
|
|
2508
|
+
-- !x! write " !!~error_description!!"
|
|
2509
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2510
|
+
values ('Invalid old PK value', '!!~error_description!!')
|
|
2511
|
+
;
|
|
2512
|
+
-- !x! if(sub_defined(logfile))
|
|
2513
|
+
-- !x! write "" to !!logfile!!
|
|
2514
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2515
|
+
-- !x! if(sub_defined(log_errors))
|
|
2516
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
2517
|
+
-- !x! export ups_invalid_old_pks append to !!logfile!! as txt
|
|
2518
|
+
-- !x! endif
|
|
2519
|
+
-- !x! endif
|
|
2520
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
2521
|
+
-- !x! prompt message "Invalid original PK in !!#stage_pfx!!!!#table!!" display ups_invalid_old_pks
|
|
2522
|
+
-- !x! endif
|
|
2523
|
+
-- !x! endif
|
|
2524
|
+
|
|
2525
|
+
|
|
2526
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2527
|
+
-- Check 6 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2528
|
+
-- None of the "new" PK values already exist in the base table
|
|
2529
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2530
|
+
|
|
2531
|
+
-- !x! if(table_exists(ups_existing_new_pks))
|
|
2532
|
+
drop table if exists ups_existing_new_pks cascade;
|
|
2533
|
+
-- !x! endif
|
|
2534
|
+
create table ups_existing_new_pks
|
|
2535
|
+
select
|
|
2536
|
+
!!@old_pkcol_aliased_prefix!!,
|
|
2537
|
+
!!@new_pkcol!!,
|
|
2538
|
+
b.*
|
|
2539
|
+
from !!~staging_table!! as s
|
|
2540
|
+
inner join !!~base_table!! as b on !!@joincond_oldnew!!
|
|
2541
|
+
;
|
|
2542
|
+
|
|
2543
|
+
-- !x! if(hasrows(ups_existing_new_pks))
|
|
2544
|
+
-- !x! if(view_exists(ups_exst_nwpk_rwcnt))
|
|
2545
|
+
drop view if exists ups_exst_nwpk_rwcnt cascade;
|
|
2546
|
+
-- !x! endif
|
|
2547
|
+
create view ups_exst_nwpk_rwcnt as
|
|
2548
|
+
select count(*) as rwcnt
|
|
2549
|
+
from ups_existing_new_pks
|
|
2550
|
+
;
|
|
2551
|
+
-- !x! subdata ~rowcount ups_exst_nwpk_rwcnt
|
|
2552
|
+
-- !x! sub ~error_description New PK already exists in !!#table!!: !!~rowcount!! row(s)
|
|
2553
|
+
-- !x! write " !!~error_description!!"
|
|
2554
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2555
|
+
values ('Existing new PK value', '!!~error_description!!')
|
|
2556
|
+
;
|
|
2557
|
+
-- !x! if(sub_defined(logfile))
|
|
2558
|
+
-- !x! write "" to !!logfile!!
|
|
2559
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2560
|
+
-- !x! if(sub_defined(log_errors))
|
|
2561
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
2562
|
+
-- !x! export ups_existing_new_pks append to !!logfile!! as txt
|
|
2563
|
+
-- !x! endif
|
|
2564
|
+
-- !x! endif
|
|
2565
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
2566
|
+
-- !x! prompt message "New PK already exists in !!#table!!" display ups_existing_new_pks
|
|
2567
|
+
-- !x! endif
|
|
2568
|
+
-- !x! endif
|
|
2569
|
+
|
|
2570
|
+
|
|
2571
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2572
|
+
-- Check 7 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2573
|
+
-- No two (or more) original PK values map to same new PK value
|
|
2574
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2575
|
+
|
|
2576
|
+
-- !x! if(table_exists(ups_pk_mapping_conflict))
|
|
2577
|
+
drop table if exists ups_pk_mapping_conflict cascade;
|
|
2578
|
+
-- !x! endif
|
|
2579
|
+
create table ups_pk_mapping_conflict
|
|
2580
|
+
select
|
|
2581
|
+
!!@old_pkcol_aliased!!,
|
|
2582
|
+
!!@new_pkcol_aliased!!
|
|
2583
|
+
from !!~staging_table!! as s
|
|
2584
|
+
inner join
|
|
2585
|
+
(
|
|
2586
|
+
select
|
|
2587
|
+
!!@new_pkcol!!
|
|
2588
|
+
from
|
|
2589
|
+
(select distinct !!@old_pkcol!!, !!@new_pkcol!! from !!~staging_table!! where !!@all_newpk_col_not_empty!!) as a
|
|
2590
|
+
group by
|
|
2591
|
+
!!@new_pkcol!!
|
|
2592
|
+
having count(*) >1
|
|
2593
|
+
) as b on !!@joincond_newnew!!
|
|
2594
|
+
;
|
|
2595
|
+
|
|
2596
|
+
-- !x! if(hasrows(ups_pk_mapping_conflict))
|
|
2597
|
+
-- !x! if(view_exists(ups_map_conf_rwcnt))
|
|
2598
|
+
drop view if exists ups_map_conf_rwcnt cascade;
|
|
2599
|
+
-- !x! endif
|
|
2600
|
+
create view ups_map_conf_rwcnt as
|
|
2601
|
+
select count(*) as rwcnt
|
|
2602
|
+
from ups_pk_mapping_conflict
|
|
2603
|
+
;
|
|
2604
|
+
-- !x! subdata ~rowcount ups_map_conf_rwcnt
|
|
2605
|
+
-- !x! sub ~error_description Multiple original PKs mapped to same new PK in !!#stage_pfx!!!!#table!!: !!~rowcount!! row(s)
|
|
2606
|
+
-- !x! write " !!~error_description!!"
|
|
2607
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2608
|
+
values ('Mapping conflict', '!!~error_description!!')
|
|
2609
|
+
;
|
|
2610
|
+
-- !x! if(sub_defined(logfile))
|
|
2611
|
+
-- !x! write "" to !!logfile!!
|
|
2612
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2613
|
+
-- !x! if(sub_defined(log_errors))
|
|
2614
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
2615
|
+
-- !x! export ups_pk_mapping_conflict append to !!logfile!! as txt
|
|
2616
|
+
-- !x! endif
|
|
2617
|
+
-- !x! endif
|
|
2618
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
2619
|
+
-- !x! prompt message "Multiple original PKs mapped to same new PK in !!#stage_pfx!!!!#table!!" display ups_pk_mapping_conflict
|
|
2620
|
+
-- !x! endif
|
|
2621
|
+
-- !x! endif
|
|
2622
|
+
|
|
2623
|
+
|
|
2624
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2625
|
+
-- Check 8 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2626
|
+
-- No single original PK value maps to multiple new PK values
|
|
2627
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2628
|
+
|
|
2629
|
+
-- !x! if(table_exists(ups_pk_duplicate_keys))
|
|
2630
|
+
drop table if exists ups_pk_duplicate_keys cascade;
|
|
2631
|
+
-- !x! endif
|
|
2632
|
+
create table ups_pk_duplicate_keys
|
|
2633
|
+
select
|
|
2634
|
+
!!@old_pkcol_aliased!!,
|
|
2635
|
+
!!@new_pkcol_aliased!!
|
|
2636
|
+
from !!~staging_table!! as s
|
|
2637
|
+
inner join
|
|
2638
|
+
(
|
|
2639
|
+
select
|
|
2640
|
+
!!@old_pkcol!!
|
|
2641
|
+
from
|
|
2642
|
+
(select distinct !!@old_pkcol!!, !!@new_pkcol!! from !!~staging_table!! where !!@all_newpk_col_not_empty!!) as a
|
|
2643
|
+
group by
|
|
2644
|
+
!!@old_pkcol!!
|
|
2645
|
+
having count(*)>1
|
|
2646
|
+
) as b on !!@joincond_origorig!!
|
|
2647
|
+
;
|
|
2648
|
+
|
|
2649
|
+
-- !x! if(hasrows(ups_pk_duplicate_keys))
|
|
2650
|
+
-- !x! if(view_exists(ups_dup_key_rwcnt))
|
|
2651
|
+
drop view if exists ups_dup_key_rwcnt cascade;
|
|
2652
|
+
-- !x! endif
|
|
2653
|
+
create view ups_dup_key_rwcnt as
|
|
2654
|
+
select count(*) as rwcnt
|
|
2655
|
+
from ups_pk_duplicate_keys
|
|
2656
|
+
;
|
|
2657
|
+
-- !x! subdata ~rowcount ups_dup_key_rwcnt
|
|
2658
|
+
-- !x! sub ~error_description Original PK mapped to multiple new PKs in !!#stage_pfx!!!!#table!!: !!~rowcount!! row(s)
|
|
2659
|
+
-- !x! write " !!~error_description!!"
|
|
2660
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2661
|
+
values ('Duplicate keys', '!!~error_description!!')
|
|
2662
|
+
;
|
|
2663
|
+
-- !x! if(sub_defined(logfile))
|
|
2664
|
+
-- !x! write "" to !!logfile!!
|
|
2665
|
+
-- !x! write "!!~error_description!!" to !!logfile!!
|
|
2666
|
+
-- !x! if(sub_defined(log_errors))
|
|
2667
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
2668
|
+
-- !x! export ups_pk_duplicate_keys append to !!logfile!! as txt
|
|
2669
|
+
-- !x! endif
|
|
2670
|
+
-- !x! endif
|
|
2671
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
2672
|
+
-- !x! prompt message "Original PK mapped to multiple new PKs in !!#stage_pfx!!!!#table!!" display ups_pk_duplicate_keys
|
|
2673
|
+
-- !x! endif
|
|
2674
|
+
-- !x! endif
|
|
2675
|
+
|
|
2676
|
+
|
|
2677
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2678
|
+
-- Check 9 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2679
|
+
-- If any of the PK columns reference a parent table, all the "new" values of that column are valid
|
|
2680
|
+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2681
|
+
|
|
2682
|
+
-- Get ALL foreign key column references for the base table
|
|
2683
|
+
-- !x! if(table_exists(ups_fkcol_refs))
|
|
2684
|
+
drop table if exists ups_fkcol_refs cascade;
|
|
2685
|
+
-- !x! endif
|
|
2686
|
+
create table ups_fkcol_refs
|
|
2687
|
+
select
|
|
2688
|
+
rc.constraint_name as fk_constraint,
|
|
2689
|
+
cu.table_schema,
|
|
2690
|
+
cu.table_name,
|
|
2691
|
+
cu.column_name,
|
|
2692
|
+
cu.ordinal_position,
|
|
2693
|
+
cu_uq.table_schema as parent_schema,
|
|
2694
|
+
cu_uq.table_name as parent_table,
|
|
2695
|
+
cu_uq.column_name as parent_column,
|
|
2696
|
+
cu_uq.ordinal_position as parent_position
|
|
2697
|
+
from
|
|
2698
|
+
(select constraint_catalog, constraint_schema, constraint_name,
|
|
2699
|
+
table_name,
|
|
2700
|
+
unique_constraint_catalog, unique_constraint_schema, unique_constraint_name,
|
|
2701
|
+
referenced_table_name
|
|
2702
|
+
from information_schema.referential_constraints
|
|
2703
|
+
where constraint_schema = '!!$db_name!!'
|
|
2704
|
+
) as rc
|
|
2705
|
+
inner join (select * from information_schema.table_constraints
|
|
2706
|
+
where constraint_type = 'FOREIGN KEY' and constraint_schema = '!!$db_name!!'
|
|
2707
|
+
) as tc
|
|
2708
|
+
on tc.constraint_catalog = rc.constraint_catalog
|
|
2709
|
+
and tc.constraint_schema = rc.constraint_schema
|
|
2710
|
+
and tc.constraint_name = rc.constraint_name
|
|
2711
|
+
and tc.table_name = rc.table_name
|
|
2712
|
+
inner join (select * from information_schema.table_constraints
|
|
2713
|
+
where constraint_type not in ('FOREIGN KEY', 'CHECK')
|
|
2714
|
+
and constraint_schema = '!!$db_name!!'
|
|
2715
|
+
) as tc_uq
|
|
2716
|
+
on tc_uq.constraint_catalog = rc.unique_constraint_catalog
|
|
2717
|
+
and tc_uq.constraint_schema = rc.unique_constraint_schema
|
|
2718
|
+
and tc_uq.constraint_name = rc.unique_constraint_name
|
|
2719
|
+
and tc_uq.table_name = rc.referenced_table_name
|
|
2720
|
+
inner join information_schema.key_column_usage as cu
|
|
2721
|
+
on cu.constraint_catalog = tc.constraint_catalog
|
|
2722
|
+
and cu.constraint_schema = tc.constraint_schema
|
|
2723
|
+
and cu.constraint_name = tc.constraint_name
|
|
2724
|
+
and cu.table_schema = tc.table_schema
|
|
2725
|
+
and cu.table_name = tc.table_name
|
|
2726
|
+
inner join information_schema.key_column_usage as cu_uq
|
|
2727
|
+
on cu_uq.constraint_catalog = tc_uq.constraint_catalog
|
|
2728
|
+
and cu_uq.constraint_schema = tc_uq.constraint_schema
|
|
2729
|
+
and cu_uq.constraint_name = tc_uq.constraint_name
|
|
2730
|
+
and cu_uq.table_schema = tc_uq.table_schema
|
|
2731
|
+
and cu_uq.table_name = tc_uq.table_name
|
|
2732
|
+
and cu_uq.ordinal_position = cu.ordinal_position
|
|
2733
|
+
where
|
|
2734
|
+
rc.table_name = '!!#table!!'
|
|
2735
|
+
;
|
|
2736
|
+
|
|
2737
|
+
-- Narrow the list down to ONLY dependencies that affect PK columns
|
|
2738
|
+
-- Include not just the PK columns themselves, but ALL columns included in FKs
|
|
2739
|
+
-- that include ANY PK columns (probably rare/unlikely that a non-PK column would be
|
|
2740
|
+
-- part of the same foreign key as a PK column, but this ensures that ALL columns of the FK
|
|
2741
|
+
-- are included, whether or not the column is part of the PK)
|
|
2742
|
+
-- !x! if(table_exists(ups_pkcol_deps))
|
|
2743
|
+
drop table if exists ups_pkcol_deps cascade;
|
|
2744
|
+
-- !x! endif
|
|
2745
|
+
create table ups_pkcol_deps
|
|
2746
|
+
select
|
|
2747
|
+
refs.*
|
|
2748
|
+
from
|
|
2749
|
+
ups_fkcol_refs as refs
|
|
2750
|
+
inner join
|
|
2751
|
+
--Distinct list of FK constraints on the table that include ANY PK columns
|
|
2752
|
+
(
|
|
2753
|
+
select distinct
|
|
2754
|
+
fk_constraint, r.table_schema, r.table_name
|
|
2755
|
+
from
|
|
2756
|
+
ups_fkcol_refs as r
|
|
2757
|
+
inner join ups_pkcol_info as p on r.table_schema=p.table_schema and r.table_name=p.table_name and r.column_name=p.column_name
|
|
2758
|
+
) as const on refs.fk_constraint=const.fk_constraint and refs.table_schema=const.table_schema and refs.table_name=const.table_name
|
|
2759
|
+
;
|
|
2760
|
+
|
|
2761
|
+
-- Create a control table for looping to check each fk
|
|
2762
|
+
-- Include (for later use) some of the constructed strings that apply to the entire PK (not
|
|
2763
|
+
-- just the FK being checked)
|
|
2764
|
+
-- !x! if(table_exists(ups_pkfk_ctrl))
|
|
2765
|
+
drop table if exists ups_pkfk_ctrl cascade;
|
|
2766
|
+
-- !x! endif
|
|
2767
|
+
create table ups_pkfk_ctrl
|
|
2768
|
+
select
|
|
2769
|
+
fk_constraint,
|
|
2770
|
+
table_name, parent_table,
|
|
2771
|
+
min(parent_column) as any_referenced_column,
|
|
2772
|
+
'!!@old_pkcol_aliased!!' as old_pkcol_aliased,
|
|
2773
|
+
'!!@new_pkcol!!' as new_pkcol,
|
|
2774
|
+
'!!@all_newpk_col_not_empty!!' as all_newpk_col_not_empty,
|
|
2775
|
+
False as processed
|
|
2776
|
+
from ups_pkcol_deps
|
|
2777
|
+
group by
|
|
2778
|
+
fk_constraint, table_name, parent_table
|
|
2779
|
+
;
|
|
2780
|
+
|
|
2781
|
+
-- Create a view to select one constraint to process.
|
|
2782
|
+
-- !x! if(view_exists(ups_next_fk))
|
|
2783
|
+
drop view if exists ups_next_fk cascade;
|
|
2784
|
+
-- !x! endif
|
|
2785
|
+
create view ups_next_fk as
|
|
2786
|
+
select *
|
|
2787
|
+
from ups_pkfk_ctrl
|
|
2788
|
+
where not processed
|
|
2789
|
+
limit 1
|
|
2790
|
+
;
|
|
2791
|
+
|
|
2792
|
+
--Process all constraints: check every foreign key
|
|
2793
|
+
--!x! execute script updtpkqa_one_innerloop with (stage_pfx=!!#stage_pfx!!, qaerror_table=!!#qaerror_table!!, display_errors=!!#display_errors!!)
|
|
2794
|
+
-- !x! endif
|
|
2795
|
+
-- !x! endif
|
|
2796
|
+
-- !x! endif
|
|
2797
|
+
|
|
2798
|
+
-- !x! if(table_exists(ups_missing_pk_cols))
|
|
2799
|
+
drop table if exists ups_missing_pk_cols cascade;
|
|
2800
|
+
-- !x! endif
|
|
2801
|
+
-- !x! if(table_exists(ups_pkqa_str_lib))
|
|
2802
|
+
drop table if exists ups_pkqa_str_lib;
|
|
2803
|
+
-- !x! endif
|
|
2804
|
+
-- !x! if(table_exists(ups_any_pk_cols))
|
|
2805
|
+
drop table if exists ups_any_pk_cols cascade;
|
|
2806
|
+
-- !x! endif
|
|
2807
|
+
-- !x! if(table_exists(ups_empty_pk_cols))
|
|
2808
|
+
drop table if exists ups_empty_pk_cols cascade;
|
|
2809
|
+
-- !x! endif
|
|
2810
|
+
-- !x! if(view_exists(ups_empty_pk_cols_rwcnt))
|
|
2811
|
+
drop view if exists ups_empty_pk_cols_rwcnt cascade;
|
|
2812
|
+
-- !x! endif
|
|
2813
|
+
-- !x! if(table_exists(ups_old_pks_wc))
|
|
2814
|
+
drop table if exists ups_old_pks_wc cascade;
|
|
2815
|
+
-- !x! endif
|
|
2816
|
+
-- !x! if(table_exists(ups_invalid_old_pks))
|
|
2817
|
+
drop table if exists ups_invalid_old_pks cascade;
|
|
2818
|
+
-- !x! endif
|
|
2819
|
+
-- !x! if(view_exists(ups_invalid_pk_rwcnt))
|
|
2820
|
+
drop view if exists ups_invld_pk_rwcnt cascade;
|
|
2821
|
+
-- !x! endif
|
|
2822
|
+
-- !x! if(table_exists(ups_existing_new_pks))
|
|
2823
|
+
drop table if exists ups_existing_new_pks cascade;
|
|
2824
|
+
-- !x! endif
|
|
2825
|
+
-- !x! if(view_exists(ups_exst_nwpk_rwcnt))
|
|
2826
|
+
drop view if exists ups_exst_nwpk_rwcnt cascade;
|
|
2827
|
+
-- !x! endif
|
|
2828
|
+
-- !x! if(table_exists(ups_pk_mapping_conflict))
|
|
2829
|
+
drop table if exists ups_pk_mapping_conflict cascade;
|
|
2830
|
+
-- !x! endif
|
|
2831
|
+
-- !x! if(view_exists(ups_map_conf_rwcnt))
|
|
2832
|
+
drop view if exists ups_map_conf_rwcnt cascade;
|
|
2833
|
+
-- !x! endif
|
|
2834
|
+
-- !x! if(table_exists(ups_pk_duplicate_keys))
|
|
2835
|
+
drop table if exists ups_pk_duplicate_keys cascade;
|
|
2836
|
+
-- !x! endif
|
|
2837
|
+
-- !x! if(view_exists(ups_dup_key_rwcnt))
|
|
2838
|
+
drop view if exists ups_dup_key_rwcnt cascade;
|
|
2839
|
+
-- !x! endif
|
|
2840
|
+
-- !x! if(table_exists(ups_fkcol_refs))
|
|
2841
|
+
drop table if exists ups_fkcol_refs cascade;
|
|
2842
|
+
-- !x! endif
|
|
2843
|
+
-- !x! if(table_exists(ups_pkcol_deps))
|
|
2844
|
+
drop table if exists ups_pkcol_deps cascade;
|
|
2845
|
+
-- !x! endif
|
|
2846
|
+
-- !x! if(table_exists(ups_pkfk_ctrl))
|
|
2847
|
+
drop table if exists ups_pkfk_ctrl cascade;
|
|
2848
|
+
-- !x! endif
|
|
2849
|
+
-- !x! if(view_exists(ups_next_fk))
|
|
2850
|
+
drop view if exists ups_next_fk cascade;
|
|
2851
|
+
-- !x! endif
|
|
2852
|
+
|
|
2853
|
+
-- !x! END SCRIPT
|
|
2854
|
+
-- ################### UPDTPKQA_ONE ########################
|
|
2855
|
+
-- ################################################################
|
|
2856
|
+
-- Script UPDTPKQA_ONE_INNERLOOP
|
|
2857
|
+
-- ----------------------------------------------------------------
|
|
2858
|
+
-- !x! BEGIN SCRIPT UPDTPKQA_ONE_INNERLOOP with parameters(stage_pfx, qaerror_table, display_errors)
|
|
2859
|
+
-- !x! if(hasrows(ups_next_fk))
|
|
2860
|
+
|
|
2861
|
+
-- !x! select_sub ups_next_fk
|
|
2862
|
+
|
|
2863
|
+
-- Compile FK info for the selected constraint
|
|
2864
|
+
-- !x! if(table_exists(ups_sel_fk_cols))
|
|
2865
|
+
drop table if exists ups_sel_fk_cols cascade;
|
|
2866
|
+
-- !x! endif
|
|
2867
|
+
create table ups_sel_fk_cols
|
|
2868
|
+
select
|
|
2869
|
+
fk_constraint, table_name,
|
|
2870
|
+
parent_table,
|
|
2871
|
+
group_concat(parent_column order by column_name separator ', ') as referenced_cols,
|
|
2872
|
+
group_concat('s.new_' || column_name || '=' || 'b.' || parent_column order by column_name separator ' and ') as join_condition
|
|
2873
|
+
from ups_pkcol_deps
|
|
2874
|
+
where fk_constraint='!!@fk_constraint!!'
|
|
2875
|
+
group by
|
|
2876
|
+
fk_constraint, table_name,
|
|
2877
|
+
parent_table
|
|
2878
|
+
;
|
|
2879
|
+
-- !x! select_sub ups_sel_fk_cols
|
|
2880
|
+
|
|
2881
|
+
-- Construct SQL to check the selected FK
|
|
2882
|
+
-- !x! sub ~select_stmt create table ups_pk_fk_check select !!@old_pkcol_aliased!!, !!@new_pkcol!! from !!#stage_pfx!!!!@table_name!! as s
|
|
2883
|
+
-- !x! sub ~join_stmt left join !!@parent_table!! as b on !!@join_condition!!
|
|
2884
|
+
-- !x! sub ~where_clause where !!@all_newpk_col_not_empty!! and b.!!@any_referenced_column!! is null
|
|
2885
|
+
|
|
2886
|
+
-- !x! sub ~fk_check !!~select_stmt!!
|
|
2887
|
+
-- !x! sub_append ~fk_check !!~join_stmt!!
|
|
2888
|
+
-- !x! sub_append ~fk_check !!~where_clause!!
|
|
2889
|
+
|
|
2890
|
+
-- Write the SQL to the log file if requested.
|
|
2891
|
+
-- !x! if(sub_defined(logfile))
|
|
2892
|
+
-- !x! andif(sub_defined(log_sql))
|
|
2893
|
+
-- !x! andif(is_true(!!log_sql!!))
|
|
2894
|
+
-- !x! write "" to !!logfile!!
|
|
2895
|
+
-- !x! write "SQL for checking foreign key !!@fk_constraint!! for PK update to !!@table_name!!:" to !!logfile!!
|
|
2896
|
+
-- !x! write [!!~fk_check!!] to !!logfile!!
|
|
2897
|
+
-- !x! endif
|
|
2898
|
+
|
|
2899
|
+
-- Run the check
|
|
2900
|
+
-- !x! if(table_exists(ups_pk_fk_check))
|
|
2901
|
+
drop table if exists ups_pk_fk_check cascade;
|
|
2902
|
+
-- !x! endif
|
|
2903
|
+
|
|
2904
|
+
!!~fk_check!!;
|
|
2905
|
+
|
|
2906
|
+
-- !x! if(hasrows(ups_pk_fk_check))
|
|
2907
|
+
|
|
2908
|
+
-- !x! if(view_exists(ups_pk_fk_check_rwcnt))
|
|
2909
|
+
drop view if exists ups_pk_fk_check_rwcnt cascade;
|
|
2910
|
+
-- !x! endif
|
|
2911
|
+
create or replace view ups_pk_fk_check_rwcnt as
|
|
2912
|
+
select count(*) as rwcnt
|
|
2913
|
+
from ups_pk_fk_check
|
|
2914
|
+
;
|
|
2915
|
+
|
|
2916
|
+
-- !x! subdata ~rowcount ups_pk_fk_check_rwcnt
|
|
2917
|
+
-- !x! sub ~error_description !!@parent_table!! (!!@referenced_cols!!): !!~rowcount!! row(s)
|
|
2918
|
+
|
|
2919
|
+
-- !x! write " Violation of foreign key !!@fk_constraint!! in new primary key columns in !!@stag_pfx!!!!@table_name!! referencing !!@parent_table!!: !!~rowcount!! row(s)"
|
|
2920
|
+
|
|
2921
|
+
-- !x! if(view_exists(pk_fk_qa_error))
|
|
2922
|
+
drop view if exists ups_pk_fk_qa_error cascade;
|
|
2923
|
+
-- !x! endif
|
|
2924
|
+
create or replace view ups_pk_fk_qa_error as
|
|
2925
|
+
select
|
|
2926
|
+
error_code, error_description
|
|
2927
|
+
from !!#qaerror_table!!
|
|
2928
|
+
where error_code='Invalid reference to parent table(s)';
|
|
2929
|
+
-- !x! if(hasrows(ups_pk_fk_qa_error))
|
|
2930
|
+
update !!#qaerror_table!!
|
|
2931
|
+
set error_description=error_description || '; !!~error_description!!'
|
|
2932
|
+
where error_code='Invalid reference to parent table(s)';
|
|
2933
|
+
|
|
2934
|
+
-- !x! else
|
|
2935
|
+
insert into !!#qaerror_table!! (error_code, error_description)
|
|
2936
|
+
values ('Invalid reference to parent table(s)', '!!~error_description!!')
|
|
2937
|
+
;
|
|
2938
|
+
-- !x! endif
|
|
2939
|
+
|
|
2940
|
+
|
|
2941
|
+
-- !x! if(sub_defined(logfile))
|
|
2942
|
+
-- !x! write "" to !!logfile!!
|
|
2943
|
+
-- !x! write "Violation of foreign key !!@fk_constraint!! in new primary key columns in !!@stage_pfx!!!!@table_name!! referencing !!@parent_table!!: !!~rowcount!! row(s)" to !!logfile!!
|
|
2944
|
+
-- !x! if(sub_defined(log_errors))
|
|
2945
|
+
-- !x! andif(is_true(!!log_errors!!))
|
|
2946
|
+
-- !x! export ups_pk_fk_check append to !!logfile!! as txt
|
|
2947
|
+
-- !x! endif
|
|
2948
|
+
-- !x! endif
|
|
2949
|
+
-- !x! if(is_true(!!#display_errors!!))
|
|
2950
|
+
-- !x! prompt message "Violation of foreign key !!@fk_constraint!! in new primary key columns in !!@stage_pfx!!!!@table_name!! referencing !!@parent_table!!" display ups_pk_fk_check
|
|
2951
|
+
-- !x! endif
|
|
2952
|
+
|
|
2953
|
+
-- !x! endif
|
|
2954
|
+
|
|
2955
|
+
-- Mark constraint as processed
|
|
2956
|
+
update ups_pkfk_ctrl
|
|
2957
|
+
set processed=True
|
|
2958
|
+
where fk_constraint='!!@fk_constraint!!';
|
|
2959
|
+
|
|
2960
|
+
-- !x! if(table_exists(ups_sel_fk_cols))
|
|
2961
|
+
drop table if exists ups_sel_fk_cols cascade;
|
|
2962
|
+
-- !x! endif
|
|
2963
|
+
-- !x! if(table_exists(ups_pk_fk_check))
|
|
2964
|
+
drop table if exists ups_pk_fk_check cascade;
|
|
2965
|
+
-- !x! endif
|
|
2966
|
+
-- !x! if(view_exists(ups_pk_fk_check_rwcnt))
|
|
2967
|
+
drop view if exists ups_pk_fk_check_rwcnt cascade;
|
|
2968
|
+
-- !x! endif
|
|
2969
|
+
-- !x! if(view_exists(pk_fk_qa_error))
|
|
2970
|
+
drop view if exists ups_pk_fk_qa_error cascade;
|
|
2971
|
+
-- !x! endif
|
|
2972
|
+
|
|
2973
|
+
--LOOP
|
|
2974
|
+
-- !x! execute script updtpkqa_one_innerloop with (stage_pfx=!!#stage_pfx!!, qaerror_table=!!#qaerror_table!!, display_errors=!!#display_errors!!)
|
|
2975
|
+
|
|
2976
|
+
-- !x! endif
|
|
2977
|
+
|
|
2978
|
+
-- !x! END SCRIPT
|
|
2979
|
+
-- #################### End of UPDTPKQA_ONE ########################
|
|
2980
|
+
-- ################################################################
|
|
2981
|
+
|