Show null values while joining SQL Server tables - sql

Stuck on this assignment and its not displaying null values as it should.
Instructions:
List the number of transactions handled by each department. Include
departments that have not handled any transactions. Show your results
in ascending order on department.
This is what I have so far and it displays the total transactions for departments with transaction and skips the null values.
SELECT
PC.Department,
COUNT(TD.TransactionID) AS TotalTransactions
FROM
TRANSACTION_DETAILS TD
INNER JOIN
PRODUCTS P ON P.ItemCode = TD.ItemCode
LEFT OUTER JOIN
PRODUCT_CATEGORIES PC ON P.Category = PC.Category
GROUP BY
PC.Department
ORDER BY
PC.Department ASC

SELECT PC.Department, COUNT(TD.TransactionID) AS TotalTransactions
FROM PRODUCT_CATEGORIES PC
LEFT JOIN PRODUCTS P ON P.Category = PC.Category
LEFT JOIN TRANSACTION_DETAILS TD ON P.ItemCode = TD.ItemCode
GROUP BY PC.Department
ORDER BY PC.Department ASC

If you need also department without value you need left join starting PRODUCT_CATEGORIES ( Department)
SELECT PC.Department, COUNT(TD.TransactionID) AS TotalTransactions
FROM PRODUCT_CATEGORIES PC
LEFT JOIN PRODUCTS P ON P.Category = PC.Category
LEFT JOIN TRANSACTION_DETAILS TD ON P.ItemCode = TD.ItemCode
GROUP BY PC.Department
ORDER BY PC.Department ASC

Related

Maria DB SQL group by and sum query is slow

My My SQl query is taking 6 sec to execute, I have added index on the where field, but its still same speed, then I remove the where clause and check the speed, the different is very small. So the problem is in SUM and Group By, I have read to optimize Group by adding index on Group BY fields but they are on different columns. Not an Expert in Mysql im a java developer.
SELECT
IF(
categories_1.NAME IS NULL,
categories.name,
categories_1.name
) AS PARENTCAT,
categories.NAME AS SUBCAT,
products.REFERENCE AS PRODREF,
products.NAME AS PRODNAME,
SUM(ticketlines.UNITS) AS UNITS,
SUM(ticketlines.PRICE * ticketlines.UNITS) AS SALES
FROM
taxes taxes
INNER JOIN ticketlines ticketlines ON (taxes.ID = ticketlines.TAXID)
INNER JOIN products products ON (products.ID = ticketlines.PRODUCT)
RIGHT OUTER JOIN categories categories ON (categories.ID = products.CATEGORY)
LEFT OUTER JOIN categories categories_1 ON (categories.PARENTID = categories_1.ID)
INNER JOIN tickets tickets ON (tickets.ID = ticketlines.TICKET)
INNER JOIN receipts receipts ON (tickets.ID = receipts.ID)
WHERE
(
receipts.DATENEW BETWEEN DATE('2021-12-01 00:00:00.000')
AND DATE('2022-02-18 00:21:00.000')
)
GROUP BY
categories.NAME,
products.REFERENCE
ORDER BY
PARENTCAT ASC,
SUBCAT ASC,
PRODNAME ASC
The Index in on receipts.DATENEW

How to list products that belong to more than 3 private categories

What's the SQL to find the list of products that belong to more than 3 private categories.
I tried this:
SELECT
products.*
FROM
products
INNER JOIN
product_categories
ON
products.product_id = product_categories.product_id
INNER JOIN
categories
ON
product_categories.category_id = categories.category_id
WHERE
categories.is_private = 1
GROUP BY
categories.category_id
HAVING
COUNT(categories.category_id) > 3
Thanks!
Your query would be correct if you aggregated by products.product_id -- well, depending on the database, you might need to include other columns in the SELECT. But it is valid SQL assuming that product_id is unique in that table.
If you only want the product ids you don't need the products table:
select pc.product_id
from product_categories pc join
categories c
on pc.category_id = c.category_id
where is_private = 1
group by pc.product_id
having count(*) > 3;
you need every product witch .... so you should do group by on productID.also you can add other columns of products that you need in both 'select' and 'group by'
SELECT
products.product_id,products.name
FROM
products
INNER JOIN
product_categories
ON
products.product_id = product_categories.product_id
INNER JOIN
categories
ON
product_categories.category_id = categories.category_id
WHERE
categories.is_private = 1
GROUP BY
products.product_id,products.name
HAVING
COUNT (categories.category_id) > 3
To get all columns of products:
SELECT products.*
FROM products p
WHERE product_id in (SELECT pc.product_id
FROM product_categories pc
INNER JOIN categories c ON pc.category_id = c.category_id
WHERE c.is_private = 1
GROUP BY c.category_id
HAVING COUNT(c.category_id) > 3)
Check this out!
select * from products where product_id in
(select pc.product_id from product_categories inner join categories c on
pc.category_id=c.category_id where c.is_private=1
group by c.category_id having count(c.category_id)>3)

How do we find which customers placed orders with items made in USA refer to image

