簡體   English   中英

CakePHP 3 - 如何在查詢生成器中編寫 COALESCE(...)?

[英]CakePHP 3 - How to write COALESCE(…) in query builder?

如何在查詢構建器中編寫這種COALESCE()語句?

SQL

SELECT COALESCE(n.value, p.value) AS value
FROM nodes n
LEFT JOIN parents p ON p.id = n.parent_id

PHP

我可以檢索子值和父值,然后遍歷結果集,如果子值是空的,則只使用父值,但如果有一種更優雅的方法將它構建到查詢本身中,我更喜歡這樣。

$child = $this->Nodes->find()
    ->select(['id', 'value'])
    ->where(['Nodes.id' => $id])
    ->contain([
        'Parents' => function ($q) {
            return $q->select('value');
        }
    ])
    ->first();

if (empty($child->value)) {
    $child->value = $child->parent->value;
}

更新 1

所以這就是我目前所擁有的,但它不起作用。

$child = $this->Nodes->find()
    ->select(['id', 'value'])
    ->where(['Nodes.id' => $id])
    ->contain([
        'Parents' => function ($q) {
            return $q->select([
                'value' => $q->func()->coalesce([
                    'Nodes.value',
                    'Parents.value'
                ])
            ]);
        }
    ])
    ->first();

返回:

object(Cake\ORM\Entity) {

    'id' => (int) 234,
    'value' => (float) 0,
    '[new]' => false,
    '[accessible]' => [
        '*' => true
    ],
    '[dirty]' => [],
    '[original]' => [],
    '[virtual]' => [],
    '[errors]' => [],
    '[invalid]' => [],
    '[repository]' => 'Nodes'
}

子值是NULL ,父值是1.00所以我希望實體值是'value' => (float) 1.00但我假設它是從查詢中出來的,因為FALSE轉換為(float) 0

更新 2

似乎將合並別名為一個已經存在的名稱,因為普通字段不起作用。 對於合並結果,它需要一個唯一的字段名稱。

更新 3

我做了另一個測試並從兩個表中選擇了name字段,它只返回我輸入到函數中的實際字符串(它們不會被評估為列名):

return $q->select([
    'value' => $q->func()->coalesce([
        'Nodes.name',
        'Parents.name'
    ])
]);

返回的實體具有:

'value' => 'Nodes.name'

所以我的新問題是如何讓查詢構建器將字符串評估為表/字段名稱?

我無法讓 Cake 的coalesce()函數將參數作為字段進行評估,它只是返回字段名稱的實際字符串。

我通過手動創建COALESCE語句來讓它工作。

// Create the query object first, so it can be used to create a SQL expression
$query = $this->Nodes->find();

// Modify the query
$query
    ->select([
        'id',
        'value' => $query->newExpr('COALESCE(Nodes.value, Parents.value)')
    ])
    ->where(['Nodes.id' => $id])
    ->contain('Parents')
    ->first();

CakePHP 的coalesce()使用以下格式來區分字段名稱和文字值:

                'value' => $q->func()->coalesce([
                    'User.last_name' => 'identifier',
                    ', ',
                    'User.first_name' => 'identifier'
                ])

上面的代碼應該產生類似Smith, John結果。

默認行為是將元素視為文字。

https://api.cakephp.org/3.3/class-Cake.Database.FunctionsBuilder.html#_coalesce

文檔根本沒有很好地解釋這一點。 H/T 到https://www.dereuromark.de/2020/02/06/virtual-query-fields-in-cakephp/一個明顯的例子。

http://book.cakephp.org/3.0/en/orm/query-builder.html#using-sql-functions

沒試過,但我猜是:

$child = $this->Nodes->find()
    ->select(['id', 'value'])
    ->where(['Nodes.id' => $id])
    ->contain([
        'Parents' => function ($q) {
            return $q->select(['value' => $query->func()->coalesce([
                /* Fields go here... I think. :) */
            ])]);
        }
    ])
    ->first();

如果這不起作用,請檢查核心的單元測試如何調用此函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM