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

Postgresql数据库中通过函数实现将不确定列的数据插入到表中

在数据库操作中,经常会遇到需要将不确定列的数据插入到表中的情况。这个文章将详细介绍如何在 PostgreSQL 中通过函数来实现这一需求,记录一下。

一、需求概述

在实际应用中,可能会接收到一个包含数据的 JSON 字符串,需要将其插入到指定表中。同时,要处理表的主键问题,确保在数据中没有主键值时能自动生成并添加。此外,还需要考虑表可能位于不同的模式(schema)下,以及后续的数据更新操作。

二、实现分析

为了实现上述需求,需要利用 PostgreSQL 丰富的函数和操作符来处理 JSON 数据、获取表结构信息、生成主键值以及构建和执行 SQL 语句。

三、实现步骤

第一步:获取表的所有字段

使用 information_schema.columns 表获取指定表和模式下的所有列名,并存储在 all_column_names 数组中。

第二步:查找主键字段及数据类型

通过查询 information_schema.key_column_usage 和相关表来确定主键列名和数据类型。

第三步:如果 Json 没有主键字段,则给 Json 增加主键字段

将输入的 JSON 字符串转换为 JSONb 类型,并检查主键列在数据中是否存在。如果不存在且主键为整数类型,从表中获取最大值并加 1 作为主键值;如果主键为其他类型,则生成一个随机 UUID 作为主键值。之后创建包含主键的新 JSON 数据并与原数据合并。

第四步:构建插入语句的列和值

接下来,构建插入语句的列和值部分。遍历 all_column_names 数组,只添加数据中存在值的列到插入语句中。

第五步:插入

最后,执行构建好的插入语句,将数据插入到表中。

四、测试

为了验证函数的正确性,进行如下测试操作:

CREATE TABLE test_table (id VARCHAR(50) PRIMARY KEY,name VARCHAR(50),age INT
);CREATE TABLE test_table2 (id int PRIMARY KEY,name VARCHAR(50),age INT
);SELECT insert_data_to_table('{"name": "Alice", "age": 25,"id": "55655655" }', 'test_table');
SELECT insert_json_data('{"name": "Aliceb", "age": 26}', 'test_table');
SELECT insert_json_data('{"name": "Alicec", "age": 27}', 'test_table');
SELECT insert_json_data('{}', 'test_table2');

插入后的效果

五、结果

经过测试,上述函数能够成功地将不确定列的数据插入到表中,并根据给定的条件进行更新操作。在实际应用中,我们可以根据具体的业务需求灵活调整函数的参数和逻辑,以满足更多复杂的场景。

六、附:完整的函数

