MySQL:Select 所有具有相同 ID 的行,如果连接 table 中的列包含 x
MySQL: Select all rows with the same ID, if a column from a joined table contains x
(为了清楚起见,这里给出了一个极其简化的示例。)
我在数据库中有一个多对多关系(MySQL 与 Doctrine2/Symfony2 实体,但我想知道简单的答案 SQL),与中间有一个简单的 2 列 "join table":
项目
iditemname
1 猫
2 鼠标
标签
id标签名
1 捕食者
2 猎物
3 喜欢奶酪
4 飞行
item_tag
item_idtag_id
1 1
1 3
2 2
2 3
此标准连接查询:
SELECT itemname, tagname FROM item
JOIN item_tag ON item_tag.item_id = item.id
JOIN tag ON item_tag.tag_id = tag.id
给了我所有我感兴趣的数据,当然某些行是双倍的:
项目
项目名标签名
猫 捕食者
猫 喜欢奶酪
老鼠 猎物
老鼠 喜欢奶酪
现在我需要用一个简单的 WHERE 语句过滤它,所以我添加如下内容:
WHERE tagname = 'prey'
但是那当然只有 returns 一行。我需要为所有具有 'prey tag' 的项目获取 all 行 - 因此鼠标项目的所有行。老鼠喜欢奶酪这一事实是您在寻找猎物时要知道的一个非常重要的细节!
重点当然是输入某个标签名称的搜索查询(事先不知道项目名称),但是一旦它 returns 一组项目,我想看到所有的其他 个标签以及该集合中的项目。
这是否可以通过一次查询实现,或者我是否会被迫重新查询以获取剩余的关联标签?
你可以像这样从每个猎物身上获得item_id:
SELECT it.item_id
FROM item_tag it
JOIN tag t ON t.id = it.tag_id AND t.tagname = 'prey';
然后,您可以将其用作原始查询的 `WHERE 子句中的子查询,以获取这些项目的所有行:
SELECT i.itemname, t.tagname
FROM item i
JOIN item_tag it ON it.item_id = i.id
JOIN tag t ON t.id = it.tag_id
WHERE i.id IN(
SELECT it.item_id
FROM item_tag it
JOIN tag t ON t.id = it.tag_id AND t.tagname = 'prey');
这是一个 SQL Fiddle 示例。
基于 McAdam331 对 SQL 的回答,我想我也会包括我的 Symfony2 / Doctrine 解决方案。
我在子查询的项目存储库中使用了第二个查询构建器实例。当然,您只需要使用与主查询构建器中不同的索引即可。
$qb = $this->createQueryBuilder('i');
$sub = $this->createQueryBuilder('subi');
$search = $qb->expr()->orX(
$qb->expr()->like('i.name', ':s'),
$qb->expr()->in('i.id',
$sub->select('subi.id')
->join('subi.tags', 'subt')
->where($sub->expr()->like('subt.tagname',':s'))->getDQL()
),
... // various other search expressions are included in the OR clause
)
$qb->select('i','t')->join->('i.tags','t') // etcetera
->where($search)
->setParameter('s', "%".$searchString."%")
(为了清楚起见,这里给出了一个极其简化的示例。)
我在数据库中有一个多对多关系(MySQL 与 Doctrine2/Symfony2 实体,但我想知道简单的答案 SQL),与中间有一个简单的 2 列 "join table":
项目
iditemname
1 猫
2 鼠标
标签
id标签名
1 捕食者
2 猎物
3 喜欢奶酪
4 飞行
item_tag
item_idtag_id
1 1
1 3
2 2
2 3
此标准连接查询:
SELECT itemname, tagname FROM item
JOIN item_tag ON item_tag.item_id = item.id
JOIN tag ON item_tag.tag_id = tag.id
给了我所有我感兴趣的数据,当然某些行是双倍的:
项目
项目名标签名
猫 捕食者
猫 喜欢奶酪
老鼠 猎物
老鼠 喜欢奶酪
现在我需要用一个简单的 WHERE 语句过滤它,所以我添加如下内容:
WHERE tagname = 'prey'
但是那当然只有 returns 一行。我需要为所有具有 'prey tag' 的项目获取 all 行 - 因此鼠标项目的所有行。老鼠喜欢奶酪这一事实是您在寻找猎物时要知道的一个非常重要的细节!
重点当然是输入某个标签名称的搜索查询(事先不知道项目名称),但是一旦它 returns 一组项目,我想看到所有的其他 个标签以及该集合中的项目。
这是否可以通过一次查询实现,或者我是否会被迫重新查询以获取剩余的关联标签?
你可以像这样从每个猎物身上获得item_id:
SELECT it.item_id
FROM item_tag it
JOIN tag t ON t.id = it.tag_id AND t.tagname = 'prey';
然后,您可以将其用作原始查询的 `WHERE 子句中的子查询,以获取这些项目的所有行:
SELECT i.itemname, t.tagname
FROM item i
JOIN item_tag it ON it.item_id = i.id
JOIN tag t ON t.id = it.tag_id
WHERE i.id IN(
SELECT it.item_id
FROM item_tag it
JOIN tag t ON t.id = it.tag_id AND t.tagname = 'prey');
这是一个 SQL Fiddle 示例。
基于 McAdam331 对 SQL 的回答,我想我也会包括我的 Symfony2 / Doctrine 解决方案。
我在子查询的项目存储库中使用了第二个查询构建器实例。当然,您只需要使用与主查询构建器中不同的索引即可。
$qb = $this->createQueryBuilder('i');
$sub = $this->createQueryBuilder('subi');
$search = $qb->expr()->orX(
$qb->expr()->like('i.name', ':s'),
$qb->expr()->in('i.id',
$sub->select('subi.id')
->join('subi.tags', 'subt')
->where($sub->expr()->like('subt.tagname',':s'))->getDQL()
),
... // various other search expressions are included in the OR clause
)
$qb->select('i','t')->join->('i.tags','t') // etcetera
->where($search)
->setParameter('s', "%".$searchString."%")