MySQL - 使用一个智能WHERE减少SELECT数量

时间:2014-12-02 10:08:32

标签: mysql

我有一个包含3列的表格,其中包含一些四位数的ids。像那样:

+ main_id + id_1 + id_2 + id_3 +
|---------|------|------|------|
|    1    | 1000 | 1500 | 1900 |
|    2    | 1001 | 1501 | 1901 |
|    3    | 1002 | 1502 | 1902 |
+---------+------+------+------+

这个想法是价值观不能通过其他组合重复。我的意思是,如果表格已经1001 - 1501 - 1901,则1001 - 1901 - 15011501 - 1001 - 1901等组合将不再出现在表格中,并且应该将初始组合指向main_id并且在任何情况下都应该返回2

为此,我得到了一个存储函数,我将所有三个ids传递给它并在退出时获取main_id,如下所示:

SET temp_id = (SELECT `main_id` FROM `tableName` WHERE (`id_1` = id1 AND `id_2` = id2 AND `id_3` = id3) LIMIT 1);

IF (temp_id IS NULL) THEN SET temp_id = (SELECT `main_id` FROM `tableName` WHERE (`id_1` = id1 AND `id_2` = id3 AND `id_3` = id2) LIMIT 1);
    IF(temp_id IS NULL) THEN SET temp_id = (SELECT `main_id` FROM `tableName` WHERE (`id_1` = id2 AND `id_2` = id1 AND `id_3` = id3) LIMIT 1);
        IF(temp_id IS NULL) THEN SET temp_id = (SELECT `main_id` FROM `tableName` WHERE (`id_1` = id2 AND `id_2` = id3 AND `id_3` = id1) LIMIT 1);
            IF(temp_id IS NULL) THEN SET temp_id = (SELECT `main_id` FROM `tableName` WHERE (`id_1` = id3 AND `id_2` = id1 AND `id_3` = id2) LIMIT 1);
                IF(temp_id IS NULL) THEN SET temp_id = (SELECT `main_id` FROM `tableName` WHERE (`id_1` = id3 AND `id_2` = id2 AND `id_3` = id1) LIMIT 1);
                END IF;
            END IF;
        END IF;
    END IF;
END IF;

RETURN temp_id;

我考虑过将WHERESELECT子句中的所有可能组合与OR运算符一起使用,如下所示:

SELECT `main_id` FROM `tableName`
  WHERE (((`id_1` = id1 AND `id_2` = id2 AND `id_3` = id3)
    OR (`id_1` = id2 AND `id_2` = id1 AND `id_3` - id3)
    ...
    )) LIMIT 1

但它会贯穿所有可能的解决方案而不会在找到时停止。如果找到组合,前面的例子至少会停止更深入。

只有三列我总共得到6个组合。我计划为4列和5列做同样的事情,总共给我一个巨大的量的选择查询。

问题是,有没有办法加快这个功能?减少我发送的SELECT个查询量?我使用InnoDB,也许更快的东西会派上用场?

更新

我需要为一组三个值提取一个主要ID。到目前为止,无休止的if语句是最快的解决方案。我正在寻找优化。

3 个答案:

答案 0 :(得分:1)

我建议将ID连接在一起以形成唯一的表示形式,然后使用它来删除重复项:

select t.*, m.cnt as NumDups
from (select min(main_id) as main_id, count(*) as cnt
             concat(least(id_1, id_2, id_3),
                    (id_1 + id_2 + id_3) - least(id_1, id_2, id_3) - greatest(id_1, id_2, id_3),
                    greatest(id_1, id_2, id_3)
                   ) as ids
      from tablename t
      group by ids
     ) m join
     tablename t
     on m.main_id = t.main_id;

编辑:

如果您要查找一个匹配项并且变量@id1@id2@id3包含值,则可以执行以下操作:

select t.*
from tablename t
where least(@id1, @id2, @id3) = least(id_1, id_2, id_3) and
      ((@id1 + @id2 + @id3 - least(@id1, @id2, @id3) - greatest(@id1, @id2, @id3)) =
       (id_1 + id_2 + id_3) - least(id_1, id_2, id_3) - greatest(id_1, id_2, id_3)
      ) and
      greatest(@id1, @id2, @id3) = greatest(id_1, id_2, id_3);

答案 1 :(得分:0)

SQL Fiddle现在似乎不稳定,但这是一个在我的评论中演示该技术的简单示例。

假设您正在寻找与值1002,1502和1902相对应的main_id:

select main_id
from ids main
where exists (select 1 from ids where main.main_id = ids.main_id and id_1 in (select 1502 union select 1002 union select 1902))
and exists (select 1 from ids where main.main_id = ids.main_id and id_2 in (select 1502 union select 1002 union select 1902))
and exists (select 1 from ids where main.main_id = ids.main_id and id_3 in (select 1502 union select 1002 union select 1902))

在您的情况下,您可以将其重构为存储过程并使用临时表来存储输入值而不是联合。

答案 2 :(得分:0)

使用union规范化原始表,然后您可以通过简单的SQL解决此问题。

select main_id,group_concat(id)
from 
    (
    select main_id,id_1 as id from tablename
    union all
    select main_id,id_2 as id from tablename
    union all
    select main_id,id_3 as id from tablename
    ) as ids
where
    id in (1001,1501,1901)
group by
    main_id
having count(*) = 3