-- 插入数据函数
CREATE OR REPLACE FUNCTION insert_data_to_table(json_string TEXT, tName TEXT, SchemaName TEXT DEFAULT 'public')
RETURNS VOID AS $$
DECLAREall_column_names TEXT[];primary_key_column_name TEXT;primary_key_data_type TEXT;json_data JSONb;new_json_data jsonb;insert_statement TEXT;key_value TEXT;max_value INT;  -- 用于存储主键的最大值
BEGIN-- 第一步:获取表的所有字段SELECT array_agg(column_name) INTO all_column_namesFROM information_schema.columnsWHERE table_name = tName AND table_schema = SchemaName;-- 第二步:查找主键字段及数据类型SELECT kcu.column_name, data_type INTO primary_key_column_name, primary_key_data_typeFROM information_schema.key_column_usage kcuJOIN information_schema.columns col ON kcu.column_name = col.column_nameWHERE kcu.table_name = tName AND col.table_schema = SchemaName AND kcu.constraint_name IN (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = tName AND table_schema = SchemaName AND constraint_type = 'PRIMARY KEY');-- 第三步:如果 Json 没有主键字段,则给 Json 增加主键字段json_data := json_string::JSONb;IF primary_key_column_name IS NOT NULL AND json_data ->> primary_key_column_name IS NULL THENIF primary_key_data_type = 'integer' THEN-- 获取主键的最大值EXECUTE 'SELECT coalesce(max(' || primary_key_column_name || '), 0) + 1 FROM ' || SchemaName || '.' || tName INTO max_value;key_value := max_value;  -- 使用获取到的最大值加 1 作为主键值ELSEkey_value := gen_random_uuid()::TEXT;END IF;new_json_data := concat('{', '"', primary_key_column_name, '": "', key_value, '"}')::jsonb;json_data := (new_json_data || json_data);END IF;-- 第四步:构建插入语句的列和值insert_statement := 'INSERT INTO ' || SchemaName || '.' || tName || ' (';FOR i IN 1..array_length(all_column_names, 1) LOOPIF json_data ->> all_column_names[i] IS NOT NULL THENinsert_statement := insert_statement || all_column_names[i] || ', ';END IF;END LOOP;insert_statement := substring(insert_statement, 1, length(insert_statement) - 2) || ') VALUES (';FOR i IN 1..array_length(all_column_names, 1) LOOPIF json_data ->> all_column_names[i] IS NOT NULL THENinsert_statement := insert_statement || quote_literal(json_data ->> all_column_names[i]) || ', ';END IF;END LOOP;insert_statement := substring(insert_statement, 1, length(insert_statement) - 2) || ')';-- 第五步:插入RAISE NOTICE '%', insert_statement;EXECUTE insert_statement;
END;
$$ LANGUAGE plpgsql;

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • c++中std::endl 和“\n“ 这两个换行符有什么区别
  • uniapp——列表图片加载太多且空间占用太大的处理方法(降低清晰度)
  • git的基本操作和原理
  • MoE-LLaVA: Mixture of Experts for Large Vision-Language Models
  • Elastic Observability 8.15:AI 助手、OTel 和日志质量增强功能
  • Filebeat+Kafka+ELK
  • RabbitMQ再回首--往事如梦
  • 代码随想录算法训练营第45天|LeetCode 115.不同的子序列、583. 两个字符串的删除操作、72. 编辑距离
  • Netty技术全解析:DelimiterBasedFrameDecoder类深度解析
  • MySQL增删改查(基础)
  • Java入门基础17:集合框架2(可变参数、Collections、Map系列集合、集合的嵌套、Stream流)
  • 不知道msvcp140.dll丢失的解决方法有哪些?看这篇文章教你修复丢失的msvcp140.dll
  • 8月9日笔记
  • Leetcode 17.电话号码的字母组合
  • SpringBoot自动装配原理
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • [译]前端离线指南(上)
  • C++类的相互关联
  • Computed property XXX was assigned to but it has no setter
  • ES10 特性的完整指南
  • flutter的key在widget list的作用以及必要性
  • Making An Indicator With Pure CSS
  • MySQL-事务管理(基础)
  • October CMS - 快速入门 9 Images And Galleries
  • orm2 中文文档 3.1 模型属性
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • Redis字符串类型内部编码剖析
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • Spring声明式事务管理之一:五大属性分析
  • Vue 2.3、2.4 知识点小结
  • Vue UI框架库开发介绍
  • 阿里云Kubernetes容器服务上体验Knative
  • 第2章 网络文档
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 前端_面试
  • 前端面试之CSS3新特性
  • 深度学习在携程攻略社区的应用
  • 小程序测试方案初探
  • 用mpvue开发微信小程序
  • 源码安装memcached和php memcache扩展
  • 阿里云ACE认证之理解CDN技术
  • # Panda3d 碰撞检测系统介绍
  • #Z0458. 树的中心2
  • #Z2294. 打印树的直径
  • %@ page import=%的用法
  • (1)常见O(n^2)排序算法解析
  • (2022 CVPR) Unbiased Teacher v2
  • (C++二叉树05) 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (day 12)JavaScript学习笔记(数组3)
  • (JS基础)String 类型
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (WSI分类)WSI分类文献小综述 2024
  • (附源码)springboot优课在线教学系统 毕业设计 081251