为什么下面的sql查询可以工作,尽管语法看起来有问题?

cvxl0en2  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(254)

我编写了一个冗长的sql更新查询,跨多个表连接,目的是对旧客户数据进行编校/匿名化。作为这个过程的一部分,我想保留找到的任何英国邮政编码的第一段,因此我有这个查询(在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)),

('oh'只是一个表别名)问题是,为什么这样做?我提请你注意第二条线,我希望是;

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

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

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

在赋值前后加上括号以确保字符串偏移量被赋值,而不是布尔表达式的结果???
似乎这里发生了一些奇怪的事情,或者我不完全理解这里的语法和关联规则。。。有人能解释一下发生了什么事吗?
我不想在这里重写,但是如果有人知道更好的方法,我很乐意学习一些东西,我想要的是更深入地理解为什么原始查询可以工作,当它看起来不应该工作的时候。
编辑:达米恩正确回答了这个问题,看起来这个查询的split-on-space部分从来没有运行过,它总是把最后的3个字符切掉,当然我没有注意到这一点,因为最终结果看起来是一样的。。。我意识到这不是最初问题的一部分,但我欢迎任何关于实现这一点的正确方法的建议。。。
编辑2
这样做有效:

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))));

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

mbjcgjjk

mbjcgjjk1#

据我所知,我们首先研究这个表达式:

TRIM(oh.postcode) > 0

在左边,我们有一根绳子。在右边,我们有一个号码。根据mysql的logic2,这意味着我们应该将两者转换为float并进行比较。
由于大多数英国邮政编码不以任何数字开头,转换为浮点数将产生一个 0 2以及 0 不大于 0 . 这个表达永远是错误的(如果没有在英国邮政编码上做一个真正糟糕的尝试)。但即使这是真的,我们现在得出:

LOCATE(' ', <boolean>)

好吧,那不好。 LOCATE 想要一个字符串,但我们有一个布尔值。不过没关系。通过mysql logic2,我们将 false (不确定是通过数字转换还是直接)到字符串 0 ,我们将转换 true1 .
因为两者都不是 0 也不是 1 曾经有过一个空间, LOCATE(' ',<'0' or '1'>) 总是会返回0,所以这就是一直分配给 @cPos ,并且由于该赋值随后被用作内部 IF ,我们从不使用第二个参数中的表达式,而是始终使用第三个参数,这只是使用简单的“chop”启发式,而不是尝试处理空间。
我想你只要去掉那根绳子就可以做出正确的举止 > 0 完全比较,只需离开 TRIM 结果作为 LOCATE .
1我也在英国:-)
你可以从我的语气中推断出来。我不喜欢mysql的逻辑。我宁愿有一个响亮的错误卡在我的脸上,我可以通过添加显式类型转换(如果这是我真正想要的)在几秒钟内修复,而不是mysql将假定的所有转换。

相关问题