数据库解析一维和二维简易JSON,

news2024/9/21 0:35:59

项目还在使用Oracle11,不支持后续官方的json解析方式, 在 前年、去年、今年 接连 遇到json解析问题后(其实是公司的轮子效率太慢,太复杂,决定自己造个轮子,看看到底为什么慢,是不是真的很复杂)

关于要不要自己再造轮子,其实还是比较犹豫的,后来不断遇到相似问题,才促使我自己搞一搞。

断断续续搞了1个礼拜多,算是初步有结果了。

至于说为什么JSON不放JAVA代码解析后再传数据库,项目总归是有各种各样的限制,以及人力物力的限制,不得不在数据库自己解析。

------------------------------------------------------------------------------------------------------------------------------

以上都是废话,

         如果你的JSON很复杂,请跳过本文。 这边只支持简易JSON。

        复杂JSON还未实现,也肯定不应该在数据库里处理 。

以下是代码实现

------------------------------------------------------------------------------------------------------------------------------

功能实现: json数组解析成sql语句,通过拼接sql可以执行

                已支持 字符串、数值、布尔值(转成1和0)、null;

实现方式:无循环嵌套,通过状态+队列来判断key和value ,最后使用sql语句,对数据进行整合

限制:1.由于表结构格式不一致,暂时没有实现value是 对象和数组的实现方式

           2. 目前使用场景还 比较单一,未作兼容性处理及错误判断.

正文

JSON数据:

[ { "key" : "valu e ","key2":"\\a\\\\\"","key3":4.43,"key4":true,"key5": null  },{"key5":Null,"key":"1","key3":0.02,"key4":false,"key2" : "2[{:," }] 

 生成代码:

SELECT *
  FROM (SELECT '1' AS KEY, '2[{:,' AS KEY2, 0.02 AS KEY3, 0 AS KEY4, NULL AS KEY5
          FROM DUAL
        UNION ALL
        SELECT 'valu e ' AS KEY, '\\a\\\\\"' AS KEY2, 4.43 AS KEY3, 1 AS KEY4, NULL AS KEY5
          FROM DUAL) V_JSON


 生成代码查询:

查询效率:  大约0.09S

下面是代码, 使用Oracle来处理的,使用到的函数是 SUBSTR , LTRIM、 TRIM 、 LISTAGG

如果是其他数据库应该都有替代的函数, 稍微改下就可以用


DECLARE
  --字符串、数值、布尔值、null、对象和数组
  V_JSON VARCHAR2(2000) := ' [ { "key" : "valu e ","key2":"\\a\\\\\"","key3":4.43,"key4":true,"key5": null  },{"key5":Null,"key":"1","key3":0.02,"key4":false,"key2" : "2[{:," }] ';

  --不支持参数值是对象和数组的情况
  --V_JSON      VARCHAR2(2000) := ' [ { "key" : "valu e ","key2":"\\a\\\\\"","key3":4,"key4":true,"key5":[1,2,3,4]},{"key":"1","key3":2,"key4":false,"key2" : "2[{:,","key5":[342,3,2]}] ';

  V_LENGTH INT; --字符串总长度
  V_STR    VARCHAR2(10); --当前字符
  V_ZT     INT := -1; --状态 0 正常, -1 忽略

  V_STR_S VARCHAR2(10); --上一字符
  V_ZT_S  INT := -1; --上一字符 状态 0 正常, -1 忽略

  V_SQL     VARCHAR2(3000); --解析出来的SQL
  V_SQL_OUT VARCHAR2(3000); --输出语句 
  V_WORD    VARCHAR2(3000); --字符串key 或value

  V_CHAT_TEMP VARCHAR2(3); --临时字符
  V_CHAT      VARCHAR2(3000); --字符栈,先进后出
  V_CHAT_ALL  VARCHAR2(3000); --所有字符

  V_I         NUMBER := 0;
  V_NUM_ARRYR NUMBER := 0; --数组序号
  V_NUM_KEY   NUMBER := 0; --key-value 序号
