Om deze query alleen in SQL te schrijven, zou je zoiets schrijven als
SELECT r.id
FROM recording r
JOIN meta m ON m.recording_id = r.id
AND (m.meta_key = 'key1' AND m.meta_value = 'value1'
OR m.meta_key = 'key2' AND m.meta_value = 'value2'
OR m.meta_key = 'key3' AND m.meta_value = 'value3'
...)
GROUP BY r.id
HAVING COUNT(*) = <count of all key/value pairs>
LIMIT 10
De HAVING
clausule is wat beweert dat een opname alle gespecificeerde metasleutel- en waardeparen heeft.
Om dat in uw PHP-code te vertalen, moet u uw $where
. opbouwen clausule op soortgelijke wijze; Ik geef er de voorkeur aan om een array te gebruiken en te imploderen om me geen zorgen te maken over het achterblijven van AND
en dergelijke. Op hetzelfde moment dat we die clausule bouwen, kunnen we de invoer bouwen naar bind_param
:
$join = array();
$params = array();
$types = '';
foreach ($metas as $key => $value) {
$join[] = 'm.meta_key=? AND m.meta_value=?';
$params[] = $key;
$params[] = $value;
$types .= 'ss';
}
// add the parameter for the `HAVING` check
$params[] = count($metas);
$types .= 'i';
// add the limit
$params[] = $limit;
$types .= 'i';
// make the query string
$sql = "SELECT recording_id
FROM {$config->recording_table} r
JOIN {$config->meta_table} m ON m.recording_id = r.id
AND (" . implode(' OR ', $join) . ")
GROUP BY r.id
HAVING COUNT(*) = ?
LIMIT ?";
$stmt = $connection->prepare($sql);
if (!$stmt) {
echo "Prepare failed: " . $conn->error . "\n";
die();
}
$stmt->bind_param($types, ...$params);
if (!$stmt->execute()) {
echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error . " \r\n";
die();
}
Een demo van het vormen van zoekopdrachten en het genereren van parameters vindt u hier .