I have 3 tables :
tags: ( id, name, sefriendly )
articles_tags: ( id, tag_id, article_id )
articles: ( id, tags, ....)
I use the following sql to get the the tags for a specific article_id (here 10) which works fine by returning all tags names separated with comma
SELECT GROUP_CONCAT( name ) AS art_tags
FROM tags, articles_tags
WHERE article_id =10
AND tags.id = tag_id
AND tags_group_id =0
GROUP BY article_id
I want to get all the tags for all ids in table articles and store theme in articles.tags
Thanks
Check the below query with join condition
UPDATE articles
JOIN
(
SELECT
article_id,
GROUP_CONCAT( name ) AS art_tags
FROM tags, articles_tags
WHERE tags.id = tag_id
AND tags_group_id =0
GROUP BY article_id) tin
ON articles.id = tin.article_id
SET tags = tin.art_tags;
Related
This question already has answers here:
Select values that meet different conditions on different rows?
(6 answers)
Closed 3 years ago.
I have the following table, witch is the relationship pivot table, between posts and tags:
post_tags table
I need to get the posts that strict contain a 'X' given tag(s).
For example:
If I need posts with exclusively tags 1 and 2, it should returns post_id 1 and 4.
If I need post with tag 2, it should only returns post_id 3.
If I need post with tag 23, it should't returns nothing.
I've tried with:
SELECT * FROM `post_tags` WHERE tag_id = 1 OR tag_id = 2;
but obviously it returns all post_id with these tags_id
And with:
SELECT * FROM `post_tags` WHERE tag_id = 1 AND tag_id = 2;
It doest's return anything, because it's trying to comparate between columns.
Any solution?
You need to group by post_id and check the conditions in the having clause:
SELECT post_id
FROM post_tags
GROUP BY post_id
HAVING
SUM(tag_id NOT IN (1, 2)) = 0
AND
COUNT(DISTINCT tag_id) = 2
This will return only posts with tags 1 and 2 and no other tag.
For posts with only tag 2:
SELECT post_id
FROM post_tags
GROUP BY post_id
HAVING
SUM(tag_id <> 2) = 0
AND
COUNT(DISTINCT tag_id) = 1
If each post_id, tag_id pair is unique, then you can do this:
SELECT post_id
FROM post_tags
GROUP BY post_id
HAVING COUNT(tag_id IN (1, 2)) = COUNT(tag_id)
You could use a correlated subquery:
SELECT *
FROM post_tags pt
WHERE (
SELECT count(*)
FROM post_tags
WHERE pt.post_id = post_id
AND post_tag IN (1, 2)
) = 2
Or you could use an in list (using similar logic):
SELECT *
FROM post_tags pt
WHERE post_id IN (
SELECT post_id
FROM post_tags
WHERE post_tag IN (1, 2)
GROUP BY post_id
HAVING count(*) = 2
)
I have three tables that I am using in this scenario: articles, tags, and article_tags. To manage the tags I use a seperate tags table. The article_tags table links the articles to the tags. So the tables look like this:
articles:
|-------------------|
|--article_id(int)--|
|-------------------|
tags
|-------------------|
|---tag_id(int)-----|
|--keyword(varchar)-|
|-------------------|
article_tags
|-------------------|
|-article_tag_id(int)|
|-article_id(int)---|
|----tag_id(int)----|
|-------------------|
So I want to fetch articles that have the most common tags with the article being viewed and order the results by the matches. How would I do this?
This is a query that I used when I only used one table for tags.
SELECT t2.article_id, count(t2.keyword) AS matches,
a.article_id AS related_id
FROM article_tags t1
JOIN article_tags t2 ON (t1.keyword = t2.keyword AND t1.article_id != t2.article_id)
JOIN articles a on (t2.article_id = a.article_id)
WHERE t1.article_id = ".$article_id."
GROUP BY t2.article_id
ORDER BY matches DESC
LIMIT 5
Consider this schema... if article id #1 is being viewed both articles 2 and 3 would be included in the results, however, article 3 would be displayed before article 2 because article 2 has more tags in common with the article being viewed(article 1).
if I understand you correctly your query should look something like this
SELECT t2.article_id, COUNT(t2.tag_id) AS matches
FROM (SELECT article_id, tag_id
FROM article_tags
WHERE article_id = 1) t1
INNER JOIN (SELECT article_id, tag_id
FROM article_tags
WHERE article_id != 1) t2
ON t1.tag_id = t2.tag_id
GROUP BY t2.article_id
ORDER BY matches DESC
LIMIT 5;
First sub-query t1 select article_id (I think this is not necessary you can only select tag_id) and tag_id for the article is viewed...
Second sub-query t2 select article_id and tag_id for all other article.
Than we do simple INNER JOIN based on tag_id from both sub-query(this will exclude all tag_id from t2 which not match with tag_id from the first table).
After this we just group and order counted tags...
Here is SQL Fiddle to see how it's work.
GL!
I have a 3 part problem thats been giving me trouble I know how to get the tables to work if I query 1 table
at a time but I can't seem to figure out how I can combine both the tags and more_tags tables to get the same results.
The 3 main problems I have are Listed below.
PROBLEM 1
I want to be able to group the same tag from both the tags and more_tags tables.
PROBLEM 2
I also want to be able to display the tags from each table that are not present in the other table.
PROBLEM 3
I also want to count the total amount of times the tag appears in both tags and more_tags tables.
MYSQL Tables
SELECT `tags`.`tag_id`, `tags`.`tag_name`, COUNT(`tags`.`tag_name`) as 'num'
FROM `tags`
INNER JOIN `users` ON `tags`.`user_id` = `users`.`user_id`
WHERE `users`.`active` IS NULL
GROUP BY `tags`.`tag_name`
ORDER BY `tags`.`tag_name` ASC";
SELECT `more_tags`.`tag_id`, `more_tags`.`tag_name`, COUNT(`more_tags`.`tag_name`) as 'num'
FROM `more_tags`
INNER JOIN `users` ON `more_tags`.`user_id` = `users`.`user_id`
WHERE `users`.`active` IS NULL
GROUP BY `more_tags`.`tag_name`
ORDER BY `more_tags`.`tag_name` ASC";
Desired output
tag_id tag_name num
10 apple 12
192 pear 1
197 bored 1
203 sad 3
207 ads 2
217 news 1
190 bf 1
196 cape 1
Problem 1:
SELECT tag_id, tag_name, count(*)
FROM (
SELECT tag_id, tag_name FROM tags
UNION ALL
SELECT tag_id, tag_name FROM more_tags
) s
GROUP BY tag_id, tag_name
Problem 2:
SELECT tag_id, tag_name, 'not present in more tags' as description
FROM tags LEFT JOIN more_tags ON tags.tag_id=more_tags.tag_id
WHERE more_tags.tag_id IS NULL
UNION ALL
SELECT tag_id, tag_name, 'not present in tags' as description
FROM tags RIGHT JOIN more_tags ON tags.tag_id=more_tags.tag_id
WHERE tags.tag_id IS NULL
Problem 3:
SELECT tag_id, tag_name, COUNT(*)
FROM tags INNER JOIN more_tags ON tags.tag_id=more_tags.tag_id
GROUP BY tag_id, tag_name
You can use UNION to add together the results sets from two queries iff those queries return rows with the same structure (that is, if the first column in the first query is an int, then the first column in the second query must be an int, and so on). Read all about it in http://dev.mysql.com/doc/refman/5.1/en/union.html
Once you've written the two selects and joined them with a UNION statement, you can use that as a subquery for GROUP BY or other things:
SELECT * FROM (
(SELECT 1 AS ticked, col1, col2 FROM table1 INNER JOIN table2 USING (col3))
UNION
(SELECT 0 AS ticked, col1, col2 FROM table1)
) AS combined_table /*derived tables need a unique name*/
GROUP BY col1 /*group by the unique col1 to stop duplicates*/
ORDER BY ticked DESC
I have two tables in my database:
Products
id (int, primary key)
name (varchar)
ProductTags
product_id (int)
tag_id (int)
I would like to select products having all given tags. I tried:
SELECT
*
FROM
Products
JOIN ProductTags ON Products.id = ProductTags.product_id
WHERE
ProductTags.tag_id IN (1, 2, 3)
GROUP BY
Products.id
But it gives me products having any of given tags, instead of having all given tags. Writing WHERE tag_id = 1 AND tag_id = 2 is pointless, because no rows will be returned.
This type of problem is known as relational division
SELECT Products.*
FROM Products
JOIN ProductTags ON Products.id = ProductTags.product_id
WHERE ProductTags.tag_id IN (1,2,3)
GROUP BY Products.id /*<--This is OK in MySQL other RDBMSs
would want the whole SELECT list*/
HAVING COUNT(DISTINCT ProductTags.tag_id) = 3 /*Assuming that there is a unique
constraint on product_id,tag_id you
don't need the DISTINCT*/
you need to have a group by / count to ensure all are accounted for
select Products.*
from Products
join ( SELECT Product_ID
FROM ProductTags
where ProductTags.tag_id IN (1,2,3)
GROUP BY Products.id
having count( distinct tag_id ) = 3 ) PreQuery
on ON Products.id = PreQuery.product_id
The MySQL WHERE fieldname IN (1,2,3) is essentially shorthand for WHERE fieldname = 1 OR fieldname = 2 OR fieldname = 3. So if you aren't getting the desired functionality with WHERE ... IN then try switching to ORs. If that still doesn't give you the results you want, then perhaps WHERE ... IN is not the function you need to use.
Sorry for the abysmal title - if someone wants to change it for something more self-explanatory, great - I'm not sure how to express the problem. Which is:
I have a table like so:
POST_ID (INT) TAG_NAME (VARCHAR)
1 'tag1'
1 'tag2'
1 'tag3'
2 'tag2'
2 'tag4'
....
What I want to do is count the number of POSTs which have both tag1 AND tag2.
I've messed about with GROUP BY and DISTINCT and COUNT but I can't construct a query which does the trick.
Any suggestions?
Edit: In pseudo sql, the query I want is:
SELECT DISTINCT(POST_ID) WHICH HAS TAG_NAME = 'tag1' AND TAG_NAME = 'tag2';
Thanks
Edit: because 'TABLE' was a poor choice for a missing tablename, I'll suppose your table is called Posts.
Join the table against itself:
SELECT * FROM Posts P1
JOIN Posts P2
ON P1.POST_ID = P2.POST_ID
WHERE P1.TAG_NAME = 'tag1'
AND P2.TAG_NAME = 'tag2'
I'm just leaving this (untested) dependent subquery solution here for reference, even though it'll probably be horribly slow once you get to large data sets. Any solution that does the same thing using joins should be chosen over this.
Assuming you have a posts table with an id field, as well:
SELECT count(*) FROM posts WHERE EXISTS(SELECT NULL FROM posts_tags WHERE tag = 'tag1' AND post_id = posts.id) AND EXISTS(SELECT NULL FROM posts_tags WHERE tag = 'tag2' AND post_id = posts.id)
Try the following query:
SELECT COUNT(*) nb_posts
FROM (
SELECT post_id, COUNT(*) nb_tags
FROM table
WHERE tag_name in ('tag1','tag2')
GROUP BY post_id
HAVING COUNT(*) = 2
) t
Edit: based on Konerak answer, here is the query that handles the case when there are duplicated tag names for a given post:
SELECT DISTINCT t1.post_id
FROM table t1
JOIN table t2
ON t1.post_id = t2.post_id
AND t2.tag_name = 'tag2'
WHERE t1.tag_name = 'tag1'