暂无图片
暂无图片
6
暂无图片
暂无图片
1
暂无图片

SQL方言:传统关系型数据库下的方言对比

原创 每天译点晓知识 2023-06-02
672

前言:

技术多元化是一个趋势,多语言并存,多数据库适配,多环境兼容><

场景:

当从SQL Server数据库迁移到MySql数据库或者Oracle数据库,甚至国产化数据库,不同数据库之间可以自定义切换?

此时,在不同版本类型的数据库下,各自独有的SQL方言,并不能同时在多个数据库中共用,那如何能够做到尽可能复用,毕竟你不能改变ta,那只有适配。而如何适配又能够做到最小改造量?

SQL方言对比:

这里,我们来看看各大数据库厂商下分页SQL的写法,其中pageNo表示页码数,pageSize表示一页包含的记录数,

SQL Server (row_number 关键字)

select top pageSize * 
from (select row_number() 
over(order by id asc) as rownumber,* 
from yx_test) temp_row
where rownumber>((pageNo-1)*pageSize);

例:分页查询第二页,每页展示10条记录
select top 10 * 
from (select row_number() 
over(order by id asc) as rownumber,* 
from yx_test) temp_row
where rownumber > 10;
复制

MySql (limit 关键字分页-结合mybatis-xml写法)

limit (pageNo-1),pageSize

<select id="pageRecords" resultMap="BaseResultMap" databaseId="mysql">
      select
      <include refid="base_column">
          <property name="alias" value="T."/>
      </include>
      from Test T
      <where>
          <if test="null != idCard and '' != idCard">
              and T.ID_CARD = #{idCard, jdbcType=VARCHAR}
          </if>
          and t.CANCEL_FLAG = '0'
      </where>
      order by T.ID DESC
      limit #{start},#{end}
</select>
复制

Oracle (rownum 伪列分页-结合mybatis-xml写法)

    <select id="pageRecords" resultMap="BaseResultMap" databaseId="oracle">
            select * from (select row_.*, rownum rownum_
            from (select t.* from (select
            <include refid="base_column">
                <property name="alias" value="T."/>
            </include>
            from yx_test T
            <where>
                <if test="null != idCard and '' != idCard">
                    and T.ID_CARD = #{idCard, jdbcType=VARCHAR}
                </if>
                and t.CANCEL_FLAG = '0'
            </where>
            order by T.ID DESC)t where rownum <![CDATA[<=]]> #{end}) row_)
            where rownum_ <![CDATA[>=]]> #{start}
    </select>
复制

上述,仅仅给出了部分的分页SQL方言写法,还有,像我们常用的一些日期函数,更多请参考->多数据库适配 | 记一次数据源从Oracle到MySQL兼容切换历程

MySql (date()函数、date_sub()函数)

例:删除一周前创建的历史数据,仅保留最近一周的日志数据
delete from yx_test_log
           where id <= (
           select id from (
           select max(id) as id from yx_test_log
	   where date(create_time) <= date(date_sub(now(), interval 7 day))
           ) as a);
复制

SQL Server (DateDiff()函数、getdate()函数)

例:删除一周前创建的历史数据,仅保留最近一周的日志数据
delete from yx_test_log where DateDiff(dd,create_time,getdate()) > #{day}
复制

SQL方言适配:

通过对比各大DBMS数据库厂商,由此可见各自的函数并不能相互兼容。这里,我们就来给一些多数据库适配的一些CASE:

自定义指定 databaseId:

1685351762480.jpg

自定义SQL拦截器:

image.png

最后:

不论是基于ORM关系映射框架去构造SQL,还是基于Mybatis插件的思想->根据当前数据库databaseId,拦截SQL,加入各自数据库的SQL方言函数兼容,我们需要能够做到支持业务灵活配置-不同环境可走不同配置,并且可插拔式-在需要时开启。

诚然,在技术多元化的今天,多语言并存,多数据库适配,多环境兼容,这已是趋势!这无不都告诉我们各位开发者,在书写SQL不仅需要规范,比较生僻且独有的SQL语法尽量规避,CRUD等操作都尽量基于框架去开发。尤其是在BI报表业务中,很多需要对数据层面的过滤、组装、转换其实可以根据实际情况放在业务代码层面去处理->或许Lambda表达式值得一试。

最后修改时间:2023-06-26 13:29:27
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
1人已赞赏
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

星星之火
暂无图片
1年前
评论
暂无图片 0
像在MySql中varchar是表示字符,varchar(50)表示可以存放50个字符,例如,DM的默认跟Oracle是一样的,varchar(50)表示50个字节。这就意味着,50个字节,如果存中文,在utf-8的字符集下,只能存最多16个。所以,如果MySql库到DM,varchar类型,需特别留意一下。
1年前
暂无图片 点赞
评论