How to get count of distinct values from two tables in MySQL? - mysql

There are two tables. 1st: blogCategories, 2nd: blog.
Table blogCategories has just 2 fields, id and categoyName. There are many category names inserted before. Table blog has id, blogCatID, header, blog, date fileds.
There are many records in table blog. But not all categoryName's were used.
I try to get a list of categoryNames with their count of uses in blogs. I need 0 (zero) if categoryName is not used in blog.
I used the query below. But categoryNames gets count number 1 even if they have not been used.
SELECT DISTINCT categoryName, COUNT(*) AS totalBlogCount
FROM
(SELECT bc.categoryName
FROM
blogCategories bc
LEFT JOIN blog b ON bc.id=b.blogCatID) AS tot
GROUP BY categoryName

The below query will give you the categoryName and count of usage. if no usage then it will return 0 as count(null value)=0
SELECT bc.categoryName, COUNT(b.blogCatID) AS totalBlogCount
FROM blogCategories bc Left JOIN blog b ON bc.id=b.blogCatID
GROUP BY categoryName
output will looks like
inspirational 5
technical 2
political 0
random 3

Select bc.CategoryName, NullIf(bCounts.NumberOfTimesUsed,0) As NumberOfTimesUsedInBlog
From BlogCategories bc
Left Join
(Select blogCatID, Count(*) as NumberOfTimesUsed
From Blog Group By BlogCatID) bCounts
On bCounts.BlogCatID = bc.ID

SELECT bc.categoryName, COUNT(*) AS totalBlogCount
FROM blogCategories bc INNER JOIN blog b ON bc.id=b.blogCatID
GROUP BY categoryName

First you count the used blogCatID:
select blogCatID, count(*) as Number
from blog
group by blogCatID
later on you can find out which blogCategories are not used:
select *
from blogCategories as bc
where bc.id not in (select blogCatID
from blog
group by blogCatID)
next try a list of blogCategories together with the count of usage in blogs (and 0 if not used):
select isnull(b.numb, 0) as num, bc.*
from blogCategories as bc left join (select blogCatID, count(*) as numb
from blog
group by blogCatID) as b ON bc.id b.blogCatID

Related

Remove duplicates based on rank after join in SQL request

I am using MySQL 5.6.
I have a SQL table with a list of users:
id name
1 Alice
2 Bob
3 John
and a SQL table with the list of gifts for each user (numbered in order of preference):
id gift rank
1 balloon 2
1 shoes 1
1 seeds 3
1  video-game 1
2 computer 2
3 shoes 2
3 hat 1
And I would like a list of the preferred gift for each user (the highest rank - if two gifts have the same rank, pick only one randomly) (bonus: if the list could be randomized, that would be perfect!):
id name gift rank
2 Bob computer 2
1 Alice shoes 1
3 John hat 1
I tried to use the clause GROUP BY but without any success.
Considering rank as a part of your data; Without using window functions or complex sub queries
SELECT u.id, u.name, g.gift
FROM users u
JOIN gifts g ON g.id = u.id
LEFT JOIN gifts g2 ON g2.id = g.id AND g2.rank > g.rank
WHERE g2.id IS NULL;
Added link http://sqlfiddle.com/#!9/62f59e/15/0
You can use row_number to get one row for each User.(Mysql 8.0+)
SELECT A.ID,NAME,GIFT,`RANK` FROM USERS A
LEFT JOIN (
SELECT ID,GIFT,`RANK` FROM
(SELECT *,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY `RANK` ASC) AS RN FROM X) X
WHERE RN =1
) B
ON A.ID= B.ID
I do not know DB what you use. And I'm not an expert in SQL(I can have some mistake in next). But I think it is not difficult.
So I can give you just advice that you have to think gradually. Let me write.
First All I need is the highest rank. So I have to get this.
SELECT MAX(RANK)
FROM GIFT
GROUP BY ID
And then I think that I need get gifts from this rank.
SELECT GIFT.*
FROM GIFT
INNER JOIN(
SELECT ID, MAX(RANK)
FROM GIFT
GROUP BY ID
) filter ON GIFT.ID = filter.ID AND GIFT.RANK = filter.RANK
I think this is the table what you want!
So If below code works, That's what you really want.
SELECT *
FROM USER
LEFT OUTER JOIN(
above table
) GIFT ON USER.ID = GIFT.ID
But Remember this, I said I'm not an expert in SQL. There can be better way.
Checkout the query
SELECT tbluser.id,name,gift,rank into tblrslt
FROM tbluser
LEFT JOIN tblgifts
ON tbluser.id = tblgifts.id order by id,rank;
SELECT tt.*
FROM tblrslt tt
INNER JOIN
(SELECT id, min(rank) AS rank
FROM tblrslt
GROUP BY id) groupedtt
ON tt.id = groupedtt.id
AND tt.rank = groupedtt.rank order by id
In MySQL versions older than 8 you have no ranking functions available. You'll select the minimum rank per user instead and use these ranks to select the gift rows. This means you access the gifts table twice.
I suggest this:
select *
fron users u
join gifts g
on g.id = u.id
and (g.id, g.rank) in (select id, min(rank) from gifts group by id)
order by u.id;
If you also want to show users without gifts, simply change the inner join to a left outer join.

