代码之家  ›  专栏  ›  技术社区  ›  Salman Arshad

字符串比较的意外结果

  •  9
  • Salman Arshad  · 技术社区  · 6 年前

    我无法理解以下行为:

    WITH tests(min, val, max) AS (
        SELECT 'a', 'x', 'z' UNION ALL
        SELECT '',  'x', 'z' UNION ALL
        SELECT 'a', 'x', '~'
    )
    SELECT min, val, max, CASE WHEN val BETWEEN min AND max THEN 'PASS' ELSE 'FAIL' END AS result
    FROM tests
    

    结果:

    | min | val | max | result |
    |-----|-----|-----|--------|
    | a   | x   | z   | PASS   |
    |     | x   | z   | PASS   |
    | a   | x   | ~   | FAIL   |
    

    的字符代码 x ~ 分别为120和126。我知道的每种编程语言 'x' < '~' is true . 那么SQL是什么呢?

    我在不同的RDBMS上得到相同的结果。在SQL Server上,使用以下排序规则:

    Latin1 General,不区分大小写,区分重音, 不区分假名类型,不区分全半角

    3 回复  |  直到 6 年前
        1
  •  4
  •   rory.ap    6 年前

    在我对你问题的评论中,我问你 collation 你在用。你说“假定违约”,但没有“违约”。“默认”取决于数据库和服务器的设置方式。我在我的SQL服务器上运行了您的实验,碰巧得到了与您相同的结果,但这只是一个巧合。

    运行实验的SQL服务器和数据库正在使用 SQL_Latin1_General_CP1_CI_AS 校对。基于此事实,以下是字符顺序:

    http://collation-charts.org/mssql/mssql.0409.1252.Latin1_General_CI_AS.html

    注意蒂尔德 ~ 之前 字母字符,显然包括 x

        2
  •  0
  •   Peter B    6 年前

    您需要应用二进制排序规则,否则SQL Server将根据表或数据库使用的排序规则使用(可能不是二进制)顺序。

    下面是一个有效的例子。您需要哪个精确的二进制排序规则,这由您决定。

    WITH tests(min, val, max) AS (
        SELECT 'a', 'x', 'z' UNION ALL
        SELECT '',  'x', 'z' UNION ALL
        SELECT 'a', 'x', '~'
    )
    SELECT
        min, val, max,
        CASE WHEN val COLLATE SQL_Latin1_General_CP437_BIN BETWEEN min AND max THEN 'PASS' ELSE 'FAIL' END AS result
    FROM tests
    

    输出:

    min val max result
    --- --- --- ------
     a   x   z  PASS
         x   z  PASS
     a   x   ~  PASS
    
        3
  •  0
  •   Joe Taras    6 年前

    您的行为取决于您使用的排序规则。

    我试过了:

    select
    case
        when 'x' < '~' then 'ok'
        else 'ko'
    end
    

    SQL Server返回ko(使用我的默认排序规则 Latin1_General_CI_AS )

    如果我可以这样做:

    select
    case
        when 'x' < '~' collate Latin1_General_BIN  then 'ok'
        else 'ko'
    end
    

    它按照ASC代码工作