我有作者的全名列,并希望将姓氏提取到另一列。我使用以下原始SQL执行此操作:
SELECT name,
SUBSTRING_INDEX(`name`, ' ', -1) AS `surname`
FROM qr.authors;
输出:
在“使用SQL函数”下,Cookbook说:
除了上述函数之外,func()方法还可用于创建任何通用SQL函数,如year,date_format,convert等。
但是如何通过func()方法创建这个SUBSTRING_INDEX函数,以便我可以将它与CakePHP查询构建器一起使用?
答案 0 :(得分:5)
FunctionsBuilder
类附带了大量现成的方法/函数供您使用,例如sum()
,count()
,concat()
,dateDiff()
,now()
等。您可以找到支持的功能的完整列表以及如何使用它们的示例in the Cookbook和the API docs。
FunctionsBuilder
类使用魔术方法__call
处理程序来构建任意SQL函数表达式,因此,如果您的函数没有现成的方法,您只需“调用”您的SQL函数:
$query = $this->SomeTable->find();
$func = $query->func()->substring_index([
'name' => 'identifier',
' ',
-1 => 'literal'
]);
$query->select([/* ... */, 'surname' => $func]);
这应该主要是相当自我解释,魔术方法名称是SQL函数名称,传递的数组包含应该传递给函数的参数,在这种情况下,第一个和最后一个参数被定义为被处理作为标识符分别作为文字,因此两者都直接插入查询,即不作为将被转义的绑定参数!
标识符1还将受到可能的自动标识符引用的影响,即name
将转换为例如`name`
,"name"
或[name]
,具体取决于数据库司机在使用中。第二个参数也可以是一个文字(通过传递例如'" "'
),我只是没有将其设置为例如目的。不这样做会导致值被绑定/转换为字符串。
生成的编译SQL将如下所示:
substring_index(name, :c0, -1)
并最终将以
执行substring_index(name, ' ', -1)
当处理非硬编码的数据(即动态数据或其他可能的更改)时,请确保在必要时在第二个参数中定义正确的转换/转义类型,例如integer
,datetime
等。为了使其正常工作,您必须使用列名称值的标识符表达式,否则在使用'xyz' => 'identifier'
语法时将忽略第二个参数:
$func = $query->func()->substring_index(
[
new \Cake\Database\Expression\IdentifierExpression('title'),
' ',
$userInput,
],
[
null, // no typecasting for the first argument
'string', // second argument will be bound/casted as string
'integer' // third argument will be bound/casted as integer
]
);
类型将通过数字索引匹配,第一个将被忽略,因为它是一个表达式,因此只传递null
。
在您的情况下,您传递的安全,硬编码值不需要作为绑定参数插入查询中,SUBSTRING_INDEX
不是任何一个涵盖的函数与CakePHP一起提供的方言,您甚至可以使用原始查询 - 但是您将无法转换自定义方言中的表达式,并且自动标识符引用也将不再适用,所以只有在您知道自己是什么时才这样做做!
$query->newExpr('SUBSTRING_INDEX(`name`, "", -1)')