Select count of column grouped by another column SQL - sql

I have two tables, one called Products and one called Products_Category. I want to show the inventory count for each category (grouped by category), and also display the name of the category. The Products table has the inventory count for each Product, but the Products_Category table has the Category names. How can I display the two together? Should I be using some kind of join?
Here's what I'm trying to get:
Category_Name --------- Sum(Products_Inventory)
------Books -------------------- 1 ----------
------Toys---------------------- 2 ----------
But as of right now all I'm able to display is the category ID instead of the category name, like so:
------- 1 ------------------------ 1 ----------
------- 2 ------------------------ 2 ----------

Use JOIN and GROUP BY:
SELECT PC.Category_Name, Sum(P.Products_Inventory)
FROM Products_Category PC
INNER JOIN Products P ON PC.ProductId = P.ProductId
GROUP BY PC.Category_Name
BTW -- This assumes you have a ProductId field in each table. And if I could make a suggestion, you should probably have a Category table as well (better for normalization). Store your ProductId and CateogryId in your Products_Category table.
Good luck.

For these queries I assume product_id is on both tables (you'll have to use the correct field name if I guessed wrong). I'm also using Product_Category.description as the name of the field that has the category names.
This query will get you all categories, and a count of 0 for any product category that's not found in the Product table.
If Product contains one record for each product in stock (ie, 4 books would mean 4 Product records), than COUNT() is the function you want.
SELECT Products_Category.description, COUNT(Product.product_id) AS category_count
FROM Products_Category
LEFT OUTER JOIN Products ON Products_Category.product_id=Products.product_id
GROUP BY Products_Category.description
If Product contains one record for each type product in stock (ie, 4 books would mean 1 record with a product_count of 4), than SUM() is the function you want.
SELECT Products_Category.description, SUM(Product.product_count) AS category_count
FROM Products_Category
LEFT OUTER JOIN Products ON Products_Category.product_id=Products.product_id
GROUP BY Products_Category.description
If you only want records returned when you have inventory in that category, change the LEFT OUTER JOIN to INNER JOIN:
SELECT Products_Category.description, SUM(Product.product_count) AS category_count
FROM Products_Category
INNER JOIN Products ON Products_Category.product_id=Products.product_id
GROUP BY Products_Category.description

the most simplest way is to do this..
SELECT a.Category_Name, Sum(b.Products_Inventory)
FROM Products_Category a, Products b
Where a.ProductId = b.ProductId
GROUP BY a.Category_Name
hope it helps

Related

Lookup with duplicate values

This is kind of a complicated question. I have three tables:
A PRODUCTS table
ProductID
ProductName
Product A
Edwardian Desk
Product B
Edwardian Lamp
And a GROUPS table
ProductGroup
ProductID
Group A
Product A
Group A
Product B
Group B
Product C
And a SALES table
Product ID
Sales
Product A
1000
Product B
500
And I need to show the total of Sales per Product Group.
This part I understand; I wrote the query:
SELECT Groups.ProductGroup, SUM(Sales) AS TotalSales
FROM Groups
JOIN Sales
ON Groups.ProductID=Sales.ProductID
GROUP BY Groups.ProductGroup
This is the part that confuses me though: for each group, I need to pull in one of the names of the products in the group. However, it does not matter which name is pulled. So the final data could show:
Group A, Edwardian Desk, 1500
or
Group A, Edwardian Lamp, 1500
How can I pull the name of the product into my query?
I am working in Microsoft SQL Server
There's a number of ways to bring in one of your product's names, a couple of options are to either use an aggregation with a correlated subquery or to to use an apply.
Note, I've used aliases for your table names - doing so is good practice and makes queries more compact and easier to read. Also - presumably this is a contrived example and not your actual tables - but generally it's not a good practice to have column names identical to the table name, so if Sales on table Sales represents a quantity, then just call it Quantity!
select g.ProductGroup,
(select Min(ProductName) from Products p where p.ProductId=g.ProductId) FirstProductAlphabetically,
Sum(s.Sales) as TotalSales
from Groups g
join Sales s on s.ProductID=g.ProductID
group by g.ProductGroup
select g.ProductGroup,
p.ProductName as FirstProductById,
Sum(s.Sales) as TotalSales
from Groups g
join Sales s on s.ProductID=g.ProductID
cross apply (
select top (1) p.ProductName
from Products p
where p.ProductId=g.ProductId
order by ProductId
)p
group by g.ProductGroup
You can add products to the JOIN and use an aggregation function:
SELECT g.ProductGroup, SUM(s.Sales) AS TotalSales,
MIN(p.ProductName)
FROM Groups g JOIN
Sales s
ON g.ProductID = s.ProductID JOIN
Products p
ON p.ProductID = s.ProductId
GROUP BY g.ProductGroup;
Note: I often add two columns, MIN() and MAX() to get two sample names.
I should add. Your sample data has ProductIds that are not in the Products. That suggests a problem with either the question (more likely) or the data model. If you actually have references to non-existent products, then use a LEFT JOIN to Products rather than an inner join.

How can I sum data from mulitple rows which have the same foreign key into one row?

I have two tables which have a 1 to n relation. One table contains general Information of a bill (named bill)
(< -1 to n ->)
and the other contains Items which are on the bill (named items). I want a query that Lists all Bills and sums up the prices from the items in a new row. But of course i want every Bill listed just once not for every item.
Usually i don't post anything. But i can't find an answer because i don't know how to search for this problem. Sorry when this is obvious.
What my tables look like:
bill:
bill_id - customer - date
items:
item_id - bill_id - amount - price
A simple join with aggregation should work here:
SELECT
b.bill_id,
COALESCE(SUM(i.price), 0) AS total_price
FROM bill b
LEFT JOIN items i
ON b.bill_id = i.bill_id
GROUP BY
b.bill_id;
If you want to include the other two columns from the bill table, then just add them to the SELECT and GROUP BY clauses.
You may try this.
; with cte as (
select b.bill_id, i.item_id ,isnull(i.price,0) as Price from
Bill as b inner join items as i on b.bill_id =i.bill_id
union all
select b.bill_id , null, sum(isnull(i.price,0)) from
Bill as b inner join items as i on b.bill_id =i.bill_id
group by b.bill_id
)
select * from cte order by bill_id, item_id desc

SQL Beginner: Getting items from 2 tables (+grouping+ordering)

I have an e-commerce website (using VirtueMart) and I sell products that consist child products. When a product is a parent, it doesn't have ParentID, while it's children refer to it. I know, not the best logic but I didn't create it.
My SQL is very basic and I believe I ask for something quite easy to achieve
Select products that have children.
Sort results by prices (ASC/DSC).
SELECT * FROM Products INNER JOIN Prices ON Products.ProductID = Prices.ProductID ORDER BY Products.Price [ASC/DSC]
Explanation:
SELECT - Select (Get/Retrieve)
* - ALL
FROM Products - Get them from a DB Table named "Products".
INNER JOIN Prices - Selects all rows from both tables as long as there is a match between the columns in both tables. Rather, JOIN DB Table "Products" with DB Table "Prices".
ON - Like WHERE, this defines which rows will be checked for matches.
Products.ProductID = Prices.ProductID - Your match criteria. Get the rows where "ProductID" exists in both DB Tables "Products" and "Prices".
ORDER BY Products.Price [ASC/DSC] - Sorting. Use ASC for Ascending, DSC for Descending.
This table design is subpar for a number of reasons. First, it appears that the value 0 is being used to indicate lack of a parent (as there's no 0 ID for products). Typically this will be a NULL value instead.
If it were a NULL value, the SQL statement to get everything without a parent would be as simple as this:
SELECT * FROM Products WHERE ParentID IS NULL
However, we can't do that. If we make the assumption that 0 = no parent, we can do this:
SELECT * FROM Products WHERE ParentID = 0
However, that's a dangerous assumption to make. Thus, the correct way to do this (given your schema above), would be to compare the two tables and ensure that the parentID exists as a ProductID:
SELECT a.*
FROM Products AS a
WHERE EXISTS (SELECT * FROM Products AS b WHERE a.ID = b.ParentID)
Next, to get the pricing, we have to join those two tables together on a common ID. As the Prices table seems to reference a ProductID, we can use that like so:
SELECT p.ProductID, p.ProductName, pr.Price
FROM Products AS p INNER JOIN Prices AS pr ON p.ProductID = pr.ProductID
WHERE EXISTS (SELECT * FROM Products AS b WHERE p.ID = b.ParentID)
ORDER BY pr.Price
That might be sufficient per the data you've shown, but usually that type of table structure indicates that it's possible to have more than one price associated with a product (we're unable to tell whether this is true based on the quick snapshot).
That should get you close... if you need something more, we'll need more detail.
use the below script if you are using ssms.
SELECT pd.ProductId,ProductName,Price
FROM product pd
LEFT JOIN price pr ON pd.ProductId=pr.ProductID
WHERE EXISTS (SELECT 1 FROM product pd1 WHERE pd.productID=pd1.ParentID)
ORDER BY pr.Price ASC
Note :neither of your parent product have price in price table. If you want the sum of price of their child product use the below script.
SELECT pd.ProductId,pd.ProductName,SUM(ISNULL(pr.Price,0)) SUM_ChildPrice
FROM product pd
LEFT JOIN product pd1 ON pd.productID=pd1.ParentID
LEFT JOIN price pr ON pd1.ProductId=pr.ProductID
GROUP BY pd.ProductId,pd.ProductName
ORDER BY pr.Price ASC
You will have to use self-join:
For example:
SELECT * FROM products parent
JOIN products children ON parent.id = children.parent_id
JOIN prices ON prices.product_id = children.id
ORDER BY prices.price
Because we are using JOIN it will filter out all entries that don't have any children.
I haven't tested it, I hope it would work.

How do I query this case?

I have three tables.
Category(id, name);
Item(id, name, category);
SoldItem(id, item, qty);
My goal is simple, I want to list ALL the categories plus item count of those categories plus the count of sold items of the items of those particular categories as rows.
The result would be like this:
Category | Item count | Item sold count
----------------------------------------
Food | 2 | 50
----------------------------------------
Beverage | 3 | 60
How do I query this in PostgreSQL. Thanks in advance.
The key is to use count(distinct) when counting rows from the middle joined table, otherwise multiple grandchildren would result in the same patent being counted multiple times too:
select
c.name as category,
count(distinct i.id) as item_count,
sum(si.qty) as item_sold_count
from Category c
left join Item i on i.category = c.id
left join SoldItem si on si.item = i.id
group by c.name;
By using left joins, categories without items, and items with sales, will still show but with zeros for the totals.

SQL Select statement which shows row-specific count information?

I need some SQL help ..
Suppose I have 2 tables: Customers and Products.
Now, I want to see a SQL statement that will show me these two columns:
Customer | Number of orders placed
How do I do that ?
The second column is a non-existent column, which is showing a number which states how many orders that customer has placed.
For example:
Customer | Number of orders placed
-------- | -----------------------
John | 23
Jack | 5
Mary | 12
etc ..
What's the SQL for this kind of a select ?
I guess that the Product table contains a foreign key CustomerID which references the Customer. The resulting query would be
select Customers.Name, Count(*)
from Customers join Products
on Customers.CustomerID = Products.CustomerID
However, this is just a guess as you forgot to inform us about the relation between the two tables, i.e. how the Products know to which Customer they belong.
Also, but this is a bit picky, you want the number of orders but only have a 'Product' table...
JOIN. This is just making up your column names since tables weren't given.
SELECT
c.Name,
myOrders = COUNT(o.id)
FROM Customers c
INNER JOIN Orders o
ON c.id = o.customerId
GROUP BY c.Name
Some quick reading: JOINS. GROUP BY