我编写了一个冗长的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的索引。。。
1条答案
按热度按时间mbjcgjjk1#
据我所知,我们首先研究这个表达式:
在左边,我们有一根绳子。在右边,我们有一个号码。根据mysql的logic2,这意味着我们应该将两者转换为float并进行比较。
由于大多数英国邮政编码不以任何数字开头,转换为浮点数将产生一个
0
2以及0
不大于0
. 这个表达永远是错误的(如果没有在英国邮政编码上做一个真正糟糕的尝试)。但即使这是真的,我们现在得出:好吧,那不好。
LOCATE
想要一个字符串,但我们有一个布尔值。不过没关系。通过mysql logic2,我们将false
(不确定是通过数字转换还是直接)到字符串0
,我们将转换true
至1
.因为两者都不是
0
也不是1
曾经有过一个空间,LOCATE(' ',<'0' or '1'>)
总是会返回0,所以这就是一直分配给@cPos
,并且由于该赋值随后被用作内部IF
,我们从不使用第二个参数中的表达式,而是始终使用第三个参数,这只是使用简单的“chop”启发式,而不是尝试处理空间。我想你只要去掉那根绳子就可以做出正确的举止
> 0
完全比较,只需离开TRIM
结果作为LOCATE
.1我也在英国:-)
你可以从我的语气中推断出来。我不喜欢mysql的逻辑。我宁愿有一个响亮的错误卡在我的脸上,我可以通过添加显式类型转换(如果这是我真正想要的)在几秒钟内修复,而不是mysql将假定的所有转换。