暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

插入"&"特殊字符的几种思考

689

一位铁杆朋友,今天问了个问题,写了一个Python程序,从文件读取数据,其中可能包含“&”这种特殊字符,为了让其能插入Oracle,需要做什么处理?


首先,我想问的问题,"&"字符在插入数据库的时候有什么特别之处?


在sqlplus下执行如下SQL,向表A插入记录“a&a”,他会提示我们“Enter value for a:”,输入变量a的值,此处输入空,则实际存储的,就是"a",

    SQL> create table a (id number, a varchar2(25));
    Table created.


    SQL> insert into a values(1'a&a');
    Enter value for a:
    old 1: insert into a values(1, 'a&a')
    new 1: insert into a values(1, 'a')


    1 row created.


    SQL> select * from a;
           ID   A
    ---------- -------------------------         
            1   a


    执 行show all,可以看到这行define "&" (hex 26),其实这个就是Oracle中用来识别自定义变量的设置,当SQL中包含"&"时,Oracle就会认为你要输入变量了,就像上面显示的 “Enter value for a:”,

      SQL> show all
      ...
      define "&" (hex 26)


      在sqlplus下,可以设置set define off,此时就关闭了自定义变量,他会将"&"看作是普通字符,直接使用"a&a",不会提示“Enter value for a:”,

        SQL> set define off


        SQL> insert into a values(1, 'a&a');
        1 row created.


        但是在python程序中,使用cx_Oracle连接Oracle数据库,并不支持执行set define off,原因就是cx_Oracle只支持标准SQL语句,这个set define off只是在sqlplus下才能执行的语句,

        The command "set define off" is not a SQL statement, but a SQLPlus statement. As such, it can only be executed in SQLPlus. Since cx_Oracle only processes SQL statements, this command is unnecessary in any case! If you are reading from a file that contains SQL statements that are normally run by SQL*Plus you'll need to filter these statements out.


        当然,你可以使用shell脚本,执行sqlplus就可以用set define off了,但是受限于实际,不能将Python程序转为shell。


        除此之外,还可以怎么做?


        我们能得到"&"的ASCII码是38,

          SQL> select ascii('&'from dual;
          ASCII('&')
          ----------
              38


          我们使用chr(38),代替"&",通过拼接字符串,就可以插入了,

            SQL> insert into a values(1'a'||chr(38)||'a');
            1 row created.


            SQL> select * from a;
            ID A
            ---------- -------------------------
                     1 a&a


            但是问题来了,Python程序可以读取行数据的时候,将"&"替换为'||chr(38)||',但是这只是一般的情况,当出现"&&",或者多个"&"的时候,可能要特殊的判断逻辑,才可以替换正确,有些复杂。


            有其他的方法么?



            我们换种思维,"&"字符直接入库,Oracle会将其认为是有特殊含义的,如果插入的不是"&",就可以解决了?


            步骤如下,

            1.Python读取行数据时,将字符串中"&"替换为其他的字符,例如"#",或者不可见字符(避免待替换字符就存在于字符串中)。

            2.插入Oracle时,将"#",replace替换为"&",如下所示,

              SQL> insert into a values(1, replace('a#c', '#', chr(38)));
              1 row created.


              SQL> select * from a;
              ID A
              ---------- -------------------------
              1 a&c


              这个方案就比较耐看了,一方面,是无需关注原始字符串中,到底存在几个连续的"&",要特殊的判断,另一方面,插入的时候,replace函数能通用,无需针对不同的输入选择特殊的逻辑,一个词概括,就是“通用”。


              参考:

              https://stackoverflow.com/questions/57470276/unable-to-set-define-off-in-cx-oracle

              http://blog.itpub.net/20750200/viewspace-706760/

              https://blog.csdn.net/dreary001/article/details/84355504


              近期热文:

              公众号600篇文章分类和索引

              Oracle ACE,一段不可思议的旅程

              Oracle 19c之RPM安装

              应用执行慢的问题排查路径

              ACOUG年会感想

              千万级表数据更新的需求

              探寻大表删除字段慢的原因

              一次Oracle bug的故障排查过程思考

              新增字段的一点一滴技巧

              对recursive calls的深刻理解

              《Oracle Concept》第三章 - 12

              一次惊心动魄的问题排查

              英超梦幻之行

              藤子不二雄博物馆之行

              传控Tiki-Taka战术解惑

              文章转载自bisal的个人杂货铺,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论