PostgreSQL(OpenGauss/MogDB) 大小写转换实战:批量处理表名与字段名的自动化方案
1. 为什么PostgreSQL的大小写问题让人头疼第一次用PostgreSQL的时候我就被它的大小写规则坑惨了。明明在Oracle里运行好好的SQL语句搬到PostgreSQL就报relation does not exist错误。后来才发现原来PostgreSQL对双引号包裹的对象名是严格区分大小写的这跟其他数据库的行为完全不同。举个例子如果你执行CREATE TABLE MyTable (id int)实际创建的表名会自动转换成小写mytable。但如果你用CREATE TABLE MyTable (id int)那就真的创建了一个大小写敏感的表名。这时候查询必须写成SELECT * FROM MyTable少个引号或者大小写不对都会报错。这种特性在ORM框架集成时尤其麻烦。比如Hibernate生成的SQL默认不带双引号当你的表名是User时Hibernate会去找user表结果当然是找不到。我见过不少团队为此重写实体类注解甚至修改框架源码其实完全可以通过批量转换表名和字段名来解决。2. 实战前的准备工作2.1 理解信息模式information_schema要批量修改表名和字段名首先得知道怎么获取这些元数据。PostgreSQL的information_schema就像是个数据库的自述文件里面存储了所有表、列、约束的定义信息。重点看这两个视图information_schema.tables包含所有表信息information_schema.columns包含所有列信息比如查询所有非小写的表名SELECT table_name FROM information_schema.tables WHERE table_schemapublic AND table_name lower(table_name);2.2 创建执行动态SQL的函数因为ALTER语句不能直接用在查询结果上我们需要一个能执行动态SQL的辅助函数CREATE OR REPLACE FUNCTION public.exec(sqlstring varchar) RETURNS varchar AS $$ BEGIN EXECUTE sqlstring; RETURN ok; EXCEPTION WHEN OTHERS THEN RETURN error: || SQLERRM; END $$ LANGUAGE plpgsql;这个改良版的exec函数还会捕获异常方便排查问题。我建议在测试环境先创建这个函数验证无误后再用于生产环境。3. 批量转换字段名大小写3.1 识别需要修改的字段先找出所有需要处理的字段假设我们只处理public模式SELECT table_name, column_name FROM information_schema.columns WHERE table_schemapublic AND column_name lower(column_name) AND table_name NOT LIKE pg_%; -- 排除系统表3.2 生成并执行修改语句用这个SQL生成所有ALTER语句并执行SELECT exec( ALTER TABLE || table_name || RENAME COLUMN || column_name || TO || lower(column_name) || ; ) FROM information_schema.columns WHERE table_schemapublic AND column_name lower(column_name);注意这里用双引号包裹原字段名新字段名则不用引号。我曾经漏掉双引号结果语句执行成功但实际没修改因为PostgreSQL默认会把标识符转成小写。4. 批量转换表名大小写4.1 查找需要修改的表查询所有非小写的表名SELECT table_name FROM information_schema.tables WHERE table_schemapublic AND table_name lower(table_name) AND table_name NOT LIKE pg_%;4.2 执行表名修改生成批量修改表名的语句SELECT exec( ALTER TABLE || table_name || RENAME TO || lower(table_name) || ; ) FROM information_schema.tables WHERE table_schemapublic AND table_name lower(table_name);这里有个坑要注意如果表有外键引用直接RENAME会报错。这时候需要先删除外键修改完表名后再重建。我在实际项目中就遇到过这个问题后来写了个脚本自动处理外键依赖。5. OpenGauss/MogDB的特殊处理OpenGauss和MogDB作为PostgreSQL的衍生版本基本兼容这些操作但有几点差异系统视图可能略有不同建议先用\d命令查看准确的视图名某些版本可能需要调整函数权限GRANT EXECUTE ON FUNCTION public.exec TO your_user;MogDB对模式名的处理更严格如果表不在public模式记得修改脚本中的schema条件我在某次MogDB迁移中发现字段名包含中文时转换会失败后来发现需要额外处理编码问题SELECT exec( ALTER TABLE || table_name || RENAME COLUMN || column_name || TO || convert_to(lower(column_name), UTF8) || ; )6. 完整脚本与安全建议结合以上内容这是一个完整的批量转换脚本-- 创建执行函数 CREATE OR REPLACE FUNCTION public.exec(sqlstring varchar) RETURNS varchar AS $$ BEGIN EXECUTE sqlstring; RETURN ok; EXCEPTION WHEN OTHERS THEN RETURN error: || SQLERRM; END $$ LANGUAGE plpgsql; -- 批量修改字段名 SELECT exec( ALTER TABLE || table_name || RENAME COLUMN || column_name || TO || lower(column_name) || ; ) AS result FROM information_schema.columns WHERE table_schemapublic AND column_name lower(column_name); -- 批量修改表名 SELECT exec( ALTER TABLE || table_name || RENAME TO || lower(table_name) || ; ) AS result FROM information_schema.tables WHERE table_schemapublic AND table_name lower(table_name);安全建议先备份数据库我在第一次运行时不小心把系统表也改了导致数据库不可用先在测试环境执行确认无误后再上生产对于大型数据库建议分批执行避免长时间锁表检查是否有应用代码直接引用带引号的表名字段名这些地方需要同步修改7. 常见问题排查问题1执行后查询还是报错relation does not exist检查是否所有表名字段名都已转换成功确认应用连接是否使用了正确的大小写查看是否有缓存如Hibernate的二级缓存问题2外键约束导致修改失败 解决方法-- 先删除外键 ALTER TABLE 子表 DROP CONSTRAINT 外键名; -- 修改表名后 ALTER TABLE 子表 ADD CONSTRAINT 外键名 FOREIGN KEY (字段) REFERENCES 父表(字段);问题3函数执行权限不足 解决方法GRANT EXECUTE ON FUNCTION public.exec TO 你的用户名;我在实际项目中遇到过最棘手的情况是一个表名同时被视图和存储过程引用这时候需要先导出这些对象的定义修改表名后再重新创建。建议先用以下查询找出所有依赖对象SELECT dependent_ns.nspname as dependent_schema, dependent_view.relname as dependent_view FROM pg_depend JOIN pg_rewrite ON pg_depend.objid pg_rewrite.oid JOIN pg_class as dependent_view ON pg_rewrite.ev_class dependent_view.oid JOIN pg_class as source_table ON pg_depend.refobjid source_table.oid JOIN pg_namespace source_ns ON source_table.relnamespace source_ns.oid WHERE source_ns.nspname public AND source_table.relname 你的表名;8. 性能优化技巧当处理成千上万的表时直接运行上述脚本可能会很慢。我总结了几点优化经验使用事务批量执行BEGIN; -- 批量执行ALTER语句 COMMIT;并行处理将表按名称分段用多个连接同时执行对于特别大的数据库可以先导出元数据到文件用外部脚本生成修改语句psql -c SELECT table_name FROM information_schema.tables WHERE ... tables.txt临时增加维护工作内存SET maintenance_work_mem 256MB;避开业务高峰期执行最好在维护窗口期操作记得有一次我需要修改一个包含5000多张表的数据库直接跑脚本花了3个多小时。后来改用分批事务处理时间缩短到40分钟。关键是要在测试环境评估执行时间做好回滚方案。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2451496.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!