SQL calculation issue - sql

I am trying to find the cost per category by joining two tables
I have wrote this query, but it seems to place the same resulting value for all categories.
SELECT category,
(select sum(count(partid) * p.cost)
from PARTS p join order_line o using (part_id)
group by category, p.cost)
from parts p join order_line o using (part_id)
group by category
Table structure:
Parts:PartID#,description,manu_date,manu_id,cost,retai,discount,category
Order_line: Order#,item#,PartID,manu_id,unitprice,quantity
What I am trying to accomplish is i want to times the cost per parts table, with the count of (quantity*partid) in the order_line table to find out which category has the highest cost.
I am using oracle 11g

your subquery isn't correlated with the embedding sql, therefore its result is the same for each category.
You do not need to weigh the part costs with the number of orders, this will happen implicitly through the join:
SELECT category
, sum (p.cost * o.quantity)
FROM parts p
JOIN order_line o USING (partid)
GROUP BY category
;

Related

How to do a 3-table join with aggregate functions and a group by clause

I can't figure out how to do a 3-table join with aggregate functions and a group by clause.
I have 3 tables:
Products
id
...
Sales
id
product_id
sale_price
...
Punches
id
punchable_id
punchable_type
...
I want to get all of the products data together with its total number of sales, views, (each row in punches table represents a view) and the total revenue from a product.
I have the following query:
#products = Product.joins("INNER JOIN sales ON sales.product_id = products.id INNER JOIN punches ON sales.product_id = punches.punchable_id AND punches.punchable_type = 'Product'").group("products.id").select("products.*, SUM(sales.sale_price) as revenue, COUNT(sales.id) as total_sales_count, COUNT(punches.id) as views").distinct
However, this is giving me the wrong data for the aggregate functions. The numbers are very high (I think it's summing and counting the rows a bunch of extra times).
When I do the Inner Join query with the products table and only one other table (either the punches or sales table), the data is fine. It blows up whenever I do the 2 joins in one query.
Does anyone know what's wrong with the above and how to properly write the query?
You should join to punches directly with products.id = punches.punchable_id ..etc not via sales.product_id

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.

SQL how to count the number of relations between two tables and include zeroes?

I have a table of orders, and a table of products contained in these orders. (The products-table has order_id, a foreign key referring to orders.id).
I would like to query the number of products contained in each order. However, I also want orders to be contained in the results if they do not contain any products at all.
This means that a simple
SELECT *, COUNT(*) n_products FROM `orders` INNER JOIN `products` on `products.order_id` = `orders.id` GROUP_BY `order_id`
does not work, since orders without any products disappear.
Using a LEFT OUTER JOIN instead would add rows without product-information, but the distinction between an order with 1 product and an order with 0 products is lost.
What am I missing here?
You need a left join here, and you should be counting some column from the products table:
SELECT
o.*,
COUNT(p.order_id) AS n_products
FROM orders o
LEFT JOIN products p
ON p.order_id = o.id
GROUP BY
o.id;
Note that I assume that Postgres would allow grouping by orders.id and then selecting all columns from that table. If not, then you would only be able to select o.id in addition to the count.

SQL Counting the amount of times a value from one table shows up in another

I am trying to work out how to go about this one SQL query.
I have two tables Orders and Customers.
Orders has two columns CustomerNumber and Fruit
Customers has two columns as well CustomerNumber and Address
Not all customers have placed an order but I need a query that runs through the list of Customers.CustomerNumber and lists how many times that Customers.CustomerNumber times shows up in the table Orders.
It's a countif query but im not sure how to set it up.
select customer.id, count(order.*)
from Customer inner join Order on Customer.id=Order.ID
group by customer.id
select c.CustomerNumber, count(1)
from Customer as c
left join Order as o on c.CustomerNumber = o.CustomerNumber
group by c.CustomerNumber
This will return a zero for customer's without any orders.

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.