我正在尝试找到具有所有四个限定值的
user_id
- 每个值都位于数据库表的不同行中。
wp_usermeta
:
Field Type Null Key Default Extra
---------------------------------------------------------------------------
umeta_id bigint(20) unsigned PRI auto_increment
user_id bigint(20) unsigned IND 0
meta_key varchar(255) Yes IND NULL
meta_value longtext Yes NULL
我写了一个MySQL查询,但它似乎不起作用,因为结果是空的。
$result = mysql_query(
"SELECT user_id
FROM wp_usermeta
WHERE
(meta_key = 'first_name' AND meta_value = '$us_name') AND
(meta_key = 'yearofpassing' AND meta_value = '$us_yearselect') AND
(meta_key = 'u_city' AND meta_value = '$us_reg') AND
(meta_key = 'us_course' AND meta_value = '$us_course')"
);
如何返回与所有这四行相关的
user_id
?
我会使用这个查询:
SELECT
user_id
FROM
wp_usermeta
WHERE
(meta_key = 'first_name' AND meta_value = '$us_name') OR
(meta_key = 'yearofpassing' AND meta_value = '$us_yearselect') OR
(meta_key = 'u_city' AND meta_value = '$us_reg') OR
(meta_key = 'us_course' AND meta_value = '$us_course')
GROUP BY
user_id
HAVING
COUNT(DISTINCT meta_key)=4
这将选择所有满足所有四个条件的
user_id
。
@fthiella 的解决方案非常优雅。
如果将来您想要显示的内容超过
user_id
,您可以使用联接,并且一行中可能包含您需要的所有数据。
如果您想使用
AND
条件,并且条件在表格中有多行,您可以使用 JOINS
示例:
SELECT `w_name`.`user_id`
FROM `wp_usermeta` as `w_name`
JOIN `wp_usermeta` as `w_year` ON `w_name`.`user_id`=`w_year`.`user_id`
AND `w_name`.`meta_key` = 'first_name'
AND `w_year`.`meta_key` = 'yearofpassing'
JOIN `wp_usermeta` as `w_city` ON `w_name`.`user_id`=`w_city`.user_id
AND `w_city`.`meta_key` = 'u_city'
JOIN `wp_usermeta` as `w_course` ON `w_name`.`user_id`=`w_course`.`user_id`
AND `w_course`.`meta_key` = 'us_course'
WHERE
`w_name`.`meta_value` = '$us_name' AND
`w_year`.meta_value = '$us_yearselect' AND
`w_city`.`meta_value` = '$us_reg' AND
`w_course`.`meta_value` = '$us_course'
其他:建议使用prepared statements,因为
mysql_*
函数不是SQL注入保存的,将被弃用。
如果您想尽可能少地更改代码,可以使用 mysqli_
函数:
http://php.net/manual/en/book.mysqli.php
推荐:
使用该表中的索引。
user_id
强烈建议使用 和 索引,并建议使用 meta_key
AND meta_value
,以便更快地运行查询。
解释:
如果您使用
AND
,您将“连接”一根线路的条件。因此,如果您想要多行的 AND 条件,首先您必须从多行创建一行,如下所示。
测试: 表数据:
PRIMARY INDEX
int varchar(255) varchar(255)
/ \ |
+---------+---------------+-----------+
| user_id | meta_key | meta_value|
+---------+---------------+-----------+
| 1 | first_name | Kovge |
+---------+---------------+-----------+
| 1 | yearofpassing | 2012 |
+---------+---------------+-----------+
| 1 | u_city | GaPa |
+---------+---------------+-----------+
| 1 | us_course | PHP |
+---------+---------------+-----------+
使用
$us_name='Kovge'
$us_yearselect='2012'
$us_reg='GaPa'
, $us_course='PHP'
: 查询结果
+---------+
| user_id |
+---------+
| 1 |
+---------+
所以它应该有效。
您的表结构是在首选最大数据灵活性时选择的。这种结构的缺点是效率受到影响,表通常会因数据而变得非常臃肿,并且查询表通常涉及使用称为“pivot”的技术的聚合函数。
以下是如何使用数据透视表来执行查询:(db-fiddle demo)
SELECT user_id
FROM wp_usermeta
GROUP BY user_id
HAVING MAX(IF(meta_key = 'first_name', meta_value, NULL)) = 'mangesh'
AND MAX(IF(meta_key = 'yearofpassing', meta_value, NULL)) = '2013'
AND MAX(IF(meta_key = 'u_city', meta_value, NULL)) = 'n/a'
AND MAX(IF(meta_key = 'us_course', meta_value, NULL)) = 'programming'
实际上,整个表格按
user_id
列进行分组。这样做时,就形成了临时的一对多关系。换句话说,每个相应的 user_id
将具有一行或多行数据(非线性,非平坦),可以通过 MySQL 的聚合函数(例如 MAX()
)进行查询。
HAVING 子句是过滤逻辑必须在 GROUP BY 之后进行的地方(其中过滤发生在 GROUP BY 之前)。在“数据集群”中,您可以通过检查其
meta_key
来隔离数据。当您找到与 meta_key
匹配的行时,您可以使用它的 meta_value
,如果没有,您可以分配一个有区别的默认值。在 IF
处理完聚合中的所有行之后,您就知道要查找的行是非 NULL 值——这是通过调用 MAX()
来访问的。使用此最大值与您要过滤的“实际”值进行比较。根据需要重复此过滤器以满足您的业务逻辑。
我还应该声明,您没有使用安全编码实践。 mysql_query()
目前已被弃用,并且出于任何原因不应存在于任何当前运行的代码中。我建议您使用 mysqli 的面向对象语法并实现带有绑定参数的准备语句以确保安全/稳定性。
$sql = "SELECT user_id
FROM wp_usermeta
GROUP BY user_id
HAVING MAX(IF(meta_key = 'first_name', meta_value, NULL)) = ?
AND MAX(IF(meta_key = 'yearofpassing', meta_value, NULL)) = ?
AND MAX(IF(meta_key = 'u_city', meta_value, NULL)) = ?
AND MAX(IF(meta_key = 'us_course', meta_value, NULL)) = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param('ssss', $us_name, $us_yearselect, $us_reg, $us_course);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($user_id);
$stmt->fetch();
echo $user_id;