通过自定义(用户创建的)字段值过滤查询结果

问题描述 投票:0回答:2

我正在使用的软件使管理员能够创建自定义字段来存储有关用户的任意信息。字段存储在名为meta的表中,其每个用户的值存储在表meta_value中,该表通过外键引用usermeta表。

表的简化定义:

CREATE TABLE `user` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `username` VARCHAR(120) NOT NULL,
    PRIMARY KEY (`id`),
    INDEX `idx_username` (`username`)
);

CREATE TABLE `meta` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `key` VARCHAR(120) NOT NULL UNIQUE,
    PRIMARY KEY (`id`),
    INDEX `idx_key` (`key`)
);

CREATE TABLE `meta_value` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `value` VARCHAR(120) NOT NULL,
    `meta_id` INT NOT NULL,
    `user_id` INT NOT NULL,
    PRIMARY KEY (`id`),
    FOREIGN KEY (`meta_id`) REFERENCES `meta` (`id`),
    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
    INDEX `idx_value` (`value`)
);

我正在实现一种搜索功能,该用户可以通过自定义字段的值搜索其他用户。搜索查询(简体)如下所示:?firstName[eq]=Andrew&lastName[eq]=Johnson&cityName[like]=Minneapol

此查询字符串应选择所有具有字段firstName = 'Andrew' ANDlastName = 'Johnson'AND city LIKE 'Minneapol%'的用户。

我已经尝试了明显的解决方案:

SELECT `user`.*
FROM `user`
INNER JOIN `meta_value` ON `meta_value`.`user_id` = `user`.`id`
INNER JOIN `meta` ON `meta`.`id` = `meta_value`.`meta_id`
WHERE (
    CASE `meta`.`key`
        WHEN 'firstName' THEN `meta_value`.`value` = 'Andrew'
        WHEN 'lastName' THEN `meta_value`.`value` = 'Johnson'
        WHEN 'cityName' THEN `meta_value`.`value` LIKE 'Minneapol%'
    END
);

此查询返回结果,其中firstName = 'Andrew'lastName = 'Johnson'cityName LIKE 'Minneapol%'不是所需的结果。

我很感谢所有有关如何解决此问题的建议,或在我做错情况时采取正确方法的所有建议。

请注意,表结构不是一成不变的,可以更改,因此,如果您知道用于此目的的更合适的数据结构方法,也请提出建议。

php mysql sql
2个回答
0
投票

您可以使用聚合和having

SELECT u.*
FROM user u JOIN
     meta_value mv
     ON mv.user_id = u.id JOIN
     meta m
     ON m.id = mv.meta_id
WHERE ( (m.key = 'firstname' AND mv.value = 'Andrew') OR
        (m.key = 'lastName' AND mv.value = 'Johnson') OR
        (m.key = 'cityName' AND mv.value LIKE 'Minneapol%')
      )
GROUP BY u.id
HAVING COUNT(DISTINCT m.key) = 3;

0
投票

在循环中添加其他条件:

$query = 'SELECT * FROM `user` 
    WHERE 1=1';
...
foreach($request as $fieldKey => $data) {
    $query .= (' AND user.id IN (
    SELECT `user_id` 
        FROM meta_value
        JOIN `meta` ON meta.`id` = meta_value.`meta_id`
        WHERE meta_value.`value` ' . $data['operand'] . ' "' . $data['value'] . '"
            AND meta.`key` = "' . $fieldKey . '")');
}
...
© www.soinside.com 2019 - 2024. All rights reserved.