SQL: Group by in subquery

I'm trying to find the output of all books that have more than one genre using a group by statement and subquery. However, it keeps returning Subquery returns more than 1 row. This is what I have so far:
SELECT title
FROM book
WHERE 1 < (SELECT COUNT(genre) FROM genres GROUP BY book_id);
Here's an example:
SELECT b.title
FROM ( SELECT g.book_id
FROM genres g
GROUP
BY g.book_id
HAVING COUNT(1) > 1
) m
JOIN book b
ON b.id = m.book_id
The inline view m is meant to return us values of book_id that appear more than one time in the genres table. Depending on uniqueness constraints, we might want to count distinct values of genre
HAVING COUNT(DISTINCT g.genre) > 1
if we want to find books with exactly three related genre:
HAVING COUNT(DISTINCT g.genre) = 3
Once we have a list of book_id values, we can join to the book table. (The query assumes that book_id in genres is a foreign key reference to the id column in book table.)
You seem to what a correlated subquery:
SELECT b.title
FROM book b
WHERE 1 < (SELECT COUNT(*) FROM genres g WHERE g.book_id = b.book_id);
SELECT distinct a.title
FROM book a, (select bookid,count(distinct genre)genres from genres group by bookid)b
WHERE a.book_id=b.bookid and b.genres>1
hope it helps!

How to get articles which are part of the same group

I want to retrieve variants of the same article which are part of the same group. DBM is MySQL 5.7.
There are 2 tables:
articles
articles_group
Table articles has the fields:
article_id | title
1 first product
2 second prod
3 3rd prod
4 4th example
Table articles_groups:
group_id | article_id
1 1
1 2
1 3
2 4
In this example I would like to retrieve all other articles which are in the same group as article 1. So that would be article 2 and 3.
My best shot, but somehow pretty complex:
SELECT
art.article_id,
model
FROM
articles art
INNER JOIN
articles_group art_g ON art.article_id = art_g.article_id
WHERE art_g.group_id = (
SELECT ag.group_id
FROM articles a
INNER JOIN articles_group ag ON a.article_id = ag.article_id
WHERE a.article_id = 1
)
How can I retrieve all other articles which belong to the same group of given article in an easy way? I can still change the shema if there is a better setup.
Let's say your given article is 1. To get all articles in same group of given article, you can use subquery to get group_id of given article. Then use outer query to get all articles in same group.
SELECT a.article_id, a.title
FROM articles a
JOIN articles_groups g ON a.ref_id = g.ref_id
WHERE g.group_id = (
SELECT g.group_id
FROM articles a
JOIN articles_groups g ON a.ref_id = g.ref_id
WHERE a.article_id = '1'
)

Join two MySQL Tables and get result from categories

