compare-schema 0.1.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.
- compare_schema-0.1.1.dist-info/METADATA +206 -0
- compare_schema-0.1.1.dist-info/RECORD +24 -0
- compare_schema-0.1.1.dist-info/WHEEL +5 -0
- compare_schema-0.1.1.dist-info/entry_points.txt +2 -0
- compare_schema-0.1.1.dist-info/licenses/LICENSE +21 -0
- compare_schema-0.1.1.dist-info/top_level.txt +2 -0
- db_client/queries/schema/data.yml +142 -0
- db_client/queries/schema/schema.yml +591 -0
- db_client/queries/source/import_data.yml +6 -0
- db_client/queries/source/import_schema.yml +53 -0
- db_client/schema.sql +56 -0
- db_client/schema_client.py +15 -0
- db_client/schema_settings.py +33 -0
- db_client/source_client.py +25 -0
- db_client/source_settings.py +36 -0
- src/config.py +49 -0
- src/env_config.py +17 -0
- src/excel_helper.py +91 -0
- src/main.py +1344 -0
- src/markdown_helper.py +101 -0
- src/models.py +254 -0
- src/util_mysql.py +404 -0
- src/util_other.py +25 -0
- src/util_path.py +128 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: compare-schema
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Compare schema and data between databases
|
|
5
|
+
Author-email: Gu Park <doctorgu@kakao.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: homepage, https://github.com/doctorgu/compare_schema
|
|
8
|
+
Project-URL: repository, https://github.com/doctorgu/compare_schema
|
|
9
|
+
Project-URL: documentation, https://github.com/doctorgu/compare_schema
|
|
10
|
+
Keywords: compare schema,database comparison,schema diff,mysql,sqlite
|
|
11
|
+
Requires-Python: >=3.13
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: sqlite3-client>=1.2.0
|
|
15
|
+
Requires-Dist: mysqlclient-client>=1.2.0
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
18
|
+
Requires-Dist: xlsxwriter>=3.0
|
|
19
|
+
Requires-Dist: tabulate>=0.9
|
|
20
|
+
Requires-Dist: types-tabulate>=0.10
|
|
21
|
+
Requires-Dist: requests>=2.28
|
|
22
|
+
Requires-Dist: PyYAML>=6.0
|
|
23
|
+
Requires-Dist: SQLAlchemy>=2.0
|
|
24
|
+
Requires-Dist: PyMySQL>=1.0
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
26
|
+
Requires-Dist: ruff
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-env; extra == "test"
|
|
31
|
+
Requires-Dist: pytest-mock; extra == "test"
|
|
32
|
+
Requires-Dist: pytest-asyncio; extra == "test"
|
|
33
|
+
Requires-Dist: build; extra == "test"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# compare-schema — Database Schema and Data Comparison Tool
|
|
37
|
+
|
|
38
|
+
[English](README.md) | [한국어](README_KO.md)
|
|
39
|
+
|
|
40
|
+
A database schema and data comparison tool across different environments (e.g. dev, stg, prd).
|
|
41
|
+
|
|
42
|
+
> [!NOTE]
|
|
43
|
+
> Currently, only **MySQL** schema and data are supported. The comparison metadata and version history are stored locally in an embedded SQLite database.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- **Schema Comparison**: Compare tables, views, columns, indices, and foreign key references across databases.
|
|
48
|
+
- **Data Comparison**: Compare key-based data records across environments.
|
|
49
|
+
- **Database History Tracking**: Track changes to the same database over time by comparing versions.
|
|
50
|
+
- **Multiple Output Formats**: Export comparison reports to Markdown (`.md`) or Excel (`.xlsx`).
|
|
51
|
+
- **History & Versioning**: Tracks versions in SQLite to detect schema drift over time.
|
|
52
|
+
- **Notifications**: Discord webhook notification support for schema and data changes.
|
|
53
|
+
- **CLI & Module Support**: Run via `compare-schema` CLI command or `python -m src.main`.
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install compare-schema
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### 1. Configuration (`config/config.yaml`)
|
|
64
|
+
|
|
65
|
+
Create a configuration YAML file:
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
output_type: md # md or xlsx
|
|
69
|
+
output_dir: ./compare_schema/result
|
|
70
|
+
prev_version: ""
|
|
71
|
+
|
|
72
|
+
data_tables:
|
|
73
|
+
- table: users
|
|
74
|
+
columns:
|
|
75
|
+
- name
|
|
76
|
+
- email
|
|
77
|
+
- nick_name
|
|
78
|
+
key_columns:
|
|
79
|
+
- id
|
|
80
|
+
|
|
81
|
+
exclude_tables: []
|
|
82
|
+
exclude_columns: []
|
|
83
|
+
db_host: 127.0.0.1
|
|
84
|
+
envs:
|
|
85
|
+
- name: dev
|
|
86
|
+
port: 3306
|
|
87
|
+
db_names: [shop, logs]
|
|
88
|
+
- name: stg
|
|
89
|
+
port: 3306
|
|
90
|
+
db_names: [shop]
|
|
91
|
+
- name: prd
|
|
92
|
+
port: 3306
|
|
93
|
+
db_names: [shop]
|
|
94
|
+
|
|
95
|
+
compare_list:
|
|
96
|
+
# Compare between different databases or environments
|
|
97
|
+
- a: dev.shop
|
|
98
|
+
b: dev.logs
|
|
99
|
+
- a: dev.shop
|
|
100
|
+
b: stg.shop
|
|
101
|
+
- a: stg.shop
|
|
102
|
+
b: prd.shop
|
|
103
|
+
# If a and b is same, compares between recent version and new version (shows history of that DB)
|
|
104
|
+
- a: dev.shop
|
|
105
|
+
b: dev.shop
|
|
106
|
+
- a: stg.shop
|
|
107
|
+
b: stg.shop
|
|
108
|
+
- a: prd.shop
|
|
109
|
+
b: prd.shop
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 2. Version Comparison & History
|
|
113
|
+
|
|
114
|
+
The tool supports two comparison modes based on the entries defined in `compare_list` (`{env}.{database}`):
|
|
115
|
+
|
|
116
|
+
#### A. Cross-Database Comparison (`a != b`)
|
|
117
|
+
|
|
118
|
+
Compares schemas and data between two distinct environments or databases (e.g., `dev.shop` vs `stg.shop`):
|
|
119
|
+
|
|
120
|
+
- **Schema Differences**:
|
|
121
|
+
- `schema_not_exists`: Identifies missing tables, views, columns, indices, and foreign keys present in one database but absent in the other.
|
|
122
|
+
- `schema_diff`: Identifies structural discrepancies in matching objects:
|
|
123
|
+
- **Columns**: Data types, nullability (`is_nullable`), default values, character length, numeric precision/scale, and column comments.
|
|
124
|
+
- **Indices**: Index types (BTREE, etc.), uniqueness (`is_unique`), and indexed column combinations.
|
|
125
|
+
- **Foreign Keys**: Target referenced tables and columns.
|
|
126
|
+
- **Data Differences**:
|
|
127
|
+
- Compares rows in tables specified in `data_tables`.
|
|
128
|
+
- Matches rows between databases using the primary/unique keys configured in `key_columns`.
|
|
129
|
+
- `data_not_exists`: Rows present in one database but missing in the other.
|
|
130
|
+
- `data_diff`: Rows that exist in both databases but have differing values in the monitored `columns`.
|
|
131
|
+
- **Output**: Exported to `{version}_compare.md` (Markdown) or the `compare` sheets in Excel.
|
|
132
|
+
|
|
133
|
+
#### B. Database History & Drift Tracking (`a == b`)
|
|
134
|
+
|
|
135
|
+
When `a` and `b` reference the same database (e.g., `a: dev.shop, b: dev.shop`), the tool compares the new `version` (timestamped as `YYYYMMDDHHmm`) against `prev_version`:
|
|
136
|
+
|
|
137
|
+
- **Change Categories**:
|
|
138
|
+
- `schema_added` / `data_added`: Newly created tables, views, columns, indices, foreign keys, or inserted rows.
|
|
139
|
+
- `schema_removed` / `data_removed`: Dropped schema objects or deleted rows.
|
|
140
|
+
- `schema_changed` / `data_changed`: Modified column types/properties or updated data row values over time.
|
|
141
|
+
- **Output**: Exported to `{version}_log.md` (Markdown) or the `log` sheets in Excel.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### Configuration Reference (`config.yaml`)
|
|
146
|
+
|
|
147
|
+
| Parameter | Type | Default | Description |
|
|
148
|
+
| :--- | :--- | :--- | :--- |
|
|
149
|
+
| `output_type` | `Literal["xlsx", "md"]` | Required | Output format. `"md"` generates Markdown files; `"xlsx"` generates an Excel workbook. |
|
|
150
|
+
| `output_dir` | `str` | Required | Directory path where output reports are saved. |
|
|
151
|
+
| `prev_version` | `str` | `""` | Previous version (`YYYYMMDDHHmm`) to compare against. If empty (`""`), automatically uses the latest version recorded in SQLite. |
|
|
152
|
+
| `process_when_changed` | `bool` | Required | If `true`, stops execution without generating reports if no schema or data changes are detected against `prev_version`. If `false`, generates reports on every run. |
|
|
153
|
+
| `data_tables` | `list[DataTableConfig]` | `[]` | List of tables and columns to compare data for. |
|
|
154
|
+
| `data_tables[].table` | `str` | Required | Table name in MySQL. |
|
|
155
|
+
| `data_tables[].columns` | `list[str]` | Required | Columns to compare for value differences. |
|
|
156
|
+
| `data_tables[].key_columns` | `list[str]` | Required | Key columns (e.g., primary key) used to match corresponding rows across databases. |
|
|
157
|
+
| `exclude_tables` | `list[str]` | Required | Table names to exclude from cross-environment schema comparison (`a != b`), such as migration tables (e.g., `["alembic_version"]`). *(Not excluded during same-database history tracking `a == b`)*. |
|
|
158
|
+
| `exclude_columns` | `list[str]` | Required | Column names to ignore during cross-environment column comparisons. |
|
|
159
|
+
| `db_host` | `str` | Required | Hostname or IP address for MySQL database connections. |
|
|
160
|
+
| `envs` | `list[EnvConfig]` | Required | List of environments and databases to connect to and extract. |
|
|
161
|
+
| `envs[].name` | `str` | Required | Environment identifier (e.g., `dev`, `stg`, `prd`). |
|
|
162
|
+
| `envs[].port` | `int` | Required | MySQL port number for this environment. |
|
|
163
|
+
| `envs[].db_names` | `list[str]` | Required | List of database names to extract from this environment. |
|
|
164
|
+
| `compare_list` | `list[EnvCompareConfig]` | Required | Target database pairs to compare (e.g., `a: dev.shop`, `b: stg.shop`). |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### How It Works
|
|
169
|
+
|
|
170
|
+
1. **Extraction & Snapshotting**:
|
|
171
|
+
- Connects to MySQL instances defined in `envs` using credentials from `.env`.
|
|
172
|
+
- Extracts schema definitions (`information_schema.TABLES`, `COLUMNS`, `STATISTICS`, `KEY_COLUMN_USAGE`) and records from `data_tables`.
|
|
173
|
+
- Saves a point-in-time snapshot into an embedded SQLite database (`db_client/schema_data.sqlite3`), tagged with the current version timestamp (`YYYYMMDDHHmm`).
|
|
174
|
+
2. **Change Detection**:
|
|
175
|
+
- Queries SQLite to check whether any schema or data differences exist between the current version and `prev_version`.
|
|
176
|
+
- If `process_when_changed: true` and no changes are found, execution halts early.
|
|
177
|
+
3. **Comparison Execution**:
|
|
178
|
+
- Compares all configured pairs in `compare_list` using parameterized queries with `#foreach` list filtering.
|
|
179
|
+
4. **Report Export & Alerts**:
|
|
180
|
+
- Writes Markdown or Excel reports to `data/`.
|
|
181
|
+
- If schema or data changes are detected in log mode (`is_log: true`), an alert is automatically posted to Discord via `DISCORD_WEB_HOOK_URL`.
|
|
182
|
+
- Any runtime errors or exceptions are formatted and sent to Discord as alerts.
|
|
183
|
+
|
|
184
|
+
### 3. Environment Variables (`.env`)
|
|
185
|
+
|
|
186
|
+
Set database credentials in `.env`:
|
|
187
|
+
|
|
188
|
+
```env
|
|
189
|
+
DB_USERNAME=your_username
|
|
190
|
+
DB_PASSWORD=your_password
|
|
191
|
+
DISCORD_WEB_HOOK_URL=https://discord.com/api/webhooks/...
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 4. Run Comparison
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Run via CLI
|
|
198
|
+
compare-schema --config_path config/config.yaml
|
|
199
|
+
|
|
200
|
+
# Or run as Python module
|
|
201
|
+
python -m src.main --config_path config/config.yaml
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
compare_schema-0.1.1.dist-info/licenses/LICENSE,sha256=SceEQXH2EqmhxRLvy-52rf03gwxH8LrGttgH-lannvU,1065
|
|
2
|
+
db_client/schema.sql,sha256=L8c87TmnsCkpQp2uKW4x6nn1hTJ4bs5ONYuhiqa5yPY,1804
|
|
3
|
+
db_client/schema_client.py,sha256=QI3w8pFuyYich_J4uy0YwHnj6h-E2idHjjNEb_IwKUs,285
|
|
4
|
+
db_client/schema_settings.py,sha256=aGmfLtEVcAg3mrwHbB_GCvaJzL2JdC_FBvv0QKXMmto,1122
|
|
5
|
+
db_client/source_client.py,sha256=y2EP4s_1qKCRPac_VcBJ5lzg8k0eSpOjELklIQ3gXiU,505
|
|
6
|
+
db_client/source_settings.py,sha256=NR5XHBteLOUJFVahCs3fhNoldVVAJLOhen9chh_gwYo,1240
|
|
7
|
+
db_client/queries/schema/data.yml,sha256=1izUdJpcC7kamR3Y9fpRM4WyXSe-ekqjpFLJqTozpwA,3848
|
|
8
|
+
db_client/queries/schema/schema.yml,sha256=WtB__WOEZ--lLeVygrhME1Bmc9V5iyTDMr3sjXEmXNU,20524
|
|
9
|
+
db_client/queries/source/import_data.yml,sha256=hFcwwZ0Fm_4VY9Lwcl9o-ewe3-SbriRXhpeJDEB6gOc,188
|
|
10
|
+
db_client/queries/source/import_schema.yml,sha256=tKONtDwTx4Wpqt1oW93OJEr1J6-ErEqYky182f-99ew,2185
|
|
11
|
+
src/config.py,sha256=_xfR1G8C9rzzvTwd8C0nszNL9Qx34j58dzmoCjbw6t8,1392
|
|
12
|
+
src/env_config.py,sha256=-JeN-P_5X4J3r02_mrLCnbRlY5lcmYUEf8NUUue_Gio,385
|
|
13
|
+
src/excel_helper.py,sha256=6zlzvUFggEznnWiIq0vA4P_nweBO7I7v2R1ZL_cGX2E,2452
|
|
14
|
+
src/main.py,sha256=uO0fSNnW6c9dqksX3UqszTkyakcf77Wus7xS4JVU5iw,47555
|
|
15
|
+
src/markdown_helper.py,sha256=cMyF0FSm0tu3PqfJ2joerrZPqouX_yVgUdbUOSppWXY,2624
|
|
16
|
+
src/models.py,sha256=trzluwMu1gaCL_drEprGcDRiGVf0ftoeGNl5jGMgdi0,6774
|
|
17
|
+
src/util_mysql.py,sha256=lknFYsM57d42-xY0LMG4UzV41bG1vFhRT8dkLdhWMxk,10781
|
|
18
|
+
src/util_other.py,sha256=qMxTLqwpHLR5v90KZEYlvLh2qrsyxQbMklZjOmBHXJk,624
|
|
19
|
+
src/util_path.py,sha256=6FBCRFjZPPFOxmh1SQXn4g8bGN-nQKvrrZua5-nry6U,3505
|
|
20
|
+
compare_schema-0.1.1.dist-info/METADATA,sha256=fInsqSoxpttNg9UABnmWdsoU9G8FT8S1mCXJtFqV_00,8849
|
|
21
|
+
compare_schema-0.1.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
22
|
+
compare_schema-0.1.1.dist-info/entry_points.txt,sha256=A5fUzIs5Z1S51jWFufwMNoYLf1U8xPDiY-ShEdcZXUA,49
|
|
23
|
+
compare_schema-0.1.1.dist-info/top_level.txt,sha256=nwhb5mKiVo0RuDBMfpvgFk3OC5T4z6FMIOq-Z2FD_is,14
|
|
24
|
+
compare_schema-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 doctorgu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
- name: delete_data_by_version
|
|
2
|
+
value: |
|
|
3
|
+
DELETE
|
|
4
|
+
FROM ${table}
|
|
5
|
+
WHERE version = :version
|
|
6
|
+
|
|
7
|
+
- name: insert_data_from_mysql
|
|
8
|
+
value: |
|
|
9
|
+
INSERT INTO ${table}
|
|
10
|
+
(
|
|
11
|
+
version, env_name, db_name,
|
|
12
|
+
${columns}
|
|
13
|
+
)
|
|
14
|
+
VALUES
|
|
15
|
+
(
|
|
16
|
+
:version, :env_name, :db_name,
|
|
17
|
+
${values}
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
- name: read_table_sql
|
|
21
|
+
value: |
|
|
22
|
+
SELECT sql
|
|
23
|
+
FROM sqlite_master
|
|
24
|
+
WHERE type = 'table'
|
|
25
|
+
AND name = :table
|
|
26
|
+
|
|
27
|
+
- name: read_table_info
|
|
28
|
+
value: |
|
|
29
|
+
PRAGMA table_info("${table}")
|
|
30
|
+
|
|
31
|
+
- name: create_backup_table
|
|
32
|
+
value: |
|
|
33
|
+
DROP TABLE IF EXISTS "${backup_table}";
|
|
34
|
+
|
|
35
|
+
CREATE TABLE "${backup_table}" AS
|
|
36
|
+
SELECT *
|
|
37
|
+
FROM "${table}";
|
|
38
|
+
|
|
39
|
+
DROP TABLE "${table}";
|
|
40
|
+
|
|
41
|
+
- name: create_table_index
|
|
42
|
+
value: |
|
|
43
|
+
CREATE TABLE "${table}" (
|
|
44
|
+
${columns}
|
|
45
|
+
) STRICT;
|
|
46
|
+
|
|
47
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "${table}_unique_idx" ON "${table}" (${index_cols});
|
|
48
|
+
|
|
49
|
+
- name: read_data_not_exists
|
|
50
|
+
value: |
|
|
51
|
+
SELECT a.env_name, a.db_name,
|
|
52
|
+
a.${key_columns}
|
|
53
|
+
FROM ${table} a
|
|
54
|
+
LEFT JOIN ${table} b
|
|
55
|
+
ON
|
|
56
|
+
#if ${other_version}
|
|
57
|
+
b.version = :other_version
|
|
58
|
+
#else
|
|
59
|
+
a.version = b.version
|
|
60
|
+
#endif
|
|
61
|
+
AND b.env_name = :other_env_name
|
|
62
|
+
AND b.db_name = :other_db_name
|
|
63
|
+
AND ${key_columns_equal}
|
|
64
|
+
WHERE a.version = :current_version
|
|
65
|
+
AND a.env_name = :current_env_name
|
|
66
|
+
AND a.db_name = :current_db_name
|
|
67
|
+
AND b.version IS NULL
|
|
68
|
+
|
|
69
|
+
- name: read_data_different
|
|
70
|
+
value: |
|
|
71
|
+
SELECT a.${key_columns},
|
|
72
|
+
${other_columns_comma_a},
|
|
73
|
+
${other_columns_comma_b},
|
|
74
|
+
a.env_name, a.db_name
|
|
75
|
+
FROM ${table} a
|
|
76
|
+
INNER JOIN ${table} b
|
|
77
|
+
ON
|
|
78
|
+
#if ${other_version}
|
|
79
|
+
b.version = :other_version
|
|
80
|
+
#else
|
|
81
|
+
a.version = b.version
|
|
82
|
+
#endif
|
|
83
|
+
AND b.env_name = :other_env_name
|
|
84
|
+
AND b.db_name = :other_db_name
|
|
85
|
+
AND ${key_columns_equal}
|
|
86
|
+
WHERE a.version = :current_version
|
|
87
|
+
AND a.env_name = :current_env_name
|
|
88
|
+
AND a.db_name = :current_db_name
|
|
89
|
+
AND
|
|
90
|
+
(
|
|
91
|
+
1 != 1
|
|
92
|
+
${other_columns_inequal}
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
- name: read_not_same_data
|
|
96
|
+
value: |
|
|
97
|
+
WITH
|
|
98
|
+
#foreach dt in ${data_tables} separator=','
|
|
99
|
+
n_${dt.table} AS (
|
|
100
|
+
SELECT env_name, db_name,
|
|
101
|
+
#foreach col in ${dt.columns} separator=','
|
|
102
|
+
"${col}"
|
|
103
|
+
#endfor
|
|
104
|
+
FROM "${dt.table}"
|
|
105
|
+
WHERE version = :version
|
|
106
|
+
)
|
|
107
|
+
, o_${dt.table} AS (
|
|
108
|
+
SELECT env_name, db_name,
|
|
109
|
+
#foreach col in ${dt.columns} separator=','
|
|
110
|
+
"${col}"
|
|
111
|
+
#endfor
|
|
112
|
+
FROM "${dt.table}"
|
|
113
|
+
WHERE version = :prev_version
|
|
114
|
+
)
|
|
115
|
+
#endfor
|
|
116
|
+
, cnt AS (
|
|
117
|
+
#foreach idx, dt in ${data_tables} separator=' UNION ALL '
|
|
118
|
+
SELECT '${dt.table}' compare_type,
|
|
119
|
+
(
|
|
120
|
+
SELECT count(*) cnt_n
|
|
121
|
+
FROM n_${dt.table}
|
|
122
|
+
) n,
|
|
123
|
+
(
|
|
124
|
+
SELECT count(*) cnt_o
|
|
125
|
+
FROM o_${dt.table}
|
|
126
|
+
) o,
|
|
127
|
+
(
|
|
128
|
+
SELECT count(*) cnt_n_o
|
|
129
|
+
FROM n_${dt.table} n
|
|
130
|
+
INNER JOIN o_${dt.table} o
|
|
131
|
+
ON o.env_name = n.env_name
|
|
132
|
+
AND o.db_name = n.db_name
|
|
133
|
+
AND
|
|
134
|
+
#foreach col in ${dt.columns} separator=' AND '
|
|
135
|
+
COALESCE(o."${col}", '<NULL>') = COALESCE(n."${col}", '<NULL>')
|
|
136
|
+
#endfor
|
|
137
|
+
) n_o
|
|
138
|
+
#endfor
|
|
139
|
+
)
|
|
140
|
+
SELECT compare_type
|
|
141
|
+
FROM cnt
|
|
142
|
+
WHERE n != o OR o != n_o
|