zoukankan      html  css  js  c++  java
  • 浅析SQL数据类型的隐式转换与显式转换以及隐式转换可能导致的问题

    一、隐式类型转换问题

    1、隐式类型转换:

      比如:SELECT 1 + '1';

    2、隐式类型转换的问题:

    (1)程序可读性差,且依赖数据库的隐式转换规则,效率差,会增加处理时间;且如果数据库升级,则程序可能无法正确执行;

    (2)有可能会导致索引失效;

    (3)有可能会导致意想不到的结果;

    3、显式类型转换:SELECT 1 + CAST('1' AS SIGNED INT);

    4、原则:尽量用显式类型转换

    5、隐式转换问题示例:

    (1)数值型 + 字符型

    SELECT 1+'1';           -- 结果:2
    SELECT CONCAT('北京',2008);    -- 结果:北京2008
    SELECT '北京' + 2008;       -- 结果: 可能2008,可能报错
    SELECT 'HELLO ' + 'WORLD!';    -- 结果:可能 0,可能报错

    (2)隐式类型转换导致索引失效

    CREATE TABLE teacher(
    teacher_id VARCHAR(50),
    teacher_name VARCHAR(50),
    id_no VARCHAR(50)
    );
    
    CREATE INDEX idx_teacher_id ON teacher(teacher_id);
    
    CREATE TABLE student(
    student_id INT,
    student_name VARCHAR(50),
    teacher_id INT
    );
    
    CREATE INDEX idx_teacher_id ON student(teacher_id);
    
    SELECT
    *
    FROM student a
    INNER JOIN teacher b
    ON a.teacher_id = b.teacher_id;
    
    -- 此时不会走索引,因为在teacher表中,teacher_id是varchar类型,而student表中teacher_id是int类型,
    -- 会做隐式类型转换,把varchar转为int类型;

    (3)隐式类型转换导致意想不到的结果

    SELECT 10/4;       -- 结果:2      解决:可以把分母分子乘以1.00,再运算
        
    SELECT COUNT(*) FROM table1;    -- count返回的是int类型,如果表中数据量超过count出来的数,就报错
    -- 解决:在count(*) 外面cast转换一下,转换为能保存结果的类型
    SELECT COUNT(*) FROM teacher WHERE teacher_name = 0;
    -- 为什么不是等价于:
    SELECT COUNT(*) FROM teacher WHERE teacher_name= '0';
    
    -- 因为隐式类型转换时,转的是左边而不是右边;
    
    -- 以下语句会返回两条信息,而不是一条,因为530102192005080114这串数字,已经超过了int类型的范围,
    -- 超过了int类型的范围就会转为float类型,等号两边都转为float类型,会丢精度,也就是最后一位数丢了,剩下的就相等了,就全返回了;
    
    SELECT COUNT(*) FROM teacher WHERE id_no = 530102192005080114;
    -- 等价于:
    SELECT COUNT(*) FROM teacher WHERE 
    CAST(id_no AS DECIMAL) = CAST(530102192005080114 AS DECIMAL);
    
    -- 在查询时把530102192005080114加上单引号就可以了;

    二、SQL 数据类型转换

      数据类型转换分为隐式转换和显式转换。

    1、显式转换:顾名思义就是使用函数进行数据类型转化,如cast、convert

    2、隐式转换问题

    -- 例子1
    SELECT 1+1’ –返回值为2
    
    -- 例子 2
    SELECT
    CASE
    WHEN 1 > 1 THEN 10
    WHEN 1 = 1 THEN10WHEN 1 < 1 THEN 10.2
    END    -- 返回值为10.2
    
    -- 例子3
    SELECT
    CASE
    WHEN 1 > 1 THEN 10
    WHEN 1 = 1 THEN ‘abc’
    WHEN 1 < 1 THEN 10.2
    END     -- 语法错误 

      在第一个例子中,'1' 被转换为 int 的 1 ;

      在第二个例子中,不管那个后面的条件成立,结果都被转换为decima;

      第三个例子由于‘ab’转换为decimal失败,所以报错。

      为什么呢?  ——  这是因为 sql server 中有多个数据类型在一个表达式中时会存在隐式的转换,各个数据类型的优先级如下:

    1、用户定义数据类型(最高)
    2、sql_variant
    3、xml
    4datetime
    5smalldatetime
    6float
    7real
    8decimal
    9money
    10smallmoney
    11bigint
    12int
    13smallint
    14tinyint
    15bit
    16ntext
    17text
    18image
    19timestamp
    20uniqueidentifier
    21nvarchar(包括 nvarchar(max))
    22nchar
    23varchar (包括 varchar(max))
    24char
    25varbinary(包括 varbinary(max))
    26binary(最低) 

    3、详细见:数据类型优先级 (Transact-SQL)  ——  https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2005/ms190309(v=sql.90)?redirectedfrom=MSDN

      当两个不同数据类型的表达式用运算符组合后,数据类型优先级规则指定将优先级较低的数据类型转换为优先级较高的数据类型。 如果此转换不是所支持的隐式转换,则返回错误。 当两个操作数表达式具有相同的数据类型时,运算的结果便为该数据类型。

      这里有一篇文章也说了这个 case when 里的隐式转换导致的问题,可以看下:《SQL Server有意思的数据类型隐式转换问题

  • 相关阅读:
    sqlite错误 Abort due to constraint violation column id is not unique id没开启自动增长
    字符串转为日期类型
    XPTable 一行添加数据 如果想添加多行 可以使用for循环
    在逮捕异常的时候 可以获取e.MESSAGE里面的信息 然后判断是什么异常
    C# 加载图片image (C#)Image.FromFile 方法会锁住文件的原因及可能的解决方法
    计算两个时间的前后 时间戳
    用C#语言写的多线程演示程序:两个线程,可以开始,可以暂停,可以恢复,可以清除。
    sqlite插入日期时候 出现18991230 0:00:00
    datagridview绑定dataset的时候 需要这一句
    WinForm 子线程修改主线程(UI线程)Control 【Z】
  • 原文地址:https://www.cnblogs.com/goloving/p/15222604.html
Copyright © 2011-2022 走看看