简体   繁体   中英

How to join tables without repeating a column value multiple times?

I have 3 tables: images, colors and tags. Each image has 2 colors and at least 1 tag. And I want my users to individually search for tags or/and colors.

The problem is when I'm joining the tables I get rows that have the same value in the columns multiple times.

SELECT images.id, tag, color
FROM images
JOIN tags ON tags.image_id = images.id
JOIN colors ON colors.image_id = images.id
WHERE images.id = 1

I get:
image_id: 1, tag: sky, color: blue
image_id: 1, tag: cloud, color: blue
image_id: 1, tag: sky, color: white
image_id: 1, tag: cloud, color: white

But the result I want is something like:
image_id: 1, tag1: sky, tag2: cloud, color1: blue, color2: white

Is this possible somehow? Or should I just change database design?

The function group_concat() is going to put all the tag or color values into a single field, with whatever separator you like:

SELECT images.id, group_concat(distinct tag separator ', ') as tags,
       group_concat(distinct color separator ', ') as colors
FROM images
left JOIN tags ON tags.image_id = images.id
left JOIN colors ON colors.image_id = images.id
WHERE images.id = 1
group by images.id

(The group by is not, strictly speaking needed in this case because you are filtering down to one group. But you might want to eliminate the where clause and see this for multiple ids.)

The distinct keyword prevents duplicates, which is important because your query produces a cartesian product between the tags and colors. If you have 4 tags and 3 colors, the query produces 4*3=12 rows for each id. I did change the joins to left outer joins, so you will see ids that are missing tags or are missing colors.

You actually request 1tag1 , tag2 , color1 , and color2` as output. Well, if there are at most two values, you are in luck:

SELECT images.id,
       min(tag) as tag1, max(tag) as tag2,
       min(color) as color1, max(color) as color2
FROM images
left JOIN tags ON tags.image_id = images.id
left JOIN colors ON colors.image_id = images.id
WHERE images.id = 1
group by images.id

With more colors or tags you have a problem. A SQL query has a fixed number of columns -- that is, you can't add another column just because a new color is added onto an id. Also, in MySQL, it is hard to enumerate things (possible, but not standard SQL). If you have more than two colors or tags, go with group_concat() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM