【问题标题】:MySQL select unique values based on one or more possible clausesMySQL 根据一个或多个可能的子句选择唯一值
【发布时间】:2011-07-13 20:50:33
【问题描述】:

于是就有了这个数据库表:

还有这个带有选定选项的数组:

$options[1] = 1;
$options[2] = 5;
$options[3] = 3;
$options[4] = 2;
$options[5] = 1;
...
$options[x] = y;

现在,我们的目标是获取所有 item_id,如果它的行中有来自 options 数组的键之一的 option_id,则该值必须与 options 数组中的值相同。

例如:

选项 1 已选择值 1

选项 2 选择了值 5

选项 3 选择了值 4

选项 4 选择了值 2

所以我们应该选择 item_id 1 和其他 item_id,其中 if option 1 -> option 1 = 1 AND if option 2 -> option 2 = 5 AND if option 3 -> option 3 = 4 AND ...

item_ids 将在 IN() 中用于从 items 表中选择 items 数据。

主要是用户在页面上选择了一些选项,然后将选项放入数组中,然后我必须找到所有符合所选选项的项目。在上表中,我们有项目和选项之间的关系,以及每个项目的预定义选项值。

【问题讨论】:

  • 如果我理解正确你只需要使用DISTINCT,即SELECT DISTINCT item_id FROM ...
  • 不是真的,如果行具有该选项 ID,我需要找到符合一个或多个选定选项值的所有行。 DISTINCT 也将被使用,但我怎样才能使选择符合一个或多个 where 子句?我尝试使用IF( option_id = 1, option_value, 'xxx' ) = 1,但是当我用 AND 放置更多 IF 时,没有选择任何内容。
  • option_value 是外键还是实际值?
  • option_value 是实际值。应该等于对应数组行的值$options[id] = value

标签: php mysql


【解决方案1】:
$where = array();
foreach($options as $key => $value) $where[] = 'option_id = ' . $key . ' AND option_value = ' . $value;
$sql = 'SELECT DISTINCT item_id
        FROM table
        WHERE (' . explode(') OR (', $where) . ')';

不过,我可能完全误解了你的问题。

【讨论】:

  • 谢谢,但这将为option_id=1 option_value=1option_id=4 option_value=1000 选择第一项。我需要一个规则来同时遵守一个项目的所有选项。
【解决方案2】:

我认为这可能对你有用。根本没有测试它,它可能会爆炸,但是......

SELECT *
FROM items
WHERE (item_id in (
    SELECT item_id
    FROM optiontable
    WHERE ((option_id = 1) and (option_value = 1)) or
        ((option_id = 2) and (option_value=5)) or
        ((option_id = 3) and (option_value=3)) or
        ((option_id = 4) and (option_value=2)) or
        ((option_id = 5) and (option_value=1))
    GROUP BY CONCAT(option_id, ',', option_value)
    HAVING COUNT(CONCAT(option_id, ',', option_value)) = 5
));

基本上,内部查询会提取与所需选项行中的一个成员行匹配的所有行。它对成对的 option_id/option_value 对进行人工分组/计数,并返回 opt_id/opt_val 对数加起来为 5 行的行的 item_ids。

您必须在客户端动态构建这样的查询,以便“where”子句条目的数量与having 子句中的数量相匹配。

【讨论】:

  • 谢谢。我尝试使用其选项获取第一个项目时得到空结果:SELECT * FROM products_options WHERE ((option_id = 1) and (option_value = 1)) or ((option_id = 4) and (option_value=2)) GROUP BY CONCAT(option_id, ',', option_value) HAVING COUNT(CONCAT(option_id, ',', option_value)) = 2
  • 另外一件事情是一个项目可以有2个option_id/option_value对,另一个项目可以有5对。
【解决方案3】:
<?php
$options = array(
    1 => 1,
    2 => 5,
    3 => 3,
    4 => 2,
    5 => 1
);
$cases = array();
foreach($options as $id => $value){
    $cases[] = "WHEN $id THEN $value";
}

$query =
'SELECT item_id '.
'FROM your_table '.
'WHERE option_value = CASE option_id '.implode(' ', $cases).' '.
'GROUP BY item_id';

echo $query;
?>

输出(由我格式化):

  SELECT item_id 
    FROM your_table 
   WHERE option_value = CASE option_id 
            WHEN 1 THEN 1 
            WHEN 2 THEN 5 
            WHEN 3 THEN 3 
            WHEN 4 THEN 2 
            WHEN 5 THEN 1 
GROUP BY item_id

测试此查询,让我知道它是否按您期望的方式工作。 :)


更新:最终查询的建议

$query =
'SELECT * FROM items '.
'WHERE id IN('.
'SELECT item_id '.
'FROM your_table '.
'WHERE option_value = CASE option_id '.implode(' ', $cases).' '.
'GROUP BY item_id)';

【讨论】:

  • 感谢您的建议。我已经尝试过这种方法,但我需要包含一个项目的所有规则。这样,如果一个项目有 option_id=1 option_value=1option_id=4 option_value=4 仍然会被选中,但它不应该。仅应选择具有所有可能匹配选项组合的项目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
相关资源
最近更新 更多