SELECT art.*,arg. FROM rd_articles AS art
LEFT JOIN rd_argument AS arg ON art.cat=arg.id WHERE art.enabled=1 ORDER BY art.id DESC
LIMIT 10
This is simple join query
Article table structure is
ID cat Description Date
1 1 Abc 08-01-2014
2 1 Aaa 10-01-2014
3 2 Abcv 11-01-2014
4 3 Aaa 12-01-2014
5 3 Aaa 14-01-2014
Arguments table is
ID Name
1 A
2 B
3 C
I want pick last updated(Date) one item from each cat.
How ?
This assumes that the enabled column is in rd_articles:
SELECT art.*, arg.*
FROM (
SELECT * FROM rd_articles
INNER JOIN (
SELECT cat, MAX(date) AS maxdate
FROM rd_articles
WHERE enabled = 1
GROUP BY cat
) md ON rd_articles.cat = md.cat AND rd_articles.date = md.maxdate
) art
LEFT JOIN rd_argument AS arg ON art.cat = arg.id
The innermost query gets the maximum date for each category, then joins it to the rd_articles table to get only those rd_articles rows that have the latest date for each article. That becomes the cat alias, which is then left-joined to the arguments table just like in your original query. You can add the LIMIT 10 at the end if needed; I wasn't sure what to do with that.
Note that if there's a tie for a category's latest date, you'll get more than one row for each category. If a tie could happen you'll need to break the tie somehow, for example by using the description or the ID. Let me know if that's the case and I'll update my answer.
SELECT ART.*, ARG.*
FROM ARTICLE AS ART
INNER JOIN RD_AGRUEMENT AS ARG
ON ARG.ID = ART.ID
WHERE (ID, DATE) IN
(SELECT ID, MAX(DATE) FROM ARTICLE GROUP BY ID)

MySQL How do I count the number of occurences of each ID?

It may be difficult to explain what I am after, apologies if the question is vague.
I have a table which associates products with keywords using IDs
So I may have product IDs, 2,3,4,5 associated with Keyword id 14
and product IDs 3,6,9 associated with Keyword id 15
My question is How do I count and store the total for those IDs associated with Keyword 14 and for those IDs associated with Keyword 15 and so on (New Keywords added all the time)?
MY SQL so far:
select products_keyword_categories.key_cat_name
from products_keyword_to_product
inner join products_keyword_categories
on products_keyword_categories.key_cat_id = products_keyword_to_product.key_cat_id
group by products_keyword_categories.key_cat_name
Many thanks in advance for any advice. Also, if there is any terminology that will aid me in further research via a Google search that would also be most welcome.
Edit to add: In the example above the table containing the associations is products_keyword_to_product - I inner join the other table to return the Keyword name.
Edit to add (2): Sorry I was afraid my question would be vague.
If I wanted to just count all the products using keyword ID 14 I would use COUNT() AS - As mentioned in the answers but I also need to count the number of products using Keyword ID 15 and Keyword ID 16 etc. - Hope that makes more sense.
select key_cat_name ,count(*)
from products_keyword_categories pkc
inner join products_keyword_to_product ptk on pkc.id=ptk.key_id
group by id;
select cat.key_cat_name, count(*) from
products_keyword_categories cat inner join products_keyword_to_product prod
on prod.key_cat_id=cat.key_cat_id
group by cat.key_cat_name
Edit:
select cat.key_cat_name, prod_assoc.product_id, count(*) from
products_keyword_categories cat inner join products_keyword_to_product prod_assoc
on prod_assoc.key_cat_id=cat.key_cat_id
group by cat.key_cat_name,prod_assoc.product_id
Assuming your tables structure is like this:
products_keyword_categories
key_cat_id key_cat_name
1 Electronics
2 Toys
3 Software
products_keyword_to_product
key_cat_id product_id
1 1
2 1
3 2
1 2
products
product_id name
1 Product A
2 Robot
Edit 2:
Try this
SELECT key_cat_name, product_id, COUNT(*)
FROM
(select cat.key_cat_name, prod_assoc.product_id from
products_keyword_categories cat inner join products_keyword_to_product prod_assoc
on prod_assoc.key_cat_id=cat.key_cat_id) as tbl
GROUP BY key_cat_name, product_id
Edit 3:
The query above is made of 2 parts:
The inner part:
(select cat.key_cat_name, prod_assoc.product_id from
products_keyword_categories cat inner join products_keyword_to_product prod_assoc
on prod_assoc.key_cat_id=cat.key_cat_id)
Which gives 1 row per combination of product_id and key_cat_name.
The outer part:
SELECT key_cat_name, product_id, COUNT(*)
FROM (...) as tbl
GROUP BY key_cat_name, product_id
Which operates on the results of the inner part (as tbl), counting how many times a combination of key_cat_name and product_id appears on the inner part.
Check this: Subqueries in MySQL, Part 1
You are almost there, you just need to add the following:
select count(products_keyword_to_product.id), products_keyword_categories.key_cat_name
...
the rest is correct
Updated Answer:
SELECT COUNT(*), reference_field FROM table WHERE...
HAVING field=value
GROUP BY field
For aggregate conditions you must use HAVING