简化问题,我有两个表 - item和item_info。
项目如下:
+-----+----------+
| id | title |
+-----+----------+
| 1 | lorem1 |
| 2 | lorem2 |
| 3 | lorem3 |
| 4 | lorem4 |
| 5 | lorem5 |
+-----+----------+
item_info如下所示:
+-----+----------+---------------+---------------+
| id | item_id | field_name | field_value |
+-----+----------+---------------+---------------+
| 1 | 1 | tag | a_tag1 |
| 2 | 1 | tag | a_tag2 |
| 3 | 1 | series_title | bob_show |
| 4 | 1 | tag | b_tag1 |
| 5 | 1 | tag | b_tag2 |
| 6 | 2 | tag | a_tag3 |
| 7 | 2 | tag | a_tag4 |
| 8 | 2 | series_title | jane_show |
| 9 | 2 | tag | b_tag3 |
| 10 | 2 | tag | b_tag4 |
+-----+----------+---------------+---------------+
我正试图得到一个看起来像这样的结果:
+-----+----------+---------------+---------------+---------------+
| id | title | series_title | a_tags | b_tags |
+-----+----------+---------------+---------------+---------------+
| 1 | lorem1 | bob_show | a_tag1,a_tag2 | b_tag1,b_tag2 |
| 2 | lorem2 | jane_show | a_tag3,a_tag4 | b_tag3,b_tag4 |
+-----+----------+---------------+---------------+---------------+
我需要将结果集限制为item.id行的细节列表。我试图用多个左连接来做这个:
select i.id as 'id', i.title as 'title', info.field_value as 'series_title',
GROUP_CONCAT(DISTINCT info2.field_value) as 'a_tags',
GROUP_CONCAT(DISTINCT info3.field_value) as 'b_tags'
from item i
left join item_info info on i.id = info.item_id
left join item_info info2 on i.id = info2.item_id
left join item_info info3 on i.id = info3.item_id
and i.id in (1,2)
where info.field_name = 'series_title'
or info2.field_name = 'tag'
and info2.field_value like "a_%"
or info3.field_name = 'tag'
and info3.field_value like "b_%"
group by 1;
我无法判断这是否有效,因为查询是永远存在的,当我们运行永远需要的查询时,我的操作人员会变得胡思乱想。任何人都可以帮我简化查询并确保我以正确的方式构建它吗?
答案 0 :(得分:0)
我认为这可以做你想要的。
select
i.id as 'id',
i.title as 'title',
series.field_value as 'series_title',
GROUP_CONCAT(DISTINCT a.field_value) as 'a_tags',
GROUP_CONCAT(DISTINCT b.field_value) as 'b_tags'
from item i
inner join item_info series on i.id = series.item_id
inner join item_info a on i.id = a.item_id
inner join item_info b on i.id = b.item_id
where
i.id in (1, 2)
and series.field_name = 'series_title'
and a.field_value like "a\_%"
and a.field_name = 'tag'
and b.field_value like "b\_%"
and b.field_name = 'tag'
group by 1
希望这有帮助。
答案 1 :(得分:0)
看起来这些谓词中的一些属于ON子句,而不是WHERE子句,如果你不想否定LEFT连接,并且i.id上的谓词属于WHERE子句(如果你想要的话)限制返回的行,而不是限制从info3加入的行。
这应该返回指定的结果集:
SELECT i.id AS `id`
, i.title AS `title`
, info.field_value AS `series_title`
, GROUP_CONCAT(DISTINCT info2.field_value ORDER BY info2.field_value) AS `a_tags`
, GROUP_CONCAT(DISTINCT info3.field_value ORDER BY info3.field_value) AS `b_tags`
FROM item i
LEFT
JOIN item_info info
ON info.item_id = i.id
AND info.field_name = 'series_title'
LEFT
JOIN item_info info2
ON info2.item_id = i.id
AND info2.field_name = 'tag'
AND info2.field_value LIKE "a_%"
LEFT
JOIN item_info info3
ON info3.item_id = i.id
AND info3.field_name = 'tag'
AND info3.field_value like "b_%"
WHERE i.id in (1,2)
GROUP
BY i.id
有可能创建一个大型结果集,其中来自info2(有效)的行与来自info3的行交叉连接。 (来自info2的20个匹配行和来自info3的20个匹配行,将导致项目中每行的20 * 20 = 400行。)
如果只返回一行或两行,则有时相关子查询的性能会更好。 (对于大型集合,情况并非如此,因为子查询的执行次数...每行一次。)
SELECT i.id AS `id`
, i.title AS `title`
, ( SELECT info.field_value
FROM item_info info
WHERE info.item_id = i.id
AND info.field_name = 'series_title'
ORDER BY info.field_value
LIMIT 1
) AS `series_title`
, ( SELECT GROUP_CONCAT(DISTINCT info2.field_value ORDER BY info2.field_value)
FROM item_info2 info2
WHERE info2.item_id = i.id
AND info2.field_name = 'tag'
AND info2.field_value LIKE "a_%"
GROUP BY info2.item_id
) AS `a_tags`
, ( SELECT GROUP_CONCAT(DISTINCT info3.field_value ORDER BY info3.field_value)
FROM item_info3 info2
WHERE info3.item_id = i.id
AND info3.field_name = 'tag'
AND info3.field_value like "b_%"
GROUP BY info3.item_id
) AS `b_tags`
FROM item i
WHERE i.id in (1,2)
ORDER BY i.id
这也消除了对GROUP BY的需要(如果i.id是唯一的),尽管您可能想要添加ORDER BY,因此结果集以相同的顺序返回(就像它与GROUP BY一样) )
但同样,第二种方法可以是从item返回的大量行上的真正调光器。
答案 2 :(得分:0)
即使通过复杂查询满足您的需求,我认为您必须redesign
您的架构。
有点像这样。,
ITEM
---------------------------
Item_Id (P) | Title | series_title (Nullable)
1 lorem1 bob_show
2 lorem2 jane_show
3 lorem3 NULL
4 lorem4 NULL
5 lorem5 NULL
TAG
------------------
Tag_id (P) | Tag_name | item_id (Ref) | TAG_GroupID (Ref)
1 a_tag1 1 1
2 a_tag2 1 1
3 a_tag3 2 1
4 a_tag4 2 1
5 b_tag1 1 2
6 b_tag2 1 2
7 b_tag3 2 2
8 b_tag4 2 2
Tag_Group
-----------------
Tag_GroupID(Primary)| Tag_GroupName
1 a_tag
2 b_tag
此外,您的查询将成为
select ITEM.ID, ITEM.TITLE, ITEM.SERIES_TITLE ,
(
SELECT GROUP_CONCAT(Tag_Name) from Tag where ITEM.ID = Tag.Item_ID AND Tag.Tag_Group_Id = 1
) as 'A_TAGS'
,
(
SELECT GROUP_CONCAT(Tag_Name) from Tag where ITEM.ID = Tag.Item_ID AND Tag.Tag_Group_Id = 2
) as 'B_TAGS'
from ITEM
这里的实用跑步方法 - > http://sqlfiddle.com/#!2/45eba/12/0
现在这个只是静态的,您可以使用Dynamic Sql
以更动态的方式执行此操作...我会尽快在相同的答案中发布....
别忘了给我你的评论,或者你对这个新架构的看法。
谢谢。