Mysql 获取SQL查询中与列表匹配的所有行
我使用以下SQL查询选择与列表(9,10)中的任何值匹配的任何行: 我试着找出如何做相反的事情,我也需要这样做,即选择匹配所有值的行 我读到过这样一种说法:Mysql 获取SQL查询中与列表匹配的所有行,mysql,sql,where-in,Mysql,Sql,Where In,我使用以下SQL查询选择与列表(9,10)中的任何值匹配的任何行: 我试着找出如何做相反的事情,我也需要这样做,即选择匹配所有值的行 我读到过这样一种说法: SELECT r.id, r.title FROM resource r WHERE id IN ( SELECT resource_id FROM category_resource WHERE
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太陌生了,无法正确地理解它,我只是得到了错误
长期更新:
戈登·林诺夫指出,这是一个奇怪的要求。我知道,我也觉得很奇怪,对于同一个资源,有一个返回多行的查询。但我不知道如何以其他方式实现这一点,也许我完全走错了方向,因为我突然意识到原始请求(获取所有资源行,其中类别与列表中任何类别匹配的请求)也不能满足我的要求
以下是我的总体要求:
首先,我认为db这一部分的模型可能会有所帮助
(顺便说一句,类别本身也有关系,因为它被存储为一个层次结构,使用邻接模型,其中每个类别存储其父id,如果有人想知道该箭头…)
1:查找类别与列表中任何值匹配的所有资源。但是(这是不够的)对于这些资源中的每一个,我需要知道资源以及它拥有的所有类别
让我用一个简单的例子来解释这一点:
正如你所看到的,这是一种多对多的关系。一个资源(比如说标题为“18世纪新英格兰木工入门”)可以与许多类别相关联(例如category.name=“subject”value=“Carpentry”、category.name=“subject”value=“Wood”、category.name=“subject”value=“newengland”、category.name=“subject”value=“History”)。请注意,本例已简化,但您看到了基本思想
现在,如果用户搜索的资源与“木工”和“绘画”中的任何一个类别相匹配,那么“18世纪新英格兰木工简介”应该会出现在搜索结果中,因为其中一个类别匹配。但是,问题是,戈登为什么觉得我的请求很奇怪:在搜索结果中,我想对于用户,我想列出标题“18世纪新英格兰木工简介”以及一个列,显示标题所属的所有类别,即使用户没有搜索这些类别-以便更好地概述此资源的完整主题
那么我该怎么做呢?我唯一能想到的就是我问题中的第一句话,但正如我所说的,它并没有给我一个资源可能拥有的所有类别,只有那些实际搜索到的类别
当然,我可以先对结果进行查询,每个结果只得到一行。然后再进行第二次查询,查找结果中每个资源的所有类别。但是如果第一次查询得到1000个结果(这将是常见的),然后要获得所有这些的类别,我必须进行1000次查询才能获得每个类别的类别…听起来这会给我带来性能问题
我是否有错误的想法?是否有其他方法来完成我想做的事情?例如,给我查询选择的资源,以及该资源的所有关联类别
2:好的,在经过长时间的解释之后,第二个要求更容易解释:关于为所选资源返回所有类别,同样是这样,但是这次查询中的选择应该只获取与所有提供的值匹配的资源oesn’意味着我已经拥有了所有类别,因为结果中的每个资源实际上可能有更多(和其他)类别,并且我在呈现第一个(任何)要求中提到的结果时也需要这些类别。您可以将结果重新加入:
SELECT u.name as "Created By", c.name as 'Category', c.value, cr.category_id
FROM resource r join
user u
on r.created_by = u.id join
(SELECT resource_id
FROM category_resource
WHERE category_id IN (9, 10)
GROUP BY resource_id
HAVING COUNT(DISTINCT category_id) = 2
) crr
on r.id = crr.resource_id join
category_resource cr
on cr.resource_id = r.id join
category c
on cr.category_id = c.id;
这似乎是一个奇怪的请求,因为每个资源(至少)将获得两行,每个类别一行
此外,不要对列别名使用单引号。这些应仅用于字符串(和日期)常量。更新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的筛选器。因此,您需要将其设置为子查询,以避免影响只需要限制资源但返回所有匹配类别的主查询 因此,
其中,(..)中的r.id必须存在于两种解决方案中。您已经知道如何在其中进行过滤(因为我只使用您提供的相同代码)
符合任何提供类别的要求
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)
)
演示
用于匹配所有提供类别的要求
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
)
演示在返回较少的结果是正常的,因为您只获得了重叠,但我不是说我不希望得到较少的结果,我只是说我需要在结果中返回更多的列,就像第一次查询一样。但是,我发现问题有点复杂,请参阅我刚才的编辑谢谢你,这很有帮助。我刚刚发现,虽然我没有充分解释这个问题,请查看我的编辑,如果你能帮助…美丽!作品
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
)