BEGIN

  --1. 
  V_LENGTH := LENGTH(V_JSON);
  FOR V_I IN 1 .. V_LENGTH LOOP
    V_STR := SUBSTR(V_JSON, V_I, 1);
  
    --DBMS_OUTPUT.PUT_LINE(V_I || '=' || V_STR);
  
    --1.处理反斜杠
    IF (V_STR_S = '\' AND V_ZT_S = 0) THEN
      V_STR_S := V_STR;
      V_ZT_S  := -1;
      V_WORD  := V_WORD || V_STR;
      CONTINUE;
    ELSE
      V_ZT := 0;
    END IF;
  
    --2.处理双引号
    IF SUBSTR(V_CHAT, 1, 1) = '"' THEN
      V_WORD := V_WORD || V_STR;
      IF V_STR = '"' THEN
        V_CHAT := SUBSTR(V_CHAT, 2, LENGTH(V_CHAT) - 1);
        --DBMS_OUTPUT.PUT_LINE('V_CHAT=' || V_CHAT);
      END IF;
    
      V_STR_S := V_STR;
      V_ZT_S  := V_ZT;
      CONTINUE;
    END IF;
    --上一个字符状态
    V_STR_S := V_STR;
    V_ZT_S  := V_ZT;
  
    IF V_STR = '{' THEN
      V_CHAT     := V_STR || V_CHAT;
      V_CHAT_ALL := V_CHAT_ALL || V_STR;
      --DBMS_OUTPUT.PUT_LINE('V_CHAT=' || V_CHAT);
    ELSIF V_STR = '[' THEN
      V_CHAT     := V_STR || V_CHAT;
      V_CHAT_ALL := V_CHAT_ALL || V_STR;
      --DBMS_OUTPUT.PUT_LINE('V_CHAT=' || V_CHAT);
    ELSIF V_STR = '}' THEN
      V_CHAT     := SUBSTR(V_CHAT, 2, LENGTH(V_CHAT) - 1);
      V_CHAT_ALL := V_CHAT_ALL || V_STR;
    
      IF SUBSTR(V_CHAT_ALL, LENGTH(V_CHAT_ALL) - 1, 1) = ':' THEN
        DBMS_OUTPUT.PUT_LINE('V_VALUE=' || V_WORD);
        V_SQL := V_SQL || ' UNION ALL SELECT ''' || V_WORD || ''' AS V ,' || V_NUM_KEY ||
                 ' AS N, 2 AS TYPE, ' || V_NUM_ARRYR || ' AS J  FROM DUAL';
      END IF;
    
      IF SUBSTR(V_CHAT, 1, 1) = '[' THEN
        V_NUM_ARRYR := V_NUM_ARRYR + 1;
      END IF;
    
      V_NUM_KEY := 0;
      --DBMS_OUTPUT.PUT_LINE('V_CHAT=' || V_CHAT);
    ELSIF V_STR = ']' THEN
      V_CHAT     := SUBSTR(V_CHAT, 2, LENGTH(V_CHAT) - 1);
      V_CHAT_ALL := V_CHAT_ALL || V_STR;
      --DBMS_OUTPUT.PUT_LINE('V_CHAT=' || V_CHAT);
    ELSIF V_STR = ':' THEN
      V_CHAT_ALL := V_CHAT_ALL || V_STR;
      DBMS_OUTPUT.PUT_LINE('V_KEY=' || V_WORD);
      V_SQL  := V_SQL || ' UNION ALL SELECT ''' || V_WORD || ''' AS V ,' || V_NUM_KEY ||
                ' AS N , 1 AS TYPE, ' || V_NUM_ARRYR || ' AS J  FROM DUAL';
      V_WORD := '';
    ELSIF V_STR = ',' THEN
      V_CHAT_ALL := V_CHAT_ALL || V_STR;
      IF SUBSTR(V_CHAT_ALL, LENGTH(V_CHAT_ALL) - 1, 1) = ':' THEN
        DBMS_OUTPUT.PUT_LINE('V_VALUE=' || V_WORD);
        V_SQL := V_SQL || ' UNION ALL SELECT ''' || V_WORD || ''' AS V ,' || V_NUM_KEY ||
                 ' AS N , 2 AS TYPE, ' || V_NUM_ARRYR || ' AS J  FROM DUAL';
      END IF;
      V_WORD := '';
      IF SUBSTR(V_CHAT, 1, 1) = '{' THEN
        V_NUM_KEY := V_NUM_KEY + 1;
      END IF;
    ELSIF V_STR IN ('"') THEN
      V_CHAT := V_STR || V_CHAT;
      V_WORD := V_WORD || V_STR;
      --DBMS_OUTPUT.PUT_LINE('V_CHAT=' || V_CHAT);
      V_WORD := V_STR;
    ELSIF V_STR IN (' ') THEN
      --  DBMS_OUTPUT.PUT_LINE('空格');
      V_STR_S := V_STR;
    ELSE 
      V_WORD := V_WORD || V_STR;
    END IF;
  
  END LOOP;

  V_SQL := LTRIM(V_SQL, ' UNION ALL');
  --JSON结果转 输出语句
  V_SQL := ' WITH A AS ( ' || V_SQL || ' )
,b as (SELECT  A.J,A.N
, case when a_v.v like ''"%"'' then ''''''''|| substr(a_v.v,2,length(a_v.v)-2) || '''''''' 
  else  case when TRIM(upper(a_v.v)) in ( ''TRUE'') THEN ''1'' when  TRIM(upper(a_v.v)) in ( ''FALSE'')  then ''0'' else a_v.v END end  as v_param 
,substr(a.v,2,length(a.v)-2)  as v_key
 FROM A  LEFT JOIN A A_V ON A_V.N = A.N AND A_V.TYPE =2 AND A_V.J=A.J
WHERE  A.TYPE = 1  )
,c as (select  '' select '' || listagg( v_param ||'' as '' || v_key ,'','')  within group( order by v_key) || '' from dual '' as s 
from b  group by j  )
select ''SELECT * FROM ( ''||  listagg( c.s,'' union all '')  within group( order by null )  || '') V_JSON ''  as s 
from c ';

  EXECUTE IMMEDIATE V_SQL
    INTO V_SQL_OUT;

  DBMS_OUTPUT.PUT_LINE('V_SQL_OUT=');
  DBMS_OUTPUT.PUT_LINE(V_SQL_OUT);
END;

PS : 欢迎各个小伙伴积极交流  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1945427.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络八股文(四)

目录 61.客户端调用close()后的断开流程是怎样的? 62.没有accept可以建立TCP连接吗? 63.没有listen可以建立TCP连接吗? 64.什么是TCP半连接队列(SYN队列)和全连接队列(accept队列)&#xff…

质量问题到底是谁的责任?

在竞争日益激烈的市场环境中,产品质量是企业生存与发展的基石。每当谈及生产企业的质量问题,我们往往不由自主地思考:在这一复杂而精细的生产链条中,究竟是谁该为质量问题负责? 必须明确一个无可争议的事实&#xff1…

MySQL多实例的配置

步骤1 环境准备 安装多实例数据库 1)安装好数据库mariadb yum -y install mariadb-server 2)创建mysql多实例数据文件目录 mkdir /data/mysql/3307/{data,etc,socket,log,bin,pid} -pv mkdir /data/mysql/3308/{data,etc,socket,log,bin,pid} –pv ch…

51单片机15(直流电机实验)

一、序言:我们知道在单片机当中,直流电机的控制也是非常多的,所以有必要了解一些这个电机相关的一些知识,以及如何使用单片机来控制这个电机,那么在没有学习PWM之前,我们先简单的使用GPIO这个管脚来控制电机…

【MySQL】Ubuntu22.04 安装 MySQL8 数据库详解

🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《C》 《Linux》《MySQL》《Qt》 ❤️感谢大家点赞👍收藏⭐评论✍️ 一、安装目录 1.1 更新软件源 sheepAron:/root$ sudo apt update1.2 安装mysql_ser…

手持式气象监测设备

手持式气象监测设备以其小巧轻便、功能齐全的特点,逐渐成为了现代气象观测的便携新选择。 一、手持式气象监测设备的优势 手持式气象监测设备最大的优势在于其便携性。相比传统的气象监测站,手持式气象监测设备体积小巧、重量轻,用户可以轻松…

聊一聊 Node.js V22.5 有啥重要更新

大家好,今天我们来聊聊 Node.js 最新发布的 V22.5 版本。作为一名开发者,每次看到新的版本更新,总是让人期待不已。V22.5 中新增了许多强大且实用的功能,让我们的开发工作更加高效便捷。在这篇文章中,我们将重点讨论以…

压测实操--kafka-consumer压测方案

作者:九月 环境信息: 操作系统centos7.9,kafka版本为hdp集群中的2.0版本。 Consumer相关参数 使用Kafka自带的kafka-consumer-perf-test.sh脚本进行压测,该脚本参数为: thread:测试时的单机线程数&…

心率血氧传感器 - 从零开始认识各种传感器【第十三期】

1、什么是心率血氧传感器 心率传感器是一种用于测量人体心跳频率的设备或传感器。由于脉搏或者心率是生命体征的重要参数之一,所以心率测量是目前可穿戴产品必备的一个测量和健康监控功能。 而血氧传感器是一种用于测量人体血液中氧气饱和度的设备或传感器。血氧饱…

c# 端口监控 Helper 以及写一个端口监控工具

c# 端口监控 Helper 以及写一个端口监控工具 介绍核心代码:工具完整编码:1、编写界面2、打开定时控件的属性设置。3、编写定时控件的 Tick 事件结果(运行效果) 介绍 由于最近做上架比较多,会经常来确保服务器的服务&a…

分享从零开始学习网络设备配置--任务6.1 实现计算机的安全接入

项目描述 随着网络技术的发展和应用范围的不断扩大,网络已经成为人们日常生活中必不可少的一部分。园区网作为给终端用户提供网络接入和基础服务的应用环境,其存在的网络安全隐患不断显现出来,如非人为的或自然力造成的故障、事故&#xff1b…

第八讲:Sysmac Studio控制器设置

控制器设置 一、控制器设定-操作设置 1、启动模式(运行模式/编程模式) 控制器上电后,希望程序运行还是不运行。如果说希望程序运行,那么就选择运行模式。如果说希望上电后程序不运行就选择编程模式。 通常情况下选运行模式可能会比较多一些。 2、SD内存卡设置 当控制…

科研绘图系列:R语言和弦图 (Chord diagram)

介绍 和弦图(Chord Diagram)是一种用于展示多个实体之间相互关系的数据可视化方法。它通常用于表示网络或系统中不同节点(实体)之间的连接强度或流量。和弦图由一个圆形布局组成,每个节点在圆周上占据一个扇形区域,节点之间的连接通过圆内的线条(和弦)来表示。 特点:…

获取本地时间(Linux下,C语言)

一、函数 #include <time.h> time_t time(time_t *tloc);函数功能&#xff1a;获取本机时间&#xff08;以秒数存储&#xff0c;从1970年1月1日0:0:0开始到现在&#xff09;。返回值&#xff1a;获得的秒数&#xff0c;如果形参非空&#xff0c;返回值也可以通过传址调用…

判断字符串,数组方法

判断字符串方法 在JavaScript中&#xff0c;可以使用typeof操作符来判断一个变量是否为字符串。 function isString(value) {return typeof value string; } 判断数组 在JavaScript中&#xff0c;typeof操作符并不足以准确判断一个变量是否为数组&#xff0c;因为typeof会…

Soul App创始人张璐团队参与公益活动,帮助年轻人正视并管理情绪需求

最近,“脆皮年轻人”在社交平台上持续走红。该词指年轻人常因别人一些无意的动作而导致身体或心理创伤,反映出“Z世代”年轻人面临着心理健康挑战。在此背景下,Soul APP创始人张璐团队携手上海市精神卫生中心(宛平南路600号),共同发起了一场别开生面的青年心理健康公益活动,旨在…

JDBC操作MySQL数据

一准备、 1、首先在IDEA中导入导入包&#xff1a;mysql-connector-java-8.0.23 2、写初始化语句 &#xff08;1&#xff09;在目录下找到driver类 &#xff08;2&#xff09;在JDBCUtil函数中把驱动器的类路径改掉 ①打开driver类 ②按住类名 Driver用快捷键 CtrlAltshiftC …

学懂C语言(十八):C语言中数组及其应用

目录 一、数组的概念 二、数组的声明、初始化及访问 1、声明 2、初始化 3、访问数组元素 三、数组的应用 1. 存储和处理数据 2. 字符串处理 3. 多维数组 4. 函数参数 5、注意事项 一、数组的概念 C语言中的数组是一种数据结构&#xff0c;用于存储一…

开源邮箱套件介绍系列1:SOGo

项目网站&#xff1a;SOGo | Free Open Source Webmail 提示&#xff1a;如下内容大部分来自官方网站&#xff0c;通过AI智能翻译而来。 1. SOGo功能概述 SOGo提供了多种访问日历和消息数据的方式。您的用户可以使用网页浏览器、Microsoft Outlook、Mozilla Thunderbird、Ap…

连接hive库增加相关包

连接hive库增加相关包 例如&#xff1a;java.lang.NoClassDefFoundError: com/ctc/wstx/io/InputBootstrapper org.apache.hadoop.hive.common.auth.HiveAuthUtils java.lang.NoClassDefFoundError: org/codehaus/stax2/XMLInputFactory2