Which customers placed orders with items made inside the USA?
SELECT DISTINCT, WHERE, Temporary Table, Subquery
tables to refer
I would use exists with a correlated subquery that follows the relationships like customer > order > order_item > product > supplier and filters on US suppliers:
select c.*
from customer c
where exists (
select 1
from order o
inner join order_item oi on oi.order_id = o.id
inner join product p on p.id = oi.product_id
inner join supplier s on s.id = p.supplier_id
where o.customer_id = c.id and s.country = 'USA'
)

sql - aggregation issue

I have two tables in my DB - products & orders. An order can only be of one kind of product.
Here's the basic idea:
What I'm trying to do is a query that given a copmany_id returns all the products (from that company) that have less than 10 orders (including 0)
my query looks like this:
SELECT p.*
FROM product p,
order o
WHERE p.company_id =?
AND o.product_id = p.id
GROUP BY p.id
HAVING Count(o.id) < 10
ORDER BY p.id DESC
The query works fine for products which have 0 < orders but doesn't return ones with 0 orders. What do I need to do to return them as well?
You're INNER JOINING your two tables, which means that only those products are returned for which there is at least one order.
You will need to LEFT OUTER JOIN the order table:
SELECT p.*
FROM product p
LEFT OUTER JOIN order o
ON o.product_id = p.id
WHERE p.company_id = ?
GROUP BY p.id
HAVING Count(o.id) < 10
ORDER BY p.id DESC
A left outer join will return every record on the left-hand side of the JOIN operation at least once, regardless if there is a matching record to the right-hand side of the JOIN operation.
try left outer join
SELECT p.*
FROM product p
LEFT OUTER JOIN order o
ON o.product_id = p.id
WHERE p.company_id =?
GROUP BY p.id
HAVING Count(o.id) < 10
ORDER BY p.id DESC
See this example for left outer join

Optimize JOIN SQL query with additional SELECT

I need a query which will select just one (GROUP BY phi.id_product) image for each product and this image have to be the one with the highest priority (inner SELECT with ORDER BY statement).
The priority is stored in N:M relation table called product_has_image
I've created a query, but it tooks about 3 seconds to execute and I need to optimize it. Here it is:
SELECT p.*, i.id AS imageid
FROM `product` p JOIN `category` c on c.`id` = p.`id_category`
LEFT OUTER JOIN (SELECT id_product, id_image FROM
`product_has_image` ORDER BY priority DESC) phi ON p.id = phi.id_product
LEFT OUTER JOIN `image` i ON phi.id_image = i.id
WHERE (c.`id_parent` = 2 OR c.`id` = 2)
GROUP BY phi.id_product
Indexes which I find to be important in this query are:
image (PRIMARY id)
product_has_image (PRIMARY id_product, id_image; INDEX id_product; INDEX id_image)
product (PRIMARY id, id_category; INDEX id_category)
category (PRIMARY id; INDEX id_parent)
Most of the time takes joining the tables using the SELECT statement which is required for sorting.
Joining with LEFT JOIN [product_has_image] phi ON p.id = phi.id_product is much faster, but doesn't assign the image with the highest priority.
Any help would be appreciated.
Reformatted for sensibility . . .
SELECT p.*, i.id AS imageid
FROM `product` p
INNER JOIN `category` c on (c.`id` = p.`id_category`)
LEFT OUTER JOIN (SELECT id_product, id_image
FROM `product_has_image`
ORDER BY priority DESC) phi
ON (p.id = phi.id_product)
LEFT OUTER JOIN `image` i
ON (phi.id_image = i.id)
WHERE (c.`id_parent` = 2 OR c.`id` = 2)
GROUP BY phi.id_product
Without seeing an execution plan or DDL, I'd guess (shudder) that the problem is likely to be the inner select/sort. If you create a view
create view highest_priority_images as
select id_product, max(priority)
from product_has_image
group by id_product
Then you can replace that inner SELECT...ORDER BY with a SELECT...INNER JOIN on that view. That would reduce the cardinality, so I'd expect it to run faster.
Posting DDL would help.
I would probably try to do it like this:
SELECT p.*, i.id AS imageid
FROM `product` p
INNER JOIN `category` c ON c.id = p.id_category
/* a list of `id_product`s with their highest priorities
from `product_has_image` */
LEFT OUTER JOIN (
SELECT id_product, MAX(priority) AS max_priority
FROM `product_has_image`
GROUP BY id_product
) m ON p.id = m.id_product
/* now joining `product_has_image` again, using
m.`max_priority` for additional filtering */
LEFT OUTER JOIN `product_has_image` phi
ON p.id = phi.id_product AND m.max_priority = phi.priority
/* if you only select `id` from `image`, you can use
phi.`id_image` instead and remove this join */
LEFT OUTER JOIN `image` i ON phi.id_image = i.id
WHERE c.id_parent = 2 OR c.id = 2
Can't test it now, but wouldn't it be possible to do this?
SELECT p.*, i.id AS imageid
FROM `product` p JOIN `category` c on c.`id` = p.`id_category`
LEFT JOIN `product_has_image` phi ON p.id = phi.id_product
LEFT OUTER JOIN `image` i ON phi.id_image = i.id
WHERE (c.`id_parent` = 2 OR c.`id` = 2)
GROUP BY phi.id_product
ORDER BY phi.priority DESC
Do it in a regular join and order by phi.priority.