对于我的mysql-audit-tables project,我想将原始数据表的定义与相关的审计表进行比较,后者具有相同的列和一些标题信息。
编辑:为此问题创建sqlfiddle后,我发现它在sqlfiddle(MYSQL V5.6)上正常工作,而在我在windows上的5.7安装中我得到了不同的结果对于3个查询中的第三个(删除列)。
编辑:添加了要与之比较的示例表:
CREATE TABLE `audit_testdata`.`testtable` (-- the data table!
`text_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`text_type_id` bigint(20) unsigned NOT NULL,
`text_other_id` bigint(20) unsigned NOT NULL,
`text_lng_id` bigint(20) unsigned NOT NULL,
`text_access_id` bigint(20) DEFAULT NULL,
`text_html` text,
`text_plain` text,
`testadd` varchar(42) DEFAULT NULL,-- new field to test queries!
PRIMARY KEY (`text_id`),
UNIQUE KEY `text_id` (`text_id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;
CREATE TABLE `audit`.`testtable_audit` ( -- audit table, simplified
`audit_seq` bigint(20) unsigned NOT NULL,
`audit_pk` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`audit_timestamp` timestamp NOT NULL,
`text_id` bigint(20) unsigned NOT NULL COMMENT 'pk_testtable: ',-- change d field to test queries.
`text_type_id` bigint(20) unsigned NOT NULL,
`text_other_id` bigint(20) unsigned NOT NULL,
`text_lng_id` bigint(20) unsigned NOT NULL,
`text_access_id` bigint(20) DEFAULT NULL,
`text_html` text,
`text_plain` text,
`text_symbol` blob,-- deleted field to test queries.
PRIMARY KEY (`audit_pk`),
UNIQUE KEY `audit_pk` (`audit_pk`),
KEY `text_id` (`text_id`),
KEY `audit_timestamp` (`audit_timestamp`),
KEY `audit_seq` (`audit_seq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
一些准备意见:
DROP VIEW IF EXISTS v_audit_info_tables;
CREATE VIEW v_audit_info_tables AS
SELECT CONCAT('`',TABLE_SCHEMA,'`.`',TABLE_NAME,'`') AS FQ_TABLE_NAME,
TABLE_SCHEMA,TABLE_NAME
FROM information_schema.TABLES;
DROP VIEW IF EXISTS v_audit_info_columns;
CREATE VIEW v_audit_info_columns AS
SELECT CONCAT('`',TABLE_SCHEMA,'`.`',TABLE_NAME,'`') AS FQ_TABLE_NAME,
CONCAT('`',TABLE_SCHEMA,'`.`',TABLE_NAME,'`.`',COLUMN_NAME,'`') AS FQ_COLUMN_NAME,
TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_KEY,COLUMN_DEFAULT,
CONCAT('`',COLUMN_NAME,'` ',
UPPER(COLUMN_TYPE),
IF(IS_NULLABLE='YES',' NULL ',' NOT NULL '),
'COMMENT ''',REPLACE(COLUMN_COMMENT,'''',''''''),'''') AS FQ_COLUMN_CHANGE
FROM information_schema.COLUMNS;
这是一个映射视图,用于链接每个数据表及其审计表。在我的真实项目中,有一些配置表可供使用:
DROP VIEW IF EXISTS v_audit_map_tables;
CREATE VIEW v_audit_map_tables AS
SELECT dat.FQ_TABLE_NAME AS dat_fq_table_name,dat.TABLE_SCHEMA AS dat_table_schema,dat.TABLE_NAME AS dat_table_name,
aud.FQ_TABLE_NAME AS aud_fq_table_name,aud.TABLE_SCHEMA AS aud_table_schema,aud.TABLE_NAME as aud_table_name
FROM v_audit_info_tables dat JOIN v_audit_info_tables aud
ON aud.TABLE_NAME = CONCAT(dat.TABLE_NAME,'_audit')
WHERE dat.TABLE_SCHEMA = 'audit_testdata' AND aud.TABLE_SCHEMA = 'audit';
;
这里有一个完整的图片,用于修改列的工作查询:
SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE,AUD.FQ_COLUMN_CHANGE,
CONCAT('ALTER TABLE ',aud.FQ_TABLE_NAME,' MODIFY COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
dat.FQ_TABLE_NAME,aud.FQ_TABLE_NAME
FROM v_audit_info_columns dat JOIN v_audit_info_columns aud
ON dat.COLUMN_NAME = aud.COLUMN_NAME
WHERE dat.FQ_COLUMN_CHANGE <> aud.FQ_COLUMN_CHANGE
;
这是非工作查询,它似乎永远存在:
SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE,NULL,
CONCAT('ALTER TABLE ',audmap.aud_fq_table_name,' ADD COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
dat.FQ_TABLE_NAME,audmap.aud_fq_table_name
FROM v_audit_info_columns dat JOIN v_audit_map_tables audmap
ON audmap.dat_fq_table_name = dat.FQ_TABLE_NAME
WHERE dat.COLUMN_NAME NOT IN
(SELECT DISTINCT aud.COLUMN_NAME FROM v_audit_info_columns aud
WHERE aud.TABLE_NAME = audmap.aud_table_name AND aud.TABLE_SCHEMA = audmap.aud_table_schema
-- AND aud.FQ_TABLE_NAME = audmap.aud_fq_table_name
);
我先尝试aud.FQ_TABLE_NAME = audmap.aud_fq_table_name
,然后直接点击TABLE_NAME/TABLE_SCHEMA
。我已经查看了其他一些问题,所以我的新想法是重新设计最终查询,但我仍然不知道如何。
EDIT-2:现在这是一个缓慢的工作解决方案,上面的查询很慢而且错误。让它运作的基本提示是MYSQL documentation。我将这些案例放在一个UNION中,它在我的窗口上运行大约6秒钟,所以我仍然有兴趣优化更多:
SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE AS dat_change,AUD.FQ_COLUMN_CHANGE AS aud_change,
CONCAT('ALTER TABLE ',aud.FQ_TABLE_NAME,' MODIFY COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
dat.FQ_TABLE_NAME AS dat_table_name,aud.FQ_TABLE_NAME AS aud_table_name
FROM v_audit_info_columns dat JOIN v_audit_info_columns aud
ON dat.COLUMN_NAME = aud.COLUMN_NAME
JOIN v_audit_map_tables audmap
ON dat.FQ_TABLE_NAME = audmap.dat_fq_table_name AND aud.FQ_TABLE_NAME = audmap.aud_fq_table_name
WHERE dat.FQ_COLUMN_CHANGE <> aud.FQ_COLUMN_CHANGE
UNION
SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE,NULL,
CONCAT('ALTER TABLE ',audmap.aud_fq_table_name,' ADD COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
dat.FQ_TABLE_NAME,audmap.aud_fq_table_name
FROM v_audit_info_columns dat
JOIN v_audit_map_tables audmap ON (audmap.dat_fq_table_name = dat.FQ_TABLE_NAME)
WHERE NOT EXISTS (SELECT 1 FROM v_audit_info_columns aud WHERE dat.aud_fq_column_name = aud.FQ_COLUMN_NAME)
UNION
SELECT aud.FQ_COLUMN_NAME,NULL,aud.FQ_COLUMN_CHANGE,
CONCAT('-- ALTER TABLE ',aud.FQ_TABLE_NAME,' DROP COLUMN `',aud.COLUMN_NAME,'`') AS modify_cmd,
audmap.dat_fq_table_name, audmap.aud_fq_table_name
FROM v_audit_info_columns aud JOIN v_audit_map_tables audmap
ON audmap.aud_fq_table_name = aud.FQ_TABLE_NAME
WHERE NOT EXISTS (SELECT 1 FROM v_audit_info_columns dat
WHERE dat.fq_column_name = CONCAT(audmap.dat_fq_table_name,'.`',aud.COLUMN_NAME,'`'))
;
答案 0 :(得分:0)
为了优化联合,还需要两个带索引的表,从我的计算机上的6.14秒到0.063秒。他们是:
CREATE TABLE IF NOT EXISTS audit12_columns (
FQ_TABLE_NAME VARCHAR(133),
FQ_COLUMN_NAME VARCHAR(200) PRIMARY KEY,
TABLE_SCHEMA VARCHAR(64),
TABLE_NAME VARCHAR(64),
COLUMN_NAME VARCHAR(64),
FQ_COLUMN_CHANGE VARCHAR(2000),
aud_fq_column_name VARCHAR(200),
INDEX (FQ_TABLE_NAME),
UNIQUE KEY (TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME),
UNIQUE KEY (aud_fq_column_name)
);
CREATE TABLE IF NOT EXISTS audit12_mapping (
dat_fq_table_name VARCHAR(200) PRIMARY KEY,
dat_table_schema VARCHAR(64),
dat_table_name VARCHAR(64),
aud_fq_table_name VARCHAR(200) UNIQUE,
aud_table_schema VARCHAR(64),
aud_table_name VARCHAR(64),
UNIQUE KEY (dat_table_schema,dat_table_name),
UNIQUE KEY (aud_table_schema,aud_table_name)
);
表可以由相应的视图填充,并且在逐个表的基础上完成,只能将这些数据条目提供给表:
DELETE FROM audit12_mapping;
INSERT INTO audit12_mapping (dat_fq_table_name, dat_table_schema, dat_table_name,
aud_fq_table_name, aud_table_schema, aud_table_name)
SELECT dat_fq_table_name, dat_table_schema, dat_table_name,
aud_fq_table_name, aud_table_schema, aud_table_name
FROM v_audit_map_tables
WHERE dat_fq_table_name = i_id_data_table;-- limit to actual entry.
DELETE FROM audit12_columns;
INSERT INTO audit12_columns (FQ_TABLE_NAME, FQ_COLUMN_NAME,
TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME,
FQ_COLUMN_CHANGE, aud_fq_column_name)
SELECT FQ_TABLE_NAME, FQ_COLUMN_NAME,
TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME,
FQ_COLUMN_CHANGE, aud_fq_column_name
FROM v_audit_info_columns
WHERE (FQ_TABLE_NAME = i_id_data_table OR FQ_TABLE_NAME = l_id_audit_table);
最终的UNION查询如下所示:
SELECT CONCAT('ALTER TABLE ',aud.FQ_TABLE_NAME,' MODIFY COLUMN ',dat.FQ_COLUMN_CHANGE,';') AS modify_cmd
FROM audit12_columns dat JOIN audit12_columns aud
ON dat.COLUMN_NAME = aud.COLUMN_NAME
JOIN audit12_mapping audmap
ON dat.FQ_TABLE_NAME = audmap.dat_fq_table_name AND aud.FQ_TABLE_NAME = audmap.aud_fq_table_name
WHERE dat.FQ_COLUMN_CHANGE <> aud.FQ_COLUMN_CHANGE
UNION
SELECT CONCAT('ALTER TABLE ',audmap.aud_fq_table_name,' ADD COLUMN ',dat.FQ_COLUMN_CHANGE,';') AS modify_cmd
FROM audit12_columns dat
JOIN audit12_mapping audmap ON (audmap.dat_fq_table_name = dat.FQ_TABLE_NAME)
WHERE NOT EXISTS (SELECT 1 FROM audit12_columns aud WHERE dat.aud_fq_column_name = aud.FQ_COLUMN_NAME)
UNION
SELECT CONCAT('-- ALTER TABLE ',aud.FQ_TABLE_NAME,' DROP COLUMN `',aud.COLUMN_NAME,'`;') AS modify_cmd
FROM audit12_columns aud JOIN audit12_mapping audmap
ON audmap.aud_fq_table_name = aud.FQ_TABLE_NAME
WHERE NOT EXISTS (SELECT 1 FROM audit12_columns dat
WHERE dat.fq_column_name = CONCAT(audmap.dat_fq_table_name,'.`',aud.COLUMN_NAME,'`'))
;
顺便说一句,我首先尝试将audit12_columns和audit12_mapping作为临时表,但是我遇到了ERROR 1137:无法重新打开表:&#39; temp_table&#39;错误,已在mysql documentation中解释。