Help with a MySQL query - php

Given the following tables I would like to know how to write a query to return only the categories that have books in them and the number of books for each category. A book can be added in one or many categories. I'm using PHP and MySQL.
Here are my tables:
categories table
- id
- name
- permalink
books table
- id
- title
- author
- description
- price
books_categories table
- id
- book_id
- category_id

select c.id
,c.name
,count(*) as num_books
from categories c
join books_categories bc on(bc.category_id = c.id)
group
by c.id
,c.name;
Use LEFT JOIN if you also want the categories without books.

SELECT *, COUNT(*) AS count
FROM books_categories AS bc
LEFT JOIN categories AS c ON c.id = bc.category_id
GROUP BY c.id
You'll get a count column with the number of rows for each category. Categories with zero books (that is those with no entry in table books_categories) won't be returned.

SELECT categories.id,
COUNT(books_categories.id) AS number
FROM categories
LEFT JOIN books_categories ON books_categories.category_id = categories.id
GROUP BY categories.id
HAVING number > 0;

Related

Php, Mysql sort results based on number of records from another table

I'm joining two tables to display car brands. Here is the structure:
SELECT DISTINCT
b.title
FROM
brands as b
INNER JOIN items as i
ON i.brand_id = b.id
WHERE i.status = 1
ORDER BY COUNT(i.brand_id) DESC;
The above only produces one record. If I remove "ORDER BY COUNT(i.brand_id) DESC;" it displays all the records correctly.
I would like to sort result based on number of vehicles under each brand category. So for example if bmw category has the most car listed under, it should be the first one.
SELECT b.title
FROM brands as b
INNER JOIN items as i
ON i.brand_id = b.id
WHERE i.status = 1
GROUP BY b.title
ORDER BY COUNT(i.brand_id) DESC;
This should work for you.
I would use
SELECT b.title, count(i.brand_id)
FROM items i
LEFT JOIN brands as b
ON b.id = i.brand_id
WHERE i.status = 1
GROUP BY i.brand_id
ORDER BY COUNT(i.brand_id) DESC;
Your concern is the amount of cars in inventory. You want to break them down by how many of each brand you have. So, you're mainly concerned with the items tables and only need the brands table to get the information stored in the items table (brand name). Lastly, in order to get aggregate the number of brands of each, you must let MySQL know what you want in the GROUP BY.
I haven't used an EXPLAIN, but I would think the bottom query is more efficient.
You could join brands on an aggregate query:
SELECT b.title
FROM brands b
INNER JOIN (SELECT brand_id, COUNT(*) AS cnt
FROM items
WHERE status = 1
GROUP BY brand_id) i ON i.brand_id = b.id
ORDER BY cnt DESC;

Display categories with number of posts

I'm making a blog. I have 2 tables, one for posts and the other for categories.
I want to display the category name, category date and the number of posts in each category. I have problems to display the number of posts in each category.
In posts table I have a column called cat_id which is equal to category.id
I have these 2 MySQL queries:
mysql_query("select Count(posts.id) as NumberOfPosts, cat_id from posts group by cat_id");
And
mysql_query("select name, date from categories");
I don't know how to have combine these two queries into one query. I'm using PHP.
You could use a join:
SELECT name, date, NumberOfPosts
FROM categories c
JOIN (SELECT cat_id, COUNT(*) AS NumberOfPosts
FROM posts
GROUP BY cat_id) p ON c.id = p.cat_id
EDIT:
To include categories with no posts, you could use a left join instead of regular join. You just need to handle the nulls you'd get for NumberOfPosts, e.g., by using coalesce:
SELECT name, date, COALESCE(NumberOfPosts, 0) AS NumberOfPosts
FROM categories c
LEFT JOIN (SELECT cat_id, COUNT(*) AS NumberOfPosts
FROM posts
GROUP BY cat_id) p ON c.id = p.cat_id

How can i filter my data from mysql?

