mysql-获取与SQL查询中的列表匹配的所有行
作者:互联网
我有以下SQL查询,该查询选择与列表(9,10)中的任何值匹配的任何行:
SELECT
r.id, r.title,
u.name as 'Created By',
c.name as 'Category',
c.value,
cr.category_id
FROM
category_resource cr
INNER JOIN resource r
ON cr.resource_id = r.id
INNER JOIN user u
ON r.created_by = u.id
INNER JOIN category c
ON cr.category_id = c.id
WHERE cr.category_id IN ('10', '9');
我试图找出如何做相反的事情,这也是我所需要的,即选择匹配所有值的行.
我已经读过有关使用这样的语句的信息:
SELECT
r.id, r.title
FROM
resource r
WHERE
id IN (
SELECT
resource_id
FROM
category_resource
WHERE
category_id IN (9, 10)
GROUP BY
resource_id
HAVING
COUNT(DISTINCT category_id) = 2
);
这是我尝试使此答案适应我的需求的尝试:
SQL Server – select rows that match all items in a list
但这并不能像第一条语句那样使我获得更多的信息.那么,我该怎么做呢?我曾尝试将其组合在一起,但对于SQL来说我还是太陌生,无法正确解决,我只是遇到错误…
长时间更新:
Gordon Linoff指出这是一个奇怪的要求.而且我知道,对于一个查询返回同一资源的多行也很奇怪.但是我不知道该怎么做,也许我完全走错了路,因为它打了我原来的请求(获取所有行的列表中与ANY匹配的资源的行)也完全不能满足我的要求…
总体而言,这是我的要求:
首先,我认为这部分数据库的模型可能会有所帮助.
(BTW类别与自身也有关系,因为它使用邻接模型存储为层次结构,如果有人想知道该箭头,则每个类别都存储其父ID …)
1:查找类别与列表中的任何值匹配的所有资源.但是(对于这些资源而言,这是不够的),我需要知道该资源及其所有类别…
让我用一个简单的例子解释这一点:
如您所见,这是一个多对多的关系.资源(例如,标题为“ 18世纪新英格兰的木工概论”)可以与许多类别相关联(例如,category.name =“ subject”值=“ carpentry”,category.name =“ subject” value = “ Wood”,category.name =“主题”值=“新英格兰”,category.name =“ subject”值=“历史”).请注意,此示例已简化,但是您可以看到基本思想.
现在,如果用户搜索与“木工”和“绘画”类别中的任何一个类别相匹配的资源,则结果“ 18世纪新英格兰的木工概论”应该显示在资源中,因为其中一个类别匹配.但是,这就是问题所在,以及为什么戈登感到我的要求很奇怪:在要显示给用户的搜索结果中,我想列出标题“ 18世纪新英格兰木工概论”以及一列显示所有标题分类的类别,即使用户没有搜索它们也是如此,以便更好地概述此资源的完整主题.
那我该怎么办呢?我能想到的唯一方法是问题中的第一条陈述,但正如我所说的那样,这让我感到震惊的是,它并没有给我提供资源可能拥有的所有类别,只有真正在搜索的类别……
当然,我可以先查询结果,每个查询只得到一行.然后执行第二个查询,在结果中查找每种资源的所有类别.但是,如果第一个查询给我1000个结果(这是很常见的),那么要获得所有这些结果的类别,我将必须进行1000个查询才能获得每个类别的声音……听起来像这样会给我带来性能问题……
我在想这个错误的方式吗?还有另一种方法可以完成我想做的事吗?即给我查询选择的资源,以及该资源的所有关联类别…
2:好了,经过冗长的解释之后,第二个要求更容易解释:再次为选择的资源取回所有类别是相同的事情,但是这次查询中的选择应该只获取与所有提供的资源匹配的那些资源价值观.但是,仅因为我再次提供了查询中的所有值并不意味着我已经拥有所有类别,因为结果中的每个资源实际上可能具有更多(其他)类别,因此在将结果表示为时我也需要这些类别.第一个(ANY)要求中提到的内容.
解决方法:
更新2个速度问题
一种提高速度(避免对每一行执行子查询)的方法是创建一个具有与子查询匹配的资源ID的临时表,并通过加入主表在主查询中使用该表.
/*Create a temporary table with the ids we want (the subquery)*/
CREATE TEMPORARY TABLE Matching_Resources (INDEX(resource_id))
AS (
SELECT
resource_id
FROM
category_resource
WHERE
category_id IN (4,1)
GROUP BY
resource_id
HAVING
COUNT(DISTINCT category_id) = 2
);
SELECT
r.id, r.title,
u.name AS 'Created By',
GROUP_CONCAT( CONCAT('[',c.name,',',c.value,',',CAST(c.id as CHAR),']') separator ' // ') AS 'Categories'
FROM
resource r
INNER JOIN Matching_Resources mr
ON r.id = mr.resource_id
INNER JOIN category_resource cr
ON r.id = cr.resource_id
INNER JOIN category c
ON cr.category_id = c.id
INNER JOIN user u
ON r.created_by = u.id
GROUP BY r.id
更新1一些评论
在这两种情况下,您都希望类别过滤仅充当匹配资源ID的过滤器.因此,您需要使其成为子查询,以避免影响主查询,该主查询仅需要限制资源,但返回所有匹配的类别.
因此,两个解决方案中都必须存在WHERE r.id IN(..)部分.您已经知道如何在其中进行过滤(因为我仅使用您提供的相同代码)
对于匹配任何提供的类别的要求
SELECT
r.id, r.title,
u.name as 'Created By',
c.name as 'Category',
c.value,
cr.category_id
FROM
resource r
INNER JOIN category_resource cr
ON r.id = cr.resource_id
INNER JOIN category c
ON cr.category_id = c.id
INNER JOIN user u
ON r.created_by = u.id
WHERE
r.id IN
(
SELECT
resource_id
FROM
category_resource
WHERE
category_id IN (6,1)
)
演示http://sqlfiddle.com/#!3/d9486/8/0
对于匹配所有提供的类别的要求
SELECT
r.id, r.title,
u.name as 'Created By',
c.name as 'Category',
c.value,
cr.category_id
FROM
resource r
INNER JOIN category_resource cr
ON r.id = cr.resource_id
INNER JOIN category c
ON cr.category_id = c.id
INNER JOIN user u
ON r.created_by = u.id
WHERE
r.id IN
(
SELECT
resource_id
FROM
category_resource
WHERE
category_id IN (1,4)
GROUP BY
resource_id
HAVING
COUNT(DISTINCT category_id) = 2
)
演示于http://sqlfiddle.com/#!3/d9486/10/0
标签:where-in,sql,mysql 来源: https://codeday.me/bug/20191122/2057786.html