[数据库]SQL的cast函数实际使用场景

业务场景:

        现在需要对 用户钱包流水记录表  sysadmin_wallet_flow_record   (以下简称:wf表) 

进行 批量新增数据  , wf表 有几个重要字段 pro_money(操作前金额) 和 after_money (操作后金额)和remarks(流水记录备注)

新增完数据后 需要在前端视图页面 ,能看到这些刚刚新增的钱包流水记录,大概如下:

而查询的列表的接口 queryWalletFlowRecordList接口   则需要保证查询出来的记录是一个线性顺序

 线性顺序的定义:

上1条记录的after_money的值 ,  必须是 下1条记录的pro_money的值

以及 最后1条记录的after_money 必须是 这个用户钱包总金额(total_money)的值

遇到的问题: 

        由于wf表不是本人设计的 ,并且之前的业务也不是我写的 , 而且最主要的 ,之前新增这个流水记录时 ,都是1条条新增的,所以每条数据的创建时间都是不一样的 ,这是正常的, 那么此时queryWalletFlowRecordList接口 , 只需要根据创建时间createTime排序 就可以完成线性顺序排序的需求, 也就是查询主表的sql  只需要这样写:

order by created_time desc

        但是我现在写的新的业务,  是批量新增这个钱包流水记录的, 所以1个用户一次性会新增多个记录, 也就导致每个记录的创建时间是一样的  ,结果这些数据加到数据库之后, 我再去看前端的列表 ,此时列表的顺序就不满足线性顺序的需求了  因为所有的创建时间都是一样的 ,列表就是乱的.

可能到这里就有人想问了:

"就算创建时间一样的,  那么MySQL也可以根据表的原顺序 返回数据列表呀?  所以你只要保证插入数据时顺序是对的就ok " 

但我想说 , 这个说法不完全正确 , 我这边经过一些测试后  得到的一个答案是这样的:

        在SQL查询时 如果指定了一个排序规则 ,例如created_time desc  但是2个数据的created_time又是完全一样的 , 那么此时MySQL返回的数据顺序 , 其实会受到其他因素(索引?字节大小?主键id?) 的影响, 这个没有规律, 也就是是说 并不是完全按照表内数据的顺序返回 

这点我也问过GPT  但它的回答只能做个小小小小...参考 , 毕竟它老墙头草了 你说它错了 它就和你道歉  并且立马改口 

这里留下一个小疑惑:  如果完全未指定排序规则呢? 那么会完全按照表中的顺序返回吗?

ok , 解决上面的问题之后 , 可能又有人想问了 

"你把创建时间弄成不一样不就行了?"  

我只能说 不是不行  而是要弄的话 风险太大   为什么呢 因为之前的 createTime一直是自动填充的  , 并且填充有2个策略

