Select a recording based on the meta

两盒软妹~` 提交于 2020-01-05 08:59:27

问题


I have have the following tables

Meta table

id | recording_id | meta_key | meta_value

Recording Table

id | recording

The recording_id on the meta_table is a foreign key that points towards a recording on the recording table.

Now I have a associative array $metas from my $_GET with meta keys and values and I want to SELECT the recordings that match all the meta keys and values. How would I do that?

This is what I have so far. How do I add an array into my bind param? And am I on the right track?

I just cannot wrap my head around this.

function retrieveRecordingsByMetaData($connection, $config, $metas, $limit)
{
    $where = "";
    for ($i = 0; $i < count($metas); $i++) {
        $where .= "meta_key=? AND meta_value=? AND ";
    }
    $where = preg_replace('/ AND $/', '', $where);

    $sql = "SELECT recording_id 
    FROM $config->meta_table 
    WHERE " . $where . " 
    INNER JOIN $config->recording_table 
    ON $config->meta_table.id=$config->recording_table.id 
    LIMIT ?";

    $stmt = $connection->prepare($sql);

    foreach ($metas as $key => $value) {
        $stmt->bind_param("s", $key);
        $stmt->bind_param("s", $value);
    }
    $stmt->bind_param("i", $limit);

    if (!$stmt->execute()) {
        echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error . " \r\n";
        die();
    }

    $result = $stmt->get_result();
    if ($result->num_rows > 0) {
        while ($row = $result->fetch_assoc()) {
            echo "recording found";
            //$recording = $row["recording"];
            //$hex = bin2hex($recording);
            //echo ("response=recording" . $id . "=" . $hex . "\r\n");
        }
    } else {
        echo "0 results \r\n";
    }
}

回答1:


To write this query just in SQL, you would write something like

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

The HAVING clause is what asserts that a recording has all of the specified meta key and value pairs.

To translate that into your PHP code, you need to build up your $where clause in a similar manner; I prefer using an array and imploding to save worrying about trailing AND and the like. At the same time as we are building that clause, we can build the inputs to 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();
}

A demo of the query formation and params generation can be found here.



来源:https://stackoverflow.com/questions/59186340/select-a-recording-based-on-the-meta

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!