I am adding a tags feature to a polling system using MySql and PHP. The user will click a tag to list all polls (AKA propositions) with the respective tag. The link looks like this, “/propositions/tagged/baseball”.
I use a mod_rewrite to assign the “baseball” tag to a variable called $tag.
RewriteRule ^propositions/tagged/(.*)$ /propositions/index.php?tag=$1 [L]
It does not return the tag names of the tags associated with the poll. How would I get those names?
The query below works, but it does not return the tag names of the tags associated with the poll. How would I get those names? Also, can it be done more efficiently. One more thing, would it be better to store the tags with the poll data. I saw a while back where SO does this like including the tags in a table column with the question. Don’t know if they still do that or ever did that but saw or read it somewhere a while back.
Thanks so much!
=======================================================
pb_prop (
id int(11) NOT NULL auto_increment,
active tinyint(1) NOT NULL default '1',
submit_by int(11) NOT NULL,
total_votes int(11) NOT NULL default '0',
removed tinyint(1) NOT NULL default '0',
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Described below as ".PROP_TABLE." p
=======================================================
pb_prop_tags (
id int(11) NOT NULL auto_increment,
prop_id int(11) NOT NULL,
tag_id int(11) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Described below as ".PROP_TAGS_TABLE." pt
=======================================================
pb_tags (
tag_id int(11) NOT NULL auto_increment,
tag_name varchar(64) NOT NULL,
PRIMARY KEY (tag_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Described below as ".TAGS_TABLE." t
=======================================================
pb_prop_answers (
id int(11) NOT NULL auto_increment,
prop_id int(11) NOT NULL,
num_votes int(11) NOT NULL default '0',
PRIMARY KEY (id),
KEY poll_id (prop_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Described below as ".PROP_ANSWERS_TABLE." a
=======================================================
Working SQL below …could be improved? Since posting the original SQL, I added specific columns to the select …got rid of some wild cards. Also, added more to the WHERE to filter the results better.
Original SQL shown after.
SELECT
u.username, u.userid,
p.*,
pt.prop_id,
pt.tag_id,
t.*,
(
SELECT
SUM(num_votes)
FROM
".PROP_ANSWERS_TABLE." a
WHERE
a.prop_id = p.id
) AS total_votes,
(
SELECT
count(*)
FROM
".PROP_ANSWERS_TABLE." a
WHERE
a.prop_id = p.id
) AS total_answers
FROM
".PROP_TABLE." p
INNER JOIN
".TAGS_TABLE." t
ON
t.tag_name LIKE '%".$tag."%'
INNER JOIN
".PROP_TAGS_TABLE." pt
ON
pt.tag_id = t.tag_id
LEFT JOIN
".USERS_TABLE." u
ON
u.userid = p.submit_by
WHERE
pt.tag_id = t.tag_id
AND
pt.prop_id = p.id
AND
p.removed = 0
AND
p.active = 1
AND
t.tag_id = pt.tag_id
ORDER BY
{$sort} {$dir}
Original posted SQL:
SELECT
u.username, u.userid,
p.*,
pt.*,
(
SELECT
SUM(num_votes)
FROM
".PROP_ANSWERS_TABLE." a
WHERE
a.prop_id = p.id
) AS total_votes,
(
SELECT
count(*)
FROM
".PROP_ANSWERS_TABLE." a
WHERE
a.prop_id = p.id
) AS total_answers
FROM
".PROP_TABLE." p
INNER JOIN
".PROP_TAGS_TABLE." pt
ON
pt.tag_id = p.id
INNER JOIN
".TAGS_TABLE." t
ON
t.tag_name LIKE '%".$tag."%'
LEFT JOIN
".USERS_TABLE." u
ON
u.userid = p.submit_by
WHERE
p.removed = 0
AND
p.active = 1
AND
t.tag_id = pt.tag_id
ORDER BY
{$sort} {$dir}
I think you could do this without the subqueries, just joining against the tables used in the subqueries and using the aggregate functions in the main select. You would need a suitable (and likely quite long!) GROUP BY clause to go with it.
Something like this (and no doubt there are typos in it)
Amended SQL below, based on your updated SQL. This is doing a JOIN against a subselect which should be more efficient than a subselect per row.
However it should be possible to do this select with just an overall group by and no need for a subselect.