当前位置: 首页 > news >正文

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 修改字段类型但是存在视图依赖

其实视图的存在与否在数据库界一直是一个话题。用好视图可以简化程序的很多代码&#xff0c;用不好视图不仅会给维护带来很多的不便&#xff0c;也会造成很大的性能问题。下面我从维护方面给出案例&#xff0c;以及当存在这种问题的时候&#xff0c;如何去解决这个问题。 假设…...

基于.NET 9实现实时进度条功能:前后端完整示例教程

要在基于.NET 9的应用中实现进度条功能&#xff0c;我们可以通过HttpContext.Response来发送实时的进度更新到前端。以下是一个简单的示例&#xff0c;展示了如何在ASP.NET Core应用中实现这一功能。 但是&#xff0c;我在.net framework4.7.2框架下&#xff0c;实际不了HttpC…...

力扣 LeetCode 19. 删除链表的倒数第N个结点(Day2:链表)

解题思路&#xff1a; 快慢指针 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实现声纹识别功能&#xff0c;调用科大讯飞接口&#xff1a; 声纹识别 API 文档 | 讯飞开放平台文档中心 其接口要求音频文件格式为mp3 二、问题产生 在安卓端根据官方文档说明&#xff0c;系统并不支持直接录制mp3格式音频&#xff0c;支持格式如…...

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 框架中广泛运用了多种设计模式&#xff0c;今天让我们来学习一下 1. 单例模式&#xff08;Singleton Pattern&#xff09; 用途&#xff1a;在Spring框架中&#xff0c;Bean默认是单例的&#xff0c;也就是说在容器中每种类型的Bean只有一个实例。这个设计可以节省资源…...

提升百度排名的有效策略与技巧解析

内容概要 提升百度排名对于网站的成功至关重要。首先&#xff0c;了解百度排名的基本原则&#xff0c;掌握搜索引擎是如何评估网页质量的&#xff0c;是优化过程中不可或缺的一部分。搜索引擎越来越倾向于将用户需求放在首位&#xff0c;因此提供高质量的内容和良好的用户体验…...

【Linux】Linux下查看cpu信息指令(top/mpstat/iostat/pidstat)说明

top命令 top(1) - Linux manual page (man7.org) top查看总的CPU利用率 us: 用户空间消耗的CPU资源占比&#xff0c;进程在用户态执行函数调用&#xff0c;编解码消耗的都是us sy: 内核空间消耗的CPU资源占比&#xff0c;进程调用系统调用达到内核后会增加sy的消耗 ni&…...

HDLBIts习题(3):使用冒号表示位宽时,冒号两端必须是常量

&#xff08;1&#xff09;易错习题1&#xff1a;Circuits - Combinational Logic - Multiplexers - 256-to-1 4bit multiplexer 使用冒号表示位宽时&#xff0c;冒号两端必须是常量&#xff0c;因此如果使用变量&#xff0c;可以使用位拼接的方法。 &#xff08;2&#xff09;…...

C++20协程详解

文章目录 什么是协程为什么需要协程什么时候使用协程协程的类别C20的协程协程的使用关键字co_wait框架一阶段完成数据交换co_yieldco_return 什么是协程 我们在学习编程的过程中&#xff0c;逐渐从单线程&#xff0c;到多线程&#xff0c;再到异步编程和并发处理 这些异步与并…...

Chromium 中chrome.system.display扩展接口定义c++

一、chrome.system.display 使用 system.display API 查询展示元数据。 权限 system.display 类型 ActiveState Chrome 117 及更高版本 用于指示系统是否检测到和使用显示屏的枚举。如果系统未检测到显示屏&#xff08;可能断开连接&#xff0c;或因睡眠模式等原因而被视…...

容器docker的ulimit

Ulimit 在linux里ulimit命令可以对shell生成的进程的资源进行限制。 常用的ulimit限制 打开文件句柄数core文件大小设置进程能够消耗的虚拟内存设置用户能够打开的进程数目 不太常用的ulimit限制 设置数据段的最大值.单位:kbytes 设置创建文件的最大值.单位:blocks 设置在…...

一、HTML

一、基础概念 1、浏览器相关知识 这五个浏览器市场份额都非常大&#xff0c;且都有自己的内核。 什么是内核&#xff1a; 内核是浏览器的核心&#xff0c;用于处理浏览器所得到的各种资源。 例如&#xff0c;服务器发送图片、视频、音频的资源&#xff0c;浏览…...

使用Geekbench6软件对真实和虚拟的苹果桌面系统(macOS)进行打分比较

前言 感觉VMWare安装的MacOS使用起来非常的慢&#xff0c;所以特意用打分软件GeekBench进行了评测。 一、Geekbench的安装 可以从官网直接进行下载&#xff0c; 链接是&#xff1a; 二、Geekbench的直接使用 2.1、真机的信息 2.2、虚拟机的信息 三、打分的比较 3.1、真机…...

lua入门教程:随机数

在Lua中&#xff0c;生成随机数是通过math库中的math.random函数来实现的。这个函数可以生成一个[0, 1)区间内的随机浮点数。如果你需要生成其他范围内的随机数&#xff0c;或者需要整数类型的随机数&#xff0c;可以通过一些简单的数学运算来调整math.random的输出。 以下是如…...

华为大咖说 | 浅谈智能运维技术

本文分享自华为云社区&#xff1a;华为大咖说 | 浅谈智能运维技术-云社区-华为云 本文作者&#xff1a;李文轩 &#xff08; 华为智能运维专家 &#xff09; 全文约2695字&#xff0c;阅读约需8分钟 在大数据、人工智能等新兴技术的加持下&#xff0c;智能运维&#xff08;AI…...

