如何使用CakePHP查询构建器生成SQL函数调用?

ndr*_*dru 6 cakephp sql-function query-builder cakephp-3.0

我有一个作者的全名列,并希望将姓氏提取到另一列.我使用以下原始SQL执行此操作:

SELECT name,
SUBSTRING_INDEX(`name`, ' ', -1) AS `surname`
FROM qr.authors;
Run Code Online (Sandbox Code Playgroud)

输出:

在此输入图像描述

在"使用SQL函数"下,Cookbook说:

除了上述函数之外,func()方法还可用于创建任何通用SQL函数,如year,date_format,convert等.

但是如何通过func()方法创建这个SUBSTRING_INDEX函数,以便我可以将它与CakePHP查询构建器一起使用?

ndm*_*ndm 5

函数构建器带有预定义的方法/函数

FunctionsBuilder级舰有一堆现成的方法/函数供你使用,比如sum(),count(),concat(),dateDiff(),now(),等你可以找到支持的功能以及如何使用它们的示例的完整列表,在食谱API文档.

只需调用它们即可构建任意函数

FunctionsBuilder类使用魔术方法__call处理程序来构建任意SQL函数表达式,所以万一有你的功能没有现成的方法,你可以"呼叫"你的SQL函数:

$query = $this->SomeTable->find();

$func = $query->func()->substring_index([
    'name' => 'identifier',
    ' ',
    -1 => 'literal'
]);
$query->select([/* ... */, 'surname' => $func]);
Run Code Online (Sandbox Code Playgroud)

这应该大部分是自我解释的,魔术方法名称是SQL函数名称,传递的数组包含应该传递给函数的参数,在这种情况下,第一个和最后一个参数被定义为分别被视为标识符作为文字,因此两者都直接插入查询,即不作为将被转义的绑定参数!

的标识符的一个将另外受到可能自动标识符引用的,即name将被转换为例如`name`,"name",或[name]根据所使用的数据库驱动程序.第二个参数也可以是一个文字(通过传递'" "'),我只是没有将其设置为一个例如目的.不这样做会导致值被绑定/转换为字符串.

生成的编译SQL将如下所示:

substring_index(name, :c0, -1)
Run Code Online (Sandbox Code Playgroud)

并最终将被执行为

substring_index(name, ' ', -1) 
Run Code Online (Sandbox Code Playgroud)

处理非硬编码数据,例如用户输入

当与不硬编码的数据,即动态,或受可能变化的工作,请确保您定义的正确类型的铸造/第二个参数中逸出如果必要的话,像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
    ]
);
Run Code Online (Sandbox Code Playgroud)

类型将通过数字索引匹配,第一个将被忽略,因为它是一个表达式,因此只是传递null.

你甚至可以使用原始表达式

在您的情况下,您传递的安全,硬编码值不需要作为绑定参数插入查询中,并且SUBSTRING_INDEX不是CakePHP附带的任何方言所涵盖的函数,您可以甚至使用原始查询 - 然而你将失去在自定义方言中转换表达式的能力,并且自动标识符引用也将不再适用,所以只有当你知道自己在做什么时才这样做!

$query->newExpr('SUBSTRING_INDEX(`name`, "", -1)')
Run Code Online (Sandbox Code Playgroud)

也可以看看