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