MySQL-使用一个智能WHERE减少选择次数
我有一个包含3列的表,其中保存了一些四位数的MySQL-使用一个智能WHERE减少选择次数,mysql,Mysql,我有一个包含3列的表,其中保存了一些四位数的id。就像这样: + main_id + id_1 + id_2 + id_3 + |---------|------|------|------| | 1 | 1000 | 1500 | 1900 | | 2 | 1001 | 1501 | 1901 | | 3 | 1002 | 1502 | 1902 | +---------+------+------+------+ 其思想是,这些值不能通过其他组合重复它们
id
。就像这样:
+ 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-1501
或1501-1001-1901
这样的组合就不能再出现在表中,并且应该指向带有main\u id
的初始组合,并且在任何情况下都应该返回2
为此,我获得了一个存储函数,我将所有三个id
传递给它,并在退出时获得main\u 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;
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
我考虑在一个SELECT
with或操作符中使用WHERE
子句中所有可能的组合,如下所示:
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;
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查询
问题是,有没有办法加速这个功能?减少我发送的SELECT
查询的数量?我使用InnoDB,也许更快的东西会派上用场
更新
我需要为一组三个值提取一个主id。到目前为止,没完没了的if
语句是最快的解决方案。我正在寻找一种优化方法。SQL Fiddle目前似乎不稳定,但下面是一个简单的示例,在我的评论中演示了该技术
假设您正在查找与值1002、1502和1902相对应的主_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))
在您的情况下,您可以将其重构到存储过程中,并使用一个临时表来存储输入值,而不是union。我建议将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);
使用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
@草莓有可能超过3列,没有问题。顺序也不重要。一种方法是从要查找的值构造一个单列表(可以使用union),然后选择所有列所在的IDtable@Strawberry如果顺序不重要,那么解决方案肯定是从最低到最高存储值(与您的示例完全相同)。@草莓我需要为一组三个值提取一个main\u id
。到目前为止,没完没了的if
语句是最快的解决方案。我正在寻找一种优化方法。看起来这对任何超过3个人来说都是很麻烦的columns@Strawberry . . . 也许吧,但是这个查询非常明确地涉及3列。嗯,像“我计划对4列和5列做同样的事情”这样的注释和语句不算数?不过,我并不是说我有更好的主意——因为我没有!!抱歉,但这看起来真的像拐杖驱动的开发解决方案。我有一种感觉(测试表明这一点),我的pokecode会演变成SlowBookCode。@Nordenheim。你是说这比你目前的方法慢吗?那么,您是在寻找一个匹配项,还是在寻找整个表的一组简化值?