tags:

views:

206

answers:

3

Hello, I'm trying to fetch the most popular tags from all videos in my database (ignoring blank tags). I also need the 'flv' for each tag. I have this working as I want if each video has one tag:

SELECT tag_1, flv, COUNT(tag_1) AS tagcount 
  FROM videos 
 WHERE NOT tag_1='' 
 GROUP BY tag_1 
 ORDER BY tagcount DESC LIMIT 0, 10

However in my database, each video is allowed three tags - tag_1, tag_2 and tag_3. Is there a way to get the most popular tags reading from multiple columns?

The record structure is:

+-----------------+--------------+------+-----+---------+----------------+ 
| Field           | Type         | Null | Key | Default | Extra          | 
+-----------------+--------------+------+-----+---------+----------------+ 
| id              | int(11)      | NO   | PRI | NULL    | auto_increment | 
| flv             | varchar(150) | YES  |     | NULL    |                | 
| tag_1           | varchar(75)  | YES  |     | NULL    |                | 
| tag_2           | varchar(75)  | YES  |     | NULL    |                | 
| tag_3           | varchar(75)  | YES  |     | NULL    |                | 
+-----------------+--------------+------+-----+---------+----------------+ 
+5  A: 
select tag, flv, count(*) as tag_count
from (
  select tag_1 as tag, flv from videos
  UNION
  select tag_2 as tag, flv from videos
  UNION
  select tag_3 as tag, flv from videos
) AS X

I think that will do it, although there will be double-counting if any record has the same values for two of the tags.

UPDATE: added AS X.

Carl Manaster
Unfortunately that gives me an error:"ERROR 1248 (42000): Every derived table must have its own alias"It's not something daft I'm forgetting is it?
liam
No - it's something daft *I'm* forgetting. Sorry, in mysql you need to name the inner select. I just toss "as x" on the end of it; will edit to demonstrate.
Carl Manaster
+3  A: 

You need to unpivot the data:

SELECT tag, COUNT(*)
FROM (
    SELECT tag_1 AS tag
    UNION ALL
    SELECT tag_2 AS tag
    UNION ALL
    SELECT tag_3 AS tag
) AS X (tag)
GROUP BY tag
ORDER BY COUNT(*) DESC

I'm not sure how the flv is determined for a particular tag, since each id can have a single flv and up to 3 tags, it seems like any tag can have many different flv.

Cade Roux
Yes, that is the case with my single-tag code. It's probably luck more than anything that my query gives the latest video for that particular tag.
liam
In the end, this is the solution that worked best. I made each select read "SELECT flv, tag_x" and it gave the output I wanted.
liam
+3  A: 

This is not exactly an answer to your question, but I believe that it is the best solution to your problem.

Is it possible for you to change your schema? If so, I think it would be best if you normalized this by pulling the tags out into a separate table. In such a case, you might end up with 2 or 3 tables, depending on whether the tags can be arbitrary strings or are from a set/list. Under this set up, you'd have

Videos (VideoId, Flv)
Tags (TagId, TagName)
VideoTags(TagId, VideoId)

Then it becomes pretty easy to find the most popular tags.

Eric
I agree with this **if** you expect to perform this query and others like it frequently. It's a more denormalized form, but in some use cases it *may* not be worth the effort. You should definitely weigh it as an option.
keithjgrant
I agree with Eric. Today you only want to have up to 3 tags per video. Next year you may decide you want 5. Every time I've done what the OP did (field1, field2, field3) for the sake of convenience it has always come back to bite me. Yesterday's iron clad rule becomes tomorrow's burdensome convention.
Autodidact