1个是数据库表字段自己定义的, 如下:

 `created_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',

1个是mybatis-plus框架定义的, 如下:

@TableField(fill = FieldFill.INSERT)
private Date createdTime;

所以说buff属实是拉满了  , 然后这里我也测试过 , 我自己写入了创建时间 , 结果您猜怎么着? 嘿 被覆盖了  

但是 , 是哪个策略覆盖的, 我也不清楚 因为这2个策略的优先级 , 以及具体详细的使用方式 我不知道

  但我估计大概率是DEFAULT CURRENT_TIMESTAMP(3) 这个函数覆盖的  

         原因: 

  mybatis-plus是最新的技术 不可能不去对值做非空判断 , 就直接强行填充 

  而DEFAULT CURRENT_TIMESTAMP(3) 这个函数非常老,

  一些新版的MySQL都不支持这个函数了

  所以我觉得是DEFAULTCURRENT_TIMESTAMP(3) 覆盖的

        所以说到这里 , 你应该明白了 , 如果我不想让他覆盖  大概率要去修改表结构   这玩意谁敢啊 到时候别的业务出了问题 我死都不知道怎么死

吐槽:

        为什么设计wf表时  不设计一个编号字段!!!!   有了编号字段直接根据编号排序就好了 

(编号直接用时间戳填充,每次时间戳保证让其不一样就行了 可以+1毫秒)  

        好吧即使没有编号字段  为什么主键不用自增  像这种钱包流水记录表 , 很明显要用自增类型的主键吧. 啊喂!!!

给出的解决方案:

第一种方法(弃用):   更改主键的填充类型为递增  (改源码) 

        弃用原因: 我不想死


第二种方法(弃用):   使自动填充时间变得无效 , 而是手动指定创建时间的值  (改源码,改表结构)   

        弃用原因: 我想活


第三种方法(弃用):    修改排序条件 : 当创建时间createTime相同  , 根据  after_money 降序排序  

<--  也就是由 -->
order by created_time desc 
<--  改为 -->
order by created_time desc , after_money desc  

说一说 为什么我会想到这个解决方案 ,  因为我这次  新增的钱包流水记录全部是正向的(增加金额) 没有负向的(减少金额)   所以每次的after_money是最接近最后的总金额的 ,  那么我根据它降序排序 其实就能保证线性顺序  

弃用原因:

        对后续业务侵入, 完全是为了满足查询当前业务产生的钱包流水记录而生 ,  后续其他业务可能因为这个排序条件 , 导致更难查询  , 因为后续其他业务 , 可能有负向的钱包流水记录产生 , 而此时after_money desc 完全没有任何合理的理由对其他业务解释 为什么是要这样排序


第四种方法(采用):  修改排序条件 : 当创建时间createTime相同   根据 remarks(流水记录备注) 字段 降序排序   

<--  也就是由 -->
order by created_time desc 
<--  改为 -->
order by created_time desc , remarks desc  

首先 remarks没有在前端展示过 (起码我没看到QAQ) 

其次 remarks 存储的值很多样: 

      如果是售后产生的记录 它会存储 "售后订单编号:zzzz123456575" 

      如果是火车票产生的记录 它会存储: "购买火车票"

      如果是购买商品产生的记录 它会存储:"商品订单编号:aaaa123456575"

那么我只需要在我的这个业务 , 构建钱包流水记录时 为每个数据的remarks字段写入不同的时间戳 , 然后再把排序sql改为上面这个SQL

这样的话 , 我用remarks字段排序也没问题吧  我觉得是说的过去的  毕竟这个字段本来就是设计出来随便造的   

但是, 但是 , 问题又来了  remarks 是 varchar类型的 !!! 

提问: 

如果varchar类型的字段  存储的是纯数字  那么怎么根据这个字段进行数字型的排序?  而不是根据ascll码  (如果remarks是varchar类型 直接写 remarks desc , 其实是根据这个字符串首个字符的 ascll码进行排序  , 这是完全不能满足当前业务需求的 )

答案就是SQL的cast函数   ,  cast函数可以把一个类型转为另外一个类型

没想到吧 这里才开始正文  真辛苦你看到这了 .....      

因此最终代码改为

<--  由 -->
order by created_time desc 
<--  改为 -->
order by created_time desc , CAST(remarks AS SIGNED) desc

并且我在这里还测试了其他情况(做过测试):

" CAST(remarks AS SIGNED) desc "

代表将remarks字段(varchar类型) 转为数字 并且进行降序排序

如果remarks字段不包含数字          例如: ABC你好        那么不会参与排序

如果remarks字段是前部分是数字  例如: 123ABC你好   那么只会使用123 作为排序参与值

如果remarks字段是后部分是数字  例如: ABC你好123   那么不会参与排序

如果remarks字段是中部分是数字  例如: ABC123你好   那么不会参与排序

总结:

设计扩展性很强的表时  尽量设计冗余字段, 或者设计一些类似上面这种 remarks字段

设计一些具有线性记录的表时, 必须考虑编号和排序问题

其他:

第一次写 , 写的有点乱  可能就我自己看得懂  如果有人愿意阅读的话  请见谅

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值