creo toolkit二次开发学习之获取任意选择模型作为元件,并进行获取约束等

获取任意选择模型作为元件进行操作前&#xff0c;先了解组件路径和程序集的构成&#xff1a;creo toolkit二次开发学习之程序集&#xff08;ProAsmcomp&#xff09;和装配体组件路径对象&#xff08;ProAsmcomppath&#xff09;-CSDN博客 代码如下 ProError test1() {ProError…...

sanitize-html 防止 XSS(跨站脚本攻击)

sanitize-html 是一个用于清理和验证 HTML 的 JavaScript 库&#xff0c;主要用于防止 XSS&#xff08;跨站脚本攻击&#xff09;。它允许你定义一套规则来决定哪些 HTML 标签和属性是可以被信任的&#xff0c;从而确保用户输入的内容不会包含潜在的恶意代码。 主要功能 HTML…...

【JavaEE】文件io

目录 文件类型 File概述 属性 构造方法 常用方法 Reader Writer InputStream OutputStream 字节流转字符流 通过Scanner读取InputStream 通过PrintWriter转换outputstream 示例 文件类型 从编程的角度看&#xff0c;文件类型主要就是两大类 文本&#xff08;文…...

FlinkPipelineComposer 详解

FlinkPipelineComposer 详解 原文 背景 在flink-cdc 3.0中引入了pipeline机制&#xff0c;提供了除Datastream api/flink sql以外的一种方式定义flink 任务 通过提供一个yaml文件&#xff0c;描述source sink transform等主要信息 由FlinkPipelineComposer解析&#xff0c…...

jenkins结合gitlab实现CI

Jenkins结合GitLab实现CI&#xff08;持续集成&#xff09; 持续集成&#xff08;Continuous Integration, CI&#xff09;是一种软件开发实践&#xff0c;开发者在代码提交后&#xff0c;系统会自动进行构建、测试&#xff0c;从而尽早发现问题。Jenkins和GitLab的结合可以高效…...

ES101系列09 | 运维、监控与性能优化

本篇文章主要讲解 ElasticSearch 中 DevOps 与性能优化的内容&#xff0c;包括集群部署最佳实践、容量规划、读写性能优化和缓存、熔断器等。 集群部署最佳实践 在生产环境中建议设置单一角色的节点。 Dedicated master eligible nodes&#xff1a;负责集群状态的管理。使用…...

【华为云Astro-服务编排】服务编排中图元的使用与配置

目录 子服务编排图元 子服务编排图元的作用 如何使用子服务编排图元 脚本图元 脚本图元的作用 如何使用脚本图元 记录创建图元 记录创建图元的作用 如何使用记录创建图元 记录删除图元 记录删除图元的作用 如何使用记录删除图元 记录查询图元 记录查询图元的作用…...

.NET 原生驾驭 AI 新基建实战系列(三):Chroma ── 轻松构建智能应用的向量数据库

在人工智能AI和机器学习ML迅猛发展的今天&#xff0c;数据的存储和检索需求发生了巨大变化。传统的数据库擅长处理结构化数据&#xff0c;但在面对高维向量数据时往往力不从心。向量数据库作为一种新兴技术&#xff0c;专为AI应用设计&#xff0c;能够高效地存储和查询高维向量…...

解锁Java线程池:性能优化的关键

一、引言 在 Java 并发编程的世界里&#xff0c;线程池是一个至关重要的概念。简单来说&#xff0c;线程池就是一个可以复用线程的 “池子”&#xff0c;它维护着一组线程&#xff0c;这些线程可以被重复使用来执行多个任务&#xff0c;而不是为每个任务都创建一个新的线程。​…...

在MATLAB中使用自定义的ROS2消息

简明结论&#xff1a; 无论ROS2节点和MATLAB运行在哪&#xff0c;MATLAB本机都必须拥有自定义消息源码并本地用ros2genmsg生成&#xff0c;才能在Simulink里订阅这些消息。只要你想让MATLAB或Simulink能识别自定义消息&#xff0c;必须把消息包源码(.msg等)拷到本机指定目录&a…...

Android四大组件通讯指南:Kotlin版组件茶话会

某日&#xff0c;Android王国举办Kotlin主题派对。Activity穿着Jetpack Compose定制礼服&#xff0c;Service戴着协程手表&#xff0c;BroadcastReceiver拿着Flow喇叭&#xff0c;ContentProvider抱着Room数据库入场。它们正愁如何交流&#xff0c;Intent举着"邮差"牌…...

设计模式杂谈-模板设计模式

在进入正题之前&#xff0c;先引入这样一个场景&#xff1a; 程序员A现在接到这样一个需求&#xff1a;这个需求有10个接口&#xff0c;这些接口都需要接收前端的传参&#xff0c;以及给前端返回业务状态信息。出于数据保密的要求&#xff0c;不管是前端传参还是最终参数返回都…...

Python 训练营打卡 Day 45

TensorBoard 简单来说&#xff0c;TensorBoard 是 TensorFlow 自带的一个「可视化工具」&#xff0c;就像给机器学习模型训练过程装了一个「监控屏幕」。你可以用它直观看到训练过程中的数据变化&#xff08;比如损失值、准确率&#xff09;、模型结构、数据分布等&#xff0c…...

软信天成:数据驱动型背后的人工智能,基于机器学习的数据管理

在数字化转型浪潮中&#xff0c;当代企业如同逆水行舟&#xff0c;不进则退。无数企业希望通过数字化转型捕获全新的市场机遇&#xff0c;改善财政状况&#xff0c;在未来市场竞争中占据一席之地。要想获得成功的数字化转型&#xff0c;关键因素在于具备可靠、及时的数据用以支…...