MySQL Count Items In Category - mysql

I don't understand MySQL very well, here are the table structures I am using.
users
id | first_name | last_name | username
| password
categories
id | user_id | name | description
links
id | user_id | category_id | name |
url | description | date_added |
hit_counter
I am trying to return a result set like this, to give information about the category for a user that includes how many links are in it.
id | user_id | name | description | link_count
At the moment I have this query, but it only returns rows for categories that have links. It should return rows for categories that do not have any links (empty categories).
SELECT categories.*, COUNT(links.id)
FROM categories LEFT JOIN links ON
categories.id=links.category_id;
How to do this query? Thanks.

we can't do select table dot "star" with an aggregate.
what you wanna do is something like (pseudocode):
select
categories.field1,
categories.field2,
{etc.}
count(links.id)
from categories
left join links
on categories.id = links.category_id
group by
categories.field1,
categories.field2,
{etc.}
iow: you're missing the group by code-block to get the right aggregate in your query result set.

To mold alien052002's answer to fit your specific question, the following (untested) should work:
select c.id,
c.user_id,
c.name,
c.description,
count(l.link_count)
from categories c
left join links l on l.category_id = c.id
group by c.id, c.user_id, c.name, c.description

try this
SELECT categories.*, COUNT(links.id) FROM categories LEFT JOIN links ON categories.id=links.category_id group by categories.id;

Related

MySQL count unique over multiple tables

I have two tables:
products product_eans
+--+-----------+ +----------+-------------+
|id|name | |product_id|ean |
+--+-----------+ +----------+-------------+
| 1|hello world| | 1|4053804303361|
+--+-----------+ +----------+-------------+
| 2|hello mars | | 1|4053804304788|
+--+-----------+ +----------+-------------+
| 2|4053804304825|
+----------+-------------+
I now want to count the (unique) products that has the string 4788 in their name or in one of their EANs. The result in the example would be 1 (one product has an EAN that contains the search string 4788)
I have managed this with
SELECT
COUNT(DISTINCT products.id) AS count
FROM
products
WHERE
products.name LIKE "%4788%" OR
(SELECT
GROUP_CONCAT(ean)
FROM
product_eans
WHERE
product_id = product.id) LIKE "%4788%"`
but it’s incredible slow with thousands of rows in both tables.
What is the most efficient way for a query like this?
Using "double-ended wildcards" is never going to be fast because you won't get use of indexing so the tables will be scanned. An inner join is probably the most efficient
SELECT COUNT(DISTINCT e.products_id)
FROM product_eans e
inner join products p on e.products_id = p.id
WHERE e.ean LIKE '%4788%'
OR p.name LIKE '%4788%'
but one other possibility is to avoid the OR in tha wheer clause by using a union query like this:
SELECT
COUNT(*)
FROM (
SELECT
product_id
FROM product_eans
WHERE ean LIKE '%4788%'
UNION
SELECT
id
FROM products
WHERE name LIKE '%4788%'
) d
After being inspired by Used_By_Already, I came across a simple idea:
SELECT
COUNT(DISTINCT products.id) AS count
FROM
products
WHERE
products.name LIKE "%4788%" OR
products.id in (SELECT product_id FROM product_eans WHERE ean "%4788%")
It's super fast now. So thanks to Used_By_Already.

mysql search with two joins and a count

I am currently trying to write a general query which returns the content of 1 table and another joined table plus the count of resulting rows from a third table.
Now my description might seem abstract so I'll try to visualize it
Tables:
posts
| ID | title | description | creator_id |
1 Title1 Descr1 1
2 Title2 Descr2 1
users
| ID | name | avatar |
1 User1 PATH
interactions
| ID | type | target_id | identifier |
1 view 1 IP
2 view 1 IP
Now what I am looking for is an output like this:
| ID | title | description | name | avatar | view_count |
1 Title1 Descr1 User1 PATH 2
2 Title2 Descr2 User1 PATH 0
My current query looks like following:
SELECT
posts.id, posts.title, posts.description,
users.name, users.avatar,
COUNT(interactions.id) AS view_count
FROM
posts
LEFT JOIN
users
ON
posts.creator_id = users.id
LEFT JOIN
interactions
ON
posts.id = interactions.target_id
But only prints out the posts result which has an interaction like this:
| ID | title | description | name | avatar | view_count |
1 Title1 Descr1 User1 PATH 2
How do I need to alter the query in order to also get the other rows which happen to not have any interactions yet?
Thank you for your help!
You can simply subquery third table to count entries:
SELECT
posts.id, posts.title, posts.description,
users.name, users.avatar,
(SELECT COUNT(*) FROM interactions i WHERE i.target_id = posts.id) AS view_count
FROM
posts
LEFT JOIN
users
ON
posts.creator_id = users.id
This is also better for performance (no groups, no unoptimized joins)
Try this:
SELECT P.ID
, P.title
, P.description
, U.name
, U.avatar
, IFNULL(COUNT(I.ID), 0) AS view_count
FROM posts P
LEFT JOIN users U ON U.ID = P.creator_id
LEFT JOIN interactions I ON I.target_id = P.ID
GROUP BY P.ID
It seems like you missed the GROUP BY clause. Without this, when you use an aggregate function like COUNT, the documentation says:
there is a single group and it is indeterminate
which name value to choose for the group
That's why your query only returned 1 row.
Try this;)
select posts.id, posts.title, posts.description, users.name, users.avatar, coalesce(t3.view_count, 0) as view_count
from posts
left join users on posts.creator_id = users.id
left join (
select target_id, count(1) as view_count from interactions group by target_id
) t3 on posts.id = t3.target_id
SQLFiddle HERE

many to many to many mysql query

I'm trying to create a database that is structured so that I can do ONE query and get all the data I need.
this is how I have it structured now:
Products Subcategory Category
------------- ------------- -------------
| id | name | | id | name | | id | name |
It makes sense to me to create two relational tables that ties the product to the subcategory, and the subcategory to the category (making it hierarchical):
prod_sub_relation sub_cat_relation
---------------------------- ---------------------------
| id | prod_id | subcat_id | | id | subcat_id | cat_id |
So the product can be in MULTIPLE subcategories, and the subcategory tells us what category the product is in.
With this structure, if I wanted to find all the products with a category_id, I'd have to query the sub_cat_relation table, then take that array and make another query for the prod_sub_relation table (and that's just messy).
My goal is to find all products, or all categories, or all subcategories with ONE id (whether it's product_id, category_id, or subcategory_id)
Is this possible? or am I doing something wrong here?
As already mentioned by #har07 you could use a simple JOIN on this one.
I am not exactly sure the other details of the structure of your tables but
I will show you based on what you have provided so far:
SELECT p.ID, p.Name, c.Name as CategoryName, s.Name as SubCategoryName
FROM Products P
INNER JOIN SubCategory S
ON P.subcat_id = S.subcat_id
INNER JOIN Category C
ON S.cat_id = C.cat_id
You could then use a WHERE clause to specify which product you want to display along with its category and subcategory
SELECT P.ID, P.Name, C.Name as CategoryName, S.Name as SubCategoryName
FROM Products P
INNER JOIN SubCategory S
ON P.subcat_id = S.subcat_id
INNER JOIN Category C
ON S.cat_id = C.cat_id
WHERE P.ID = valuehereforyourID
To get the Products and SubCategory for a given category ID you just change the WHERE clause, like:
WHERE C.cat_id = ValueForCategoryIDhere
To get the Products and Category for a given Subcategory ID you just change the WHERE clause, like:
WHERE S.subcat_id = ValueForSubCategoryIDhere
Put each products' categories in an array, serialize the array, and store that in the DB...

MySQL query with several values in one result

I need to get a list of rows with one query where one of the column consists of several values and I couln't figure this out.
I have three tables that logs mailings to people. One table has all the contact data of a person such as first_name, last_name, address etc. Second table consist of list of mailing names with its unique IDs. Like #1 - Mailing_1, #2 Mailing_2 etc. The third table liaise those two by logging mailing id and people id. Now I need to get the full list of people where the last column would show list of mailins each people got.
Here is what I have tried:
SELECT p.fname, p.lname, p.address m.mailing_name FROM people p
JOIN mailings_liaison l ON l.contact_id - p.id
JOIN mailings m ON m.id = l.mailings_id
WHERE 1
ORDER by p.lname ASC
I get what I need by this but if a person had two or more mailings it shows up as additional rows. I would need to unite those rows so each person has only one row in the query result with several mailings listed in the last column, i.e. I get:
| 1. | John | White | john#white.ru | Mailing_1 |
| 2. | John | White | john#white.ru | Mailing_2 |
But somehow instead I want to get:
| 1. | Jhon | White | john#white.ru | Mailing_1 Mailing_2 |
Is this possible?
use GROUP_CONCAT
SELECT p.fname, p.lname, p.address,
GROUP_CONCAT(m.mailing_name SEPARATOR ' ')
FROM people p
JOIN mailings_liaison l ON l.contact_id - p.id
JOIN mailings m ON m.id = l.mailings_id
GROUP BY p.fname, p.lname, p.address
ORDER by p.lname ASC
MySQL GROUP_CONCAT()

mysql - selecting groups and users all in same query

I have following two tables 'USERS' and 'GROUPS':
USERS
-id
-name
-groupid
GROUP
-id
-name
I'd like to return all users along with their group's name and group id. It should be an outer join on group id field correct?
A simple INNER JOIN should be enough:
SELECT `USERS`.*, `GROUP`.name AS group_name
FROM `USERS`, `GROUP`
WHERE `USERS`.groupid = `GROUP`.id
You're going to want to look at the JOIN statement
Doing this from my phone, so pardon any moderately incorrect syntax, but something a long the lines of
Edit: other guy's syntax is better. It's too early here
You can use a LEFT JOIN between users and groups so that users who are not in a group still show up in the result set, but with group name and id NULL:
SELECT
a.*,
b.name AS group_name
FROM
users a
LEFT JOIN
`group` b ON a.group_id = b.id
Side note: Ensure that you're encasing the table name group in backticks because it is a reserved keyword.
The result-set should look something like:
id | name | group_id | group_name
-----------------------------------------------------------------------------
1 | John | 5 | ThisIsGroup5
3 | Tim | 3 | ThisIsGroup3
6 | NotInGroup | NULL | NULL
Changing LEFT to INNER in the above query would INNER JOIN the two tables and exclude the user "NotInGroup" from the result-set.