尽管语法看起来错误,为什么以下SQL查询仍然有效?

时间:2018-05-23 09:00:36

标签: mysql sql

为了对旧客户数据进行编辑/匿名化,我编写了一个冗长的SQL UPDATE查询,它连接在多个表中。 作为此过程的一部分,我想保留找到的任何英国邮政编码的第一部分,所以我有这个查询(在UPDATE查询的SET子句中):

    oh.postcode = IF(oh.country = 'United Kingdom',
        IF(@cPos:=LOCATE(' ', TRIM(oh.postcode) > 0),
            SUBSTRING(UPPER(TRIM(oh.postcode)),
                0,
                @cPos - 1),
            TRIM(REVERSE(SUBSTRING(REVERSE(UPPER(TRIM(oh.postcode))),
                    4)))),
        LEFT(LTRIM(oh.postcode), 2)),

('哦'只是一个表别名) 问题是,为什么这有效?我提请你注意我希望的第二行;

IF(@cPos:=LOCATE(' ', TRIM(oh.postcode)) > 0,

因为LOCATE()的第二个参数不应该是一个布尔表达式...... 甚至

IF( ( @cPos:=LOCATE(' ', TRIM(oh.postcode)) ) > 0,

赋值的额外括号以确保分配字符串偏移量,而不是布尔表达式的结果???

似乎这里发生了一些奇怪的事情,或者我不完全理解这里的语法和关联规则......任何人都可以解释发生了什么事吗?

我不是在寻找重写,但如果有人知道更好的方法,我会很乐意学习一些东西,我之后会更深入地理解原始查询的工作原理,当它看起来不应该。

编辑: Damien_The_Unbeliever正确回答,看来这个查询的空间部分从未运行过,而且它总是只能将3个字符排除在最后,当然我没有注意到这一点首先,最终结果看起来一样...... 我意识到这不是原始问题的一部分,但我欢迎任何有关实现这一目标的正确方法的建议......

EDIT2

这有效:

SET @pc = ' W1s 3NW';
SELECT 
    IF(@cPos:=LOCATE(' ', TRIM(@pc)),
        SUBSTRING(UPPER(TRIM(@pc)),
            1,
            @cPos - 1),
        TRIM(REVERSE(SUBSTRING(REVERSE(UPPER(TRIM(@pc))),
                4))));

我想我忘了有一个基于1的索引的mysql字符串...

1 个答案:

答案 0 :(得分:1)

据我所知,我们首先使用这个表达式:

TRIM(oh.postcode) > 0

在左边,我们有一个字符串。在右边,我们有一个数字。通过MySQL的逻辑 2 ,这意味着我们应该convert both to floats and do that comparison

由于大多数 1 UK邮政编码不以任何数字开头,因此转换为float将产生0 2 0不大于0。这个表达总是(没有真正搞砸了英国邮政编码的尝试)是假的。但即使这是真的,我们现在来:

LOCATE(' ', <boolean>)

嗯,这不好。 LOCATE需要一个字符串,但我们有一个布尔值。那没关系。通过MySQL逻辑 2 ,我们将false(不确定它是通过数字转换还是直接转换)转换为字符串0,我们将转换{{ 1}}到true

由于10都不包含空格,1总是会返回0,因此总是分配给LOCATE(' ',<'0' or '1'>),因为该分配是然后用作内部IF的真值,我们从不在第二个参数中使用表达式并始终使用第三个,这只是使用简单的“chop”启发式而不是尝试使用空格。 / p>

认为只需完全删除@cPos比较就可以获得正确的行为,只需将> 0结果作为第二个参数留给{{1 }}

1 我也在英国: - )

2 你可以从我的语气中推断出来。我是MySQL逻辑的粉丝。我宁愿在我的脸上发出一个鸣喇叭错误,我可以在几秒钟内通过添加显式类型转换来修复,如果这是我真正想要的而不是MySQL将承担的所有转换。 / p>