PostgreSQL 修改字段类型但是存在视图依赖
其实视图的存在与否在数据库界一直是一个话题。用好视图可以简化程序的很多代码,用不好视图不仅会给维护带来很多的不便,也会造成很大的性能问题。下面我从维护方面给出案例,以及当存在这种问题的时候,如何去解决这个问题。
假设有如下的表和视图
CREATE TABLE view_test (id int,cname varchar(10),des text);
CREATE VIEW vw_view_testa AS SELECT * FROM view_test WHERE id > 2;
CREATE VIEW vw_view_testb AS SELECT * FROM view_test WHERE id < 3;
INSERT INTO view_test(id,cname,des) VALUES (1,'a','value a'),(2,'b','value b'),(3,'c','value c'),(4,'d','value d'),(5,'e','value e');
现在我想修改表的字段 cname 从 varchar(10) 到 varchar(50)
ALTER TABLE view_test ALTER COLUMN cname TYPE VARCHAR(50);
ERROR: cannot alter type of a column used by a view or rule
DETAIL: rule _RETURN on view vw_view_testa depends on column "cname"
说明:这个时候会提示存在视图依赖无法修改字段的长度。当视图依赖成为一种嵌套的时候,这种问题在系统升级的时候会严重的影响升级的速度。那么有没有更好的办法去兼容呢。好的架构师需要从根本上解决,一般的业务公司只能是考虑做兼容。
下面是解决视图依赖的解决方案和步骤以及操作案例
CREATE TABLE public.deps_saved_ddl (
deps_id serial,
deps_view_schema name,
deps_view_name name,
deps_ddl_to_run text,
PRIMARY KEY (deps_id));
ALTER TABLE public.deps_saved_ddl OWNER TO postgres;
-- 将所有与表依赖的视图进行转储
CREATE OR REPLACE FUNCTION public.deps_save_and_drop_dependencies(p_view_schema name, p_view_name name)
RETURNS pg_catalog.void AS $BODY$
DECLARE v_curr record;
BEGIN FOR v_curr IN (
SELECT obj_schema,obj_name,obj_type
FROM ( WITH recursive recursive_deps(obj_schema, obj_name, obj_type, depth) AS
( SELECT p_view_schema, p_view_name, null::char,0
UNION
SELECT dep_schema::name, dep_name::name, dep_type::char, recursive_deps.depth + 1
FROM ( SELECT ref_nsp.nspname ref_schema, ref_cl.relname ref_name, rwr_cl.relkind dep_type, rwr_nsp.nspname dep_schema, rwr_cl.relname dep_name
FROM pg_depend dep
INNER JOIN pg_class ref_cl ON dep.refobjid = ref_cl.oid
INNER JOIN pg_namespace ref_nsp ON ref_cl.relnamespace = ref_nsp.oid
INNER JOIN pg_rewrite rwr ON dep.objid = rwr.oid
INNER JOIN pg_class rwr_cl ON rwr.ev_class = rwr_cl.oid
INNER JOIN pg_namespace rwr_nsp ON rwr_cl.relnamespace = rwr_nsp.oid
WHERE dep.deptype = 'n' AND dep.classid = 'pg_rewrite'::regclass ) deps
INNER JOIN recursive_deps ON deps.ref_schema = recursive_deps.obj_schema AND deps.ref_name = recursive_deps.obj_name
WHERE (deps.ref_schema != deps.dep_schema or deps.ref_name != deps.dep_name) )
SELECT obj_schema, obj_name, obj_type, depth
FROM recursive_deps
WHERE depth > 0 ) t
GROUP BY obj_schema, obj_name, obj_type
ORDER BY max(depth) DESC ) LOOP
INSERT INTO deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
SELECT DISTINCT p_view_schema, p_view_name, indexdef
FROM pg_indexes
WHERE schemaname = v_curr.obj_schema AND tablename = v_curr.obj_name;
INSERT INTO deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
SELECT DISTINCT tablename, rulename, definition
FROM pg_rules
WHERE schemaname = v_curr.obj_schema AND tablename = v_curr.obj_name;
INSERT INTO deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
SELECT p_view_schema,
p_view_name,
'COMMENT ON ' || CASE WHEN c.relkind = 'v' THEN 'VIEW' WHEN c.relkind = 'm' THEN 'MATERIALIZED VIEW' ELSE '' END || ' ' || n.nspname || '.' || c.relname || ' IS ''' || replace(d.description, '''', '''''') || ''';'
FROM pg_class c
INNER JOIN pg_namespace n ON n.oid = c.relnamespace
INNER JOIN pg_description d ON d.objoid = c.oid AND d.objsubid = 0
WHERE n.nspname = v_curr.obj_schema AND c.relname = v_curr.obj_name AND d.description is not null;
INSERT INTO deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
SELECT p_view_schema,
p_view_name,
'COMMENT ON COLUMN ' || n.nspname || '.' || c.relname || '.' || a.attname || ' IS ''' || replace(d.description, '''', '''''') || ''';'
FROM pg_class c
INNER JOIN pg_attribute a ON c.oid = a.attrelid
INNER JOIN pg_namespace n ON n.oid = c.relnamespace
INNER JOIN pg_description d ON d.objoid = c.oid AND d.objsubid = a.attnum
WHERE n.nspname = v_curr.obj_schema AND c.relname = v_curr.obj_name AND d.description is not null;
INSERT INTO deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
SELECT p_view_schema,
p_view_name,
'GRANT ' || privilege_type || ' ON ' || table_schema || '.' || quote_ident(table_name) || ' TO ' || grantee
FROM information_schema.role_table_grants
WHERE table_schema = v_curr.obj_schema AND table_name = v_curr.obj_name;
IF v_curr.obj_type = 'v' THEN
INSERT INTO deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
SELECT p_view_schema,
p_view_name,
'CREATE VIEW ' || v_curr.obj_schema || '.' || quote_ident(v_curr.obj_name) || ' AS ' || view_definition
FROM information_schema.views
WHERE table_schema = v_curr.obj_schema AND table_name = v_curr.obj_name;
elsif v_curr.obj_type = 'm' THEN
INSERT INTO deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
SELECT p_view_schema,
p_view_name,
'CREATE MATERIALIZED VIEW ' || v_curr.obj_schema || '.' || quote_ident(v_curr.obj_name) || ' AS ' || definition
FROM pg_matviews
WHERE schemaname = v_curr.obj_schema AND matviewname = v_curr.obj_name;
END IF;
EXECUTE 'DROP ' || CASE WHEN v_curr.obj_type = 'v' THEN 'VIEW' WHEN v_curr.obj_type = 'm' THEN 'MATERIALIZED VIEW' END || ' ' || v_curr.obj_schema || '.' || quote_ident(v_curr.obj_name);
END loop;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION public.deps_save_and_drop_dependencies(p_view_schema name, p_view_name name) OWNER TO postgres;
-- 对所有之前创建的视图进行重建
CREATE OR REPLACE FUNCTION "public"."deps_restore_dependencies"("p_view_schema" name, "p_view_name" name)
RETURNS "pg_catalog"."void" AS $BODY$
DECLARE v_curr record;
BEGIN
FOR v_curr IN ( SELECT deps_ddl_to_run
FROM deps_saved_ddl
WHERE deps_view_schema = p_view_schema AND deps_view_name = p_view_name ORDER BY deps_id DESC )
loop
EXECUTE v_curr.deps_ddl_to_run;
END loop;
DELETE FROM deps_saved_ddl WHERE deps_view_schema = p_view_schema AND deps_view_name = p_view_name;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION public.deps_restore_dependencies(p_view_schema name, p_view_name name) OWNER TO postgres;
操作案例
BEGIN;
SELECT deps_save_and_drop_dependencies('public', 'view_test');
ALTER TABLE view_test ALTER COLUMN cname TYPE VARCHAR(50);
SELECT deps_restore_dependencies('public', 'view_test');
COMMIT;
查看表的结构字段 cname 的长度是否是 50
[postgres@localhost data]$ psql
psql (12.8)
Type "help" for help.
postgres=# \c cloud_test
You are now connected to database "cloud_test" as user "postgres".
cloud_test=# \d view_test
Table "public.view_test"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
id | integer | | |
cname | character varying(50) | | |
des | text | | |
cloud_test=#
相关文章:
PostgreSQL 修改字段类型但是存在视图依赖
其实视图的存在与否在数据库界一直是一个话题。用好视图可以简化程序的很多代码,用不好视图不仅会给维护带来很多的不便,也会造成很大的性能问题。下面我从维护方面给出案例,以及当存在这种问题的时候,如何去解决这个问题。 假设…...
基于.NET 9实现实时进度条功能:前后端完整示例教程
要在基于.NET 9的应用中实现进度条功能,我们可以通过HttpContext.Response来发送实时的进度更新到前端。以下是一个简单的示例,展示了如何在ASP.NET Core应用中实现这一功能。 但是,我在.net framework4.7.2框架下,实际不了HttpC…...
力扣 LeetCode 19. 删除链表的倒数第N个结点(Day2:链表)
解题思路: 快慢指针 class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummy new ListNode(-1);dummy.next head;ListNode fast dummy;ListNode slow dummy;for (int i 0; i < n; i) {fast fast.next;}while (fast.ne…...
音频格式转换
一、场景 项目需求需要App实现声纹识别功能,调用科大讯飞接口: 声纹识别 API 文档 | 讯飞开放平台文档中心 其接口要求音频文件格式为mp3 二、问题产生 在安卓端根据官方文档说明,系统并不支持直接录制mp3格式音频,支持格式如…...
npm list @types/node 命令用于列出当前项目中 @types/node 包及其依赖关系
文章目录 作用示例常用选项示例命令注意事项 1、实战举例**解决方法**1. **锁定唯一的 types/node 版本**2. **清理依赖并重新安装**3. **设置 tsconfig.json 的 types**4. **验证 Promise 类型支持** **总结** npm list types/node 命令用于列出当前项目中 types/node 包及其…...
【Spring】Spring框架中有有哪些常见的设计模式
Spring 框架中广泛运用了多种设计模式,今天让我们来学习一下 1. 单例模式(Singleton Pattern) 用途:在Spring框架中,Bean默认是单例的,也就是说在容器中每种类型的Bean只有一个实例。这个设计可以节省资源…...
提升百度排名的有效策略与技巧解析
内容概要 提升百度排名对于网站的成功至关重要。首先,了解百度排名的基本原则,掌握搜索引擎是如何评估网页质量的,是优化过程中不可或缺的一部分。搜索引擎越来越倾向于将用户需求放在首位,因此提供高质量的内容和良好的用户体验…...
【Linux】Linux下查看cpu信息指令(top/mpstat/iostat/pidstat)说明
top命令 top(1) - Linux manual page (man7.org) top查看总的CPU利用率 us: 用户空间消耗的CPU资源占比,进程在用户态执行函数调用,编解码消耗的都是us sy: 内核空间消耗的CPU资源占比,进程调用系统调用达到内核后会增加sy的消耗 ni&…...
HDLBIts习题(3):使用冒号表示位宽时,冒号两端必须是常量
(1)易错习题1:Circuits - Combinational Logic - Multiplexers - 256-to-1 4bit multiplexer 使用冒号表示位宽时,冒号两端必须是常量,因此如果使用变量,可以使用位拼接的方法。 (2)…...
C++20协程详解
文章目录 什么是协程为什么需要协程什么时候使用协程协程的类别C20的协程协程的使用关键字co_wait框架一阶段完成数据交换co_yieldco_return 什么是协程 我们在学习编程的过程中,逐渐从单线程,到多线程,再到异步编程和并发处理 这些异步与并…...
Chromium 中chrome.system.display扩展接口定义c++
一、chrome.system.display 使用 system.display API 查询展示元数据。 权限 system.display 类型 ActiveState Chrome 117 及更高版本 用于指示系统是否检测到和使用显示屏的枚举。如果系统未检测到显示屏(可能断开连接,或因睡眠模式等原因而被视…...
容器docker的ulimit
Ulimit 在linux里ulimit命令可以对shell生成的进程的资源进行限制。 常用的ulimit限制 打开文件句柄数core文件大小设置进程能够消耗的虚拟内存设置用户能够打开的进程数目 不太常用的ulimit限制 设置数据段的最大值.单位:kbytes 设置创建文件的最大值.单位:blocks 设置在…...
一、HTML
一、基础概念 1、浏览器相关知识 这五个浏览器市场份额都非常大,且都有自己的内核。 什么是内核: 内核是浏览器的核心,用于处理浏览器所得到的各种资源。 例如,服务器发送图片、视频、音频的资源,浏览…...
使用Geekbench6软件对真实和虚拟的苹果桌面系统(macOS)进行打分比较
前言 感觉VMWare安装的MacOS使用起来非常的慢,所以特意用打分软件GeekBench进行了评测。 一、Geekbench的安装 可以从官网直接进行下载, 链接是: 二、Geekbench的直接使用 2.1、真机的信息 2.2、虚拟机的信息 三、打分的比较 3.1、真机…...
lua入门教程:随机数
在Lua中,生成随机数是通过math库中的math.random函数来实现的。这个函数可以生成一个[0, 1)区间内的随机浮点数。如果你需要生成其他范围内的随机数,或者需要整数类型的随机数,可以通过一些简单的数学运算来调整math.random的输出。 以下是如…...
华为大咖说 | 浅谈智能运维技术
本文分享自华为云社区:华为大咖说 | 浅谈智能运维技术-云社区-华为云 本文作者:李文轩 ( 华为智能运维专家 ) 全文约2695字,阅读约需8分钟 在大数据、人工智能等新兴技术的加持下,智能运维(AI…...
creo toolkit二次开发学习之获取任意选择模型作为元件,并进行获取约束等
获取任意选择模型作为元件进行操作前,先了解组件路径和程序集的构成:creo toolkit二次开发学习之程序集(ProAsmcomp)和装配体组件路径对象(ProAsmcomppath)-CSDN博客 代码如下 ProError test1() {ProError…...
sanitize-html 防止 XSS(跨站脚本攻击)
sanitize-html 是一个用于清理和验证 HTML 的 JavaScript 库,主要用于防止 XSS(跨站脚本攻击)。它允许你定义一套规则来决定哪些 HTML 标签和属性是可以被信任的,从而确保用户输入的内容不会包含潜在的恶意代码。 主要功能 HTML…...
【JavaEE】文件io
目录 文件类型 File概述 属性 构造方法 常用方法 Reader Writer InputStream OutputStream 字节流转字符流 通过Scanner读取InputStream 通过PrintWriter转换outputstream 示例 文件类型 从编程的角度看,文件类型主要就是两大类 文本(文…...
FlinkPipelineComposer 详解
FlinkPipelineComposer 详解 原文 背景 在flink-cdc 3.0中引入了pipeline机制,提供了除Datastream api/flink sql以外的一种方式定义flink 任务 通过提供一个yaml文件,描述source sink transform等主要信息 由FlinkPipelineComposer解析,…...
MySQL JOIN 优化详解
我刚工作的时候,有次上线了个新功能,结果有个 JOIN 查询慢得要命,用户投诉电话被打爆。DBA 帮我一看执行计划,发现驱动表选错了,扫描了 2000 万行。 从那以后,我每次写 JOIN 查询都会用 EXPLAIN 看看执行计…...
ET框架:C#全栈游戏开发的热更与服务端重构实践
1. ET框架不是“又一个Unity网络库”,而是重构服务器开发范式的底层工具链很多人第一次看到“ET框架”四个字,下意识会把它归类为“Unity里用的Socket封装库”或者“带点RPC味道的通信中间件”——这种理解偏差,恰恰是踩坑的起点。我2018年在…...
SuperCam:从源头减量的超像素传感器,重塑边缘视觉感知范式
1. 项目概述:为什么我们需要一种直接输出超像素的传感器?在计算机视觉领域,我们早已习惯了与像素打交道。无论是手机拍照、视频监控,还是自动驾驶的感知模块,其底层数据都源于一个由数百万乃至上亿个正方形像素点构成的…...
Arm调试中MEM-AP访问属性的配置与应用
1. 使用调试器启动带特定属性的MEM-AP访问在嵌入式系统调试过程中,我们经常需要通过调试器访问目标设备的内存。当涉及到安全内存区域或需要特殊访问权限时,理解如何配置Memory Access Port(MEM-AP)的属性就显得尤为重要。本文将详…...
Android高版本HTTPS抓包解法:Magisk+MoveCert证书升权实战
1. 为什么高版本安卓抓包越来越像在拆炸弹? 你有没有试过在Android 12或13上用Charles抓App的HTTPS流量,结果刚装完证书就弹出“此证书不受信任”?App死活不走代理,甚至直接闪退——不是网络问题,不是Charles没配好&a…...
Ubuntu 20.04上virt-manager报GDBus错误?别慌,三步排查法搞定‘Message recipient disconnected‘
Ubuntu 20.04 virt-manager报GDBus错误的深度排查指南当你在Ubuntu 20.04上使用virt-manager管理KVM虚拟机时,突然遇到"GDBus.Error:org.freedesktop.DBus.Error.NoReply: Message recipient disconnected"这样的错误提示,确实会让人感到困惑。…...
黑群晖硬盘满了别慌!手把手教你用SSH命令行扩容,Linux系统也通用
黑群晖存储扩容实战:SSH命令行全流程指南与Linux通用技巧当你发现黑群晖的存储空间亮起红灯时,那种焦虑感我深有体会。去年我的媒体服务器突然报出"存储空间不足"警告,当时存放的4TB家庭影像资料和重要工作备份几乎占满了整个磁盘。…...
AI驱动的高能物理探测器协同优化设计与实践
1. 高能物理探测器设计的范式转变在大型强子对撞机(LHC)时代,探测器设计面临前所未有的挑战。以CMS实验为例,其硅像素跟踪器的材料预算曾引发激烈讨论——虽然40-60%的光子转换概率有助于希格斯玻色子双光子衰变通道的识别&#x…...
固件逆向实战指南:从熵值分析到函数重建的七步法
1. 这不是“刷机教程”,而是一份固件逆向的实战切片很多人第一次听说“固件逆向”,脑子里浮现的是路由器刷OpenWrt、智能摄像头换壳跑Home Assistant,或者某款老式NAS突然不支持新硬盘,只好翻出U-Boot命令硬怼。这些确实是固件逆向…...
【AI Daily】Arxiv论文研读Top5 | 2026-05-23
📚 每日学习汇总 | 2026-05-23(周6) 📊 今日概览 今日:周6,午读检索分类:cs.AI / q-bio.NC / cs.HC关键词:cognitive science behavioral AI alignment🔥 五篇精读速报 ①…...
