CakePHP 3 - использовать разные псевдонимы таблиц при разделении условий JOIN - PullRequest
0 голосов
/ 18 февраля 2019

Я перестраиваю ванильное приложение PHP / MySQL с использованием CakePHP 3.5.13.

Один из запросов в исходном приложении должен создать условие JOIN для той же таблицы и делает это с помощьюпсевдонимы отдельных таблиц.Запрос выглядит следующим образом - и дает правильные результаты, которые мы ожидаем:

SELECT DISTINCT(s.id) FROM substances s
JOIN display_substances AS dsUses
ON (s.id = dsUses.substance_id AND dsUses.display_id = 128 AND  (dsUses.value LIKE '%dye%') ) 
JOIN display_substances AS displays
ON (s.id = displays.substance_id AND displays.display_id NOT IN (1,2,3,4,6,128) AND  (displays.value LIKE '%bpr%'))

Причина, по которой это необходимо, заключается в том, что запрос выполняет поиск 2 отдельных элементов ввода пользователя - в пределах одной таблицы (display_substances), но против различных полей display_substances .display_id.В терминах запроса выше это означает:

  • Поиск "%dye%", где display_id = 128
  • Поиск "%bpr%", где display_id - , а не 1,2,3,4,6 or 128

В Cake я написал это так в контроллере, который обрабатывает функции поиска:

$query = $Substances->find()->select(['id' => 'Substances.id'])->distinct();

// Search for "dye"
$query = $query->matching('DisplaySubstances', function ($q) use ($uses_summary) {
return $q->where([
        'DisplaySubstances.value LIKE' => '%dye%', // "dye" is dynamic and comes from $uses_summary
        'DisplaySubstances.display_id' => 128
    ]);
});

// Search for "bpr"
$query = $query->matching('DisplaySubstances', function ($q) use ($regulatory_information) {
    return $q->where([
            'DisplaySubstances.value LIKE' => '%bpr%', // "bpr" is dynamic and comes from $regulatory_information
            'DisplaySubstances.display_id NOT IN' => [1,2,3,4,6,128]
        ]);
 });

Это приводит к неправильному SQL, потому что когда я отлаживаю $query->sql(); это дает другое JOIN условие:

INNER JOIN display_substances DisplaySubstances ON 
(
    DisplaySubstances.value like "%dye%" AND DisplaySubstances.display_id = 128 
    AND DisplaySubstances.value like "%bpr%" 
    AND DisplaySubstances.display_id not in (1,2,3,4,6,128) 
    AND Substances.id = (DisplaySubstances.substance_id)
)

Я не уверен, как переписать этот запрос так, чтобы он обрабатывал каждый из двух входных данных поиска как условие JOIN, согласнооригинальный запрос.

Главное, что я заметил, - это то, что исходный запрос имеет отдельные псевдонимы для одной и той же таблицы (AS dsUses и AS displays).Я не уверен, что это актуально?

Буду признателен за любую помощь здесь.Я пытаюсь использовать ORM вместо написания SQL вручную, поэтому предпочел бы знать, как использовать его для этого.

1 Ответ

0 голосов
/ 18 февраля 2019

Это пока нет можно указать пользовательские псевдонимы для вызовов matching(), в настоящее время множественные вызовы matching() в одной и той же ассоциации объединят условия, которые можно увидеть в сгенерированном вами вызове.Фрагмент SQL.

На данный момент вам придется либо создать дополнительные ассоциации (то есть, в дополнение к вашей DisplaySubstances ассоциации в вашем классе SubstancesTable) с разными псевдонимами:

$this->hasMany('DsUses', [
    'className' => 'DisplaySubstances'
]);
$this->hasMany('Displays', [
    'className' => 'DisplaySubstances'
]);

onзатем вы можете сопоставить:

$query->matching('DsUses', function ($q) use ($regulatory_information) {
    return $q->where([
        'DsUses.value LIKE' => '%dye%',
        'DsUses.display_id' => 128
    ]);
});

$query->matching('Displays', function ($q) use ($regulatory_information) {
    return $q->where([
        'Displays.value LIKE' => '%bpr%',
        'Displays.display_id NOT IN' => [1, 2, 3, 4, 6, 128]
    ]);
});

или создать объединения вручную, например, используя innerJoin():

$query->innerJoin(
    [
        'DsUses' => 'display_substances'
    ],
    [
        'Substances.id' => new \Cake\Database\Expression\IdentifierExpression('DsUses.substance_id'),
        'DsUses.display_id' => 128,
        'DsUses.value LIKE' => '%dye%'
    ],
    [
        'DsUses.display_id' => 'integer',
        'DsUses.value' => 'string'
    ]
);

$query->innerJoin(
    [
        'Displays' => 'display_substances'
    ],
    [
        'Substances.id' => new \Cake\Database\Expression\IdentifierExpression('Displays.substance_id'),
        'Displays.display_id NOT IN' => [1, 2, 3, 4, 6, 128],
        'Displays.value LIKE' => '%bpr%'
    ],
    [
        'Displays.display_id' => 'integer',
        'Displays.value' => 'string'
    ]
);

См. также

...