MS SQL CONCAT 与“+”查询差异(与 Doctrine 2)

MS SQL CONCAT vs "+" query difference (with Doctrine 2)

我正在使用 Doctrine 2 界面访问 MS SQL 数据库。我发现双方都非常感兴趣的问题:Doctrine 2 和 MS SQL.

Doctrine 2 由于某种原因改变查询

$this->getEntityManager()->createQueryBuilder()
            ->from(table::class, 'il')
            ->select('CONCAT(il.col1,il.col2,il.col3) AS concated')

更改为类似(它使用自己的别名):

SELECT (t0_.col1+ t0_.col2+ t0_.col3) AS sclr_0 FROM tableName t0_

最重要的 - 它将 CONCAT 更改为带有“+”的表达式。但它工作正常(或者看起来像这样)直到我想将连接的字符串与其他 table...

中的值进行比较
$targetQueryBuilder->getEntityManager()->createQueryBuilder()
            ->from($namespace, 's')
            ->select('1')
            ->where('CONCAT(il1.col1, il1.col2, il1.col3) = s.controlValue')
            ->andWhere('s.tableName = :tablename')
            ->andWhere('s.tableRowIdentifier='.$rowIdentifier);

(我是凭记忆写这个查询,如果有什么不对的地方 - 没关系 - 就是把问题形象化) 在 SQL Studio 中执行原始查询与 CONCAT 函数一起工作绝对正常。使用“+”则不会。所有具有 nvarchar 类型的连接列。问题是:哪里不一样了?

我检查了学说中的大量组合以跳过将 CONCAT 映射到“+”但没有成功,我不得不编写一些虚拟词法分析器扩展来强制应用 CONCAT 函数到最后的查询。

其他(可能是 ms sql 服务器特定的)问题是: 我在测试的时候

SELECT
(i1_.NameUnternehmen + i1_.Land + i1_.Ort + i1_.Straße + i1_.Postleitzahl) AS a,
CONCAT(i1_.NameUnternehmen , i1_.Land , i1_.Ort , i1_.Straße , i1_.Postleitzahl) AS c
FROM tablename

Straße 列名称在本期中看起来并不重要) 使用 WHERE 语句将连接的字符串与控制值进行比较时,select 结果不同。

->where('CONCAT(il1.col1, il1.col2, il1.col3) = s.controlValue') - 一切正确

->where('(il1.col1 + il1.col2 + il1.col3) = s.controlValue') - "a" 列中的结果为空。我刚刚测试过,在其他 tables 上有时它不是空的。我不知道为什么。 "c" 列总是正确的。

CONCAT+ 操作不一样。如果在使用 + 时任何表达式的值为 NULL,则将返回 NULL。对于 CONCAT,它会隐式地将 NULL 替换为 '',因此不会返回 NULL

CONCAT 也将表达式中的任何值隐式转换为 (n)varchar,其中 + 使用 Data Type Precedence 确定数据类型并隐式转换表达式中的其他值最高优先级数据类型的表达式。

示例:

SELECT c1,
       c2,
       c3,
       c4,
       c1 + c2 + c3 + c4, --NULL 
       CONCAT(c1, c2, c3, c4) --'abcdefxyc'
FROM (VALUES('abc','def',NULL,'xyz'))V(c1, c2, c3, c4);

隐式转换:

SELECT c1 + c2 + c3 + c4
FROM (VALUES('abc','def',7,'xyz'))V(c1, c2, c3, c4);

Msg 245, Level 16, State 1, Line 9
Conversion failed when converting the varchar value 'abcdef' to data type int.

SELECT CONCAT(c1, c2, c3, c4) --'abcdef7xyz'
FROM (VALUES('abc','def',7,'xyz'))V(c1, c2, c3, c4);

有趣但符合预期的行为:

SELECT c1 + c2 + c3 + c4 --NULL
FROM (VALUES('abc','def',NULL,7))V(c1, c2, c3, c4);

SELECT c1 + c2 + c3 + c4 --123456790
FROM (VALUES('123','456','789',1))V(c1, c2, c3, c4);

出现这种行为的原因是表达式是从左到右求值的。因此,首先,您有 'abc' + 'def' = 'abcdef',然后是 'abcdef' + NULL = NULL (varchar)。最后你有 NULL + 7 = NULL,这很好,因为 NULL 可以隐式转换为 int.

对于后者,您有 '123' + '456' = '123456' 然后 '123456' + '789' = '123456789'。最后你有 '123456789' + 1 = 123456789 + 1 = 123456790。请注意,在最后的表达式中,varchar 首先隐式转换为 int,然后 + 运算符用作加法,而不是连接。

CONCAT 和 '+' 都是不同的。 在 mysql concat simple combine/join 我们的 data/sting/number 中。 主要区别在于数据类型。