Let's say i have 3 tables:
table: SONGS
cell: ID primary key
cell: TITLE
cell: ADD_TIME
table: CATEGORIES
cell: ID primary key
cell: title
table: SONGS_CATEGORIES
cell: ID primary key
cell: SONG_ID
cell: CATEGORY_ID
Then let's assume that I have 3 songs(with id's 0, 1, 2), and I have 5 categories(rock, pop, rap and so on) and respectively, their id's(0, 1, 2...). How my sql query should look like, if I want to be able to select more than one category, then I need to look into table SONGS_CATEGORIES and get all songs_id with category id I selected, and then i get songs from table SONGS with those id's?
Hope i explained what i need pretty well, English is not my native language.
If you already know the ID numbers of the categories that you're wanting songs from then the following should do the trick:
SELECT *
FROM SONGS s
JOIN SONGS_CATEGORIES sc
ON s.ID = sc.SONG_ID
WHERE sc.CATEGORY_ID IN (#id1, #id2, #id3...#idN);
If you only know the names of the categories you want the songs for then you can use this:
SELECT *
FROM SONGS s
JOIN SONGS_CATEGORIES sc
ON s.ID = sc.SONG_ID
JOIN CATEGORIES c
ON sc.CATEGORY_ID = c.ID
WHERE c.title IN (#catTitle1, #catTitle2, #catTitle3...#catTitleN);
In both of these examples you would replace the # with the data you are providing and adjust the SELECT part to show only the columns you need.
If you want to select songs from categories 1 & 2 :
SELECT s.id song_id, s.title song_title, s.add_time song_add_time, c.id cat_id, c.title cat_title
FROM CATEGORIES c
INNER JOIN SONGS_CATEGORIES sg
ON c.id = sg.category_id
INNER JOIN SONGS s
ON sg.song_id = s.id
WHERE c.id = 1 OR c.id = 2
I guess this is what you need
SELECT * -- select what ever columns you need to display
FROM SONGS s
JOIN SONGS_CATEGORIES sc
ON s.ID = sc.SONG_ID
JOIN CATEGORIES c
ON c.ID = sc.CATEGORY_ID
where c.title in ('title1','title2')

Show null results when left join don't find match

I have problem with join left. It work fine but i don't see null results. It connects three tables - categories, product_categories and order_products.
Query made by stack user look's like:
SELECT
categories.name,categories.id,
SUM((orders_products.product_price_gross + orders_products.option_price)*(1 - (orders_products.rebate/100)) * orders_products.product_qty) as suma
FROM orders_products
LEFT JOIN product_categories
ON product_categories.product_id = orders_products.product_id
LEFT JOIN categories
ON product_categories.category_id = categories.id
GROUP BY categories.name, categories.id
ORDER BY suma DESC
I'm not sure how upgrade this query - I need to see what never been sold to show on shop statistics.
I hope You could help me.
Kind regards
Mark
You want to see products that has not been sold? Your main table is the transaction table orders_products. So any product not "ordered" will not show. Interchange product_categories and orders_products to achieve what you want. This will list all categories and null out the "suma" if JOIN statement cannot find the product_id listed in the "order_products" table
SELECT
categories.name,
categories.id,
SUM((orders_products.product_price_gross + orders_products.option_price)*(1 - (orders_products.rebate/100)) * orders_products.product_qty) AS suma
FROM product_categories
LEFT JOIN orders_products
ON product_categories.product_id = orders_products.product_id
LEFT JOIN categories
ON product_categories.category_id = categories.id
GROUP BY categories.name, categories.id
ORDER BY suma DESC

MySQL - WHERE / HAVING count

I searched lots of similar topics about this but can't find the answer to this specific probem.
So I have a table with categories and I have another table with products, so what I want is select all the categories that contain at least 1 product, seems very easy but the following code dont give me what I expect.
SELECT *
FROM categories
INNER JOIN products on (categories.id = products.cat_id)
HAVING count(products.cat_id) > 0
All help is appreciated.
Thank you!
You can actually get what you want with just a join because any categories without products will not match.
You should also add a DISTINCT or GROUP BY to remove the duplicate category records from the results:
SELECT DISTINCT c.*
FROM categories c
JOIN products p
ON c.id = p.cat_id
OR:
SELECT c.*
FROM categories c
JOIN products p
ON c.id = p.cat_id
GROUP BY c.id
If you want something fancy like categories that have 2 or more products then you can use GROUP BY and HAVING:
SELECT c.*
FROM categories c
JOIN products p
ON c.id = p.cat_id
GROUP BY c.id
HAVING count(*) >= 2
Try this select in this select all categories that have at least one product
select categories.* from categories
left join products on (categories.id = products.cat_id)
where products.cat_id IS NOT NULL
group by categories.id
In this case you're not using "HAVING" but will have the same result

Categories