Output of two different queries as one result in oracle - sql

I have two different tables and I want to get these two different output in single result. Here I want to display the result of both queries in single report.
Query 1
Select name, sum(purchasqty)-sum (soldqty) as pending
from (select p.name, p.qty as purchasqty, s.qty as soldqty
from purchase p
left join sold s on p.id = s.id )
group by name;
Query 2
Select name, sum(qty) as damage
from purchase p
where con = 'c'
group by name

This will do
Select name, sum(purchasqty)-sum (soldqty) as pending, '' as damage
from (select p.name, p.qty as purchasqty, s.qty as soldqty
from purchase p
left join sold s on p.id = s.id )
group by name
union all
Select name, '' as pending, sum(qty) as damage
from purchase p
where con = 'c'
group by name

This is a little tricky because you seem to be aggregating at a level different from what you are joining on. I would recommend:
select p.name, (p.purchasqty - coalesce(ps.soldqty, 0) as pending ,
p.damage
from (select p.name, sum(qty) as purchase_qty,
sum(case when con = 'c' then qty else 0 end) as damage
from purchase p
group by p.name
) p left join
(select p.name, sum(s.qty) as soldqty
from purchase p join
sold s
on p.id = s.id
group by p.name
) ps
on ps.name = p.name;

Related

SQL. Find the customers who bought same brands and at-least 2 products in each brand

I have two tables :
Sales
columns: (Sales_id, Date, Customer_id, Product_id, Purchase_amount):
Product
columns: (Product_id, Product_Name, Brand_id,Brand_name)
I have to write a query to find the customers who bought the brands 'X' and 'Y' (both) and at least 2 products of each brand. Is the following query correct? Any recommended changes?
SELECT S.Customer_id "Customer ID"
FROM Sales S LEFT JOIN Product P
ON S.Product_id = P.Product_id
AND P.Brand_Name IN ('X','Y')
GROUP BY S.Customer_id
HAVING COUNT(DISTINCT S.Product_id)>=2 -----at least 2 products in each brand
AND COUNT(S.Customer_id) =2 ---------------customers who bought both brands
Any help will be appreciated. Thanks in advance
Use COUNT() window function to count the number of distinct brands and the number of distinct products of each brand that each customer has bought.
Then filter out the customers who haven't bought both brands and GROUP BY customer with a HAVING clause that filters out the customers who haven't bought at least 2 products of each brand.
Also your join should be an INNER join and not a LEFT join.
select t.customer_id "Customer ID"
from (
select s.customer_id,
count(distinct p.brand_id) over (partition by s.customer_id) brands_counter,
count(distinct p.product_id) over (partition by s.customer_id, p.brand_id) products_counter
from sales s inner join product p
on p.product_id = s.product_id
where p.brand_name in ('X', 'Y')
) t
where t.brands_counter = 2
group by t.customer_id
having min(t.products_counter) >= 2
Starting from your existing query, you can use the following HAVING clause:
HAVING
AND COUNT(DISTINCT CASE WHEN p.brand_name = 'X' then S.product_id end) >= 2
AND COUNT(DISTINCT CASE WHEN p.brand_name = 'Y' then S.product_id end) >= 2
This ensures that the customer bought at least two products in both brands. This implicitly guarantees that it placed ordered in both brands, so there is no need for additional logic for this.
You could also express this with MIN() and MAX():
HAVING
AND MIN(CASE WHEN p.brand_name = 'X' THEN S.product_id END)
<> MAX(CASE WHEN p.brand_name = 'X' then S.product_id end)
AND MIN(CASE WHEN p.brand_name = 'Y' THEN S.product_id END)
<> MAX(CASE WHEN p.brand_name = 'Y' then S.product_id end)
You can use two levels of aggregation:
SELECT Customer_id
FROM (SELECT S.Customer_id, S.Brand_Name, COUNT(DISTINCT S.Product_Id) as num_products
FROM Sales S LEFT JOIN
Product P
ON S.Product_id = P.Product_id
WHERE P.Brand_Name IN ('X', 'Y')
GROUP BY S.Customer_id, S.Product_Id
) s
GROUP BY Customer_Id
HAVING COUNT(*) = 2 AND MIN(num_products) >= 2;

Display Product Name and City where that product sold in largest quantity

I'm trying to get a query to display the product name and city where the product had the highest quantity sold. Here is the code I'm working with:
SELECT DISTINCT
(s.city),
MAX(t.quantity),
p.Name
FROM [DS715-Cameron-Erwin].dbo.Tb_Transactions AS t,
[DS715-Cameron-Erwin].dbo.Tb_Product AS p,
[DS715-Cameron-Erwin].dbo.Tb_Supplier AS s
WHERE p.prod_id = t.prod_id
AND s.Supp_ID = t.Supp_ID
GROUP BY t.Prod_ID,
p.name,
s.city
ORDER BY p.name, s.city
This is giving me the highest quantity sold for each product in each city.
Sample Data
From the screenshot there are multiple records for each product (Airplane, Auto, Boat...). I'm trying to get a single record for each product where ever the highest quantity was purchased.
So, the top record would only show for Airplane because the most orders were from there.
You want to use the ROW_NUMBER() OVER functionality to order by the quantity and then select the one with the biggest quantity over each product.
SELECT
city,
quantity,
name
FROM
(
SELECT S.city,
T.quantity,
P.name,
ROW_NUMBER() OVER
( PARTITION BY
P.name
ORDER BY t.Quantity DESC
) as RowNum
FROM
Tb_Transactions T
INNER JOIN
Tb_Product P
ON
P.prod_id = T.prod_id
INNER JOIN
Tb_Supplier S
ON
S.supp_id = T.supp_id
) a
WHERE
RowNum = 1
http://sqlfiddle.com/#!6/628458/5
For this, I would use a CTE (also I would use the explicit INNER JOIN syntax):
;With CTE
As
(
Select
s.city
, t.quantity
, p.Name
, Row_Number Over (Partition By P.Name, s.city Order By t.Quantity Desc) as RN
From [DS715-Cameron-Erwin].dbo.Tb_Transactions as t
Inner Join [DS715-Cameron-Erwin].dbo.Tb_Product as p
On p.prod_id = t.prod_id
Inner Join [DS715-Cameron-Erwin].dbo.Tb_Supplier as s
On s.Supp_ID = t.Supp_ID
)
Select
city
, quantity
, Name
From CTE
Where RN = 1

Oracle SQL - Getting Max Date with several joins

I think I may be overthinking this, but I'm having an issue when trying to find a max date with several joins in an Oracle database as well as several where clauses. I've found many examples of simple max queries, but nothing specifically like this. The query works fine if I add a line in to find all records above a specific date (there are only a handful of results returned). However, I want to automatically get the most recent date for all records from the bill table. This database has an additional table where the actual bill amount is stored, so that adds another layer.
SELECT p.purchase_id, p.account_id, b.bill_date, bp.current_amount
FROM Purchases p
JOIN Bill_Purchases bp ON p.purchase_id = bp.purchase_id
JOIN Bills b ON bp.bill_id = b.bill_id
--NEED TO GET MOST RECENT DATE FROM BILL TABLE FOR EACH BILL
WHERE p.type != 'CASH'
AND bp.amount > '100.00'
AND p.status = 'Approved'
AND p.purchase_id IN ( ... list of purchases ...);
I have tried doing subqueries with Max functions in them, but am not having any luck. Each query returns the same amount of records as the original query. How would I rearrange this query to still retrieve all of the necessary columns and where clauses while still limiting this to only the most recent purchase that was billed?
Try like below this
SELECT p.purchase_id, p.account_id, b.bill_date, bp.current_amount
FROM Purchases p
JOIN Bill_Purchases bp ON p.purchase_id = bp.purchase_id
JOIN ( SELECT bill_id, MAX(bill_date) bill_date
FROM Bills
GROUP BY bill_id
)b ON bp.bill_id = b.bill_id
WHERE p.type != 'CASH'
AND bp.amount > '100.00'
AND p.status = 'Approved'
AND p.purchase_id IN ( ... list of purchases ...);
You may want to solve this problem using Rank() function,
SELECT p.purchase_id, p.account_id, , bp.current_amount, RANK() OVER ( partition by b.bill_id order by b.bill_date) as max_bill_date
FROM Purchases p
JOIN Bill_Purchases bp ON p.purchase_id = bp.purchase_id
JOIN Bills b ON bp.bill_id = b.bill_id
--NEED TO GET MOST RECENT DATE FROM BILL TABLE FOR EACH BILL
WHERE max_bill_date = 1
AND p.type != 'CASH'
AND bp.amount > '100.00'
AND p.status = 'Approved'`enter code here`
AND p.purchase_id IN ( ... list of purchases ...);
Do either of these work for you?
WITH data as (
SELECT
p.purchase_id, p.account_id, b.bill_date, bp.current_amount,
FROM
Purchases p
INNER JOIN Bill_Purchases bp ON p.purchase_id = bp.purchase_id
INNER JOIN Bills b ON b.bill_id = bp.bill_id
WHERE p.type <> 'CASH'
AND bp.amount > '100.00'
AND p.status = 'Approved'
AND p.purchase_id IN ( ... list of purchases ...)
), most_recent as (
SELECT max(bill_date) as bill_date FROM data
)
SELECT *
FROM data
WHERE bill_date = (select bill_date from most_recent);
SELECT purchase_id, account_id, bill_date, current_amount
FROM (
SELECT
p.purchase_id, p.account_id, b.bill_date, bp.current_amount,
dense_rank() over (order by b.bill_date desc) as dr
FROM
Purchases p
INNER JOIN Bill_Purchases bp ON p.purchase_id = bp.purchase_id
INNER JOIN Bills b ON b.bill_id = bp.bill_id
WHERE p.type <> 'CASH'
AND bp.amount > '100.00'
AND p.status = 'Approved'
AND p.purchase_id IN ( ... list of purchases ...)
) data
WHERE dr = 1;
I got this working pretty much right after posting, was a stupid mistake on my part. Data for the max function needed to be joined on the account_id, not the bill_id.

filling one table column with if else statement in SQL

I want to check if a product is one of TOP 10 product (from eye side of selling in Sales.SalesOrderDetails) make one column and set it to YES or NO
I have TOP 10 products of MAX selling like this:
SELECT TOP 10 p.Name , COUNT(*) 'Num of sell' FROM Sales.SalesOrderDetail SOD
inner join Production.Product p on SOD.ProductID = p.ProductID
GROUP BY p.Name
ORDER BY COUNT(*) DESC
now i want another table which is all of products and I want to somehow put a column with a if/else statement and put yes or no in there. like:
SELECT p.Name, #someVariable FROM Production.Product p
IF p.Name IN
(SELECT TOP 10 p.Name , COUNT(*) 'Num of sell' FROM Sales.SalesOrderDetail SOD
inner join Production.Product p on SOD.ProductID = p.ProductID
GROUP BY p.Name
ORDER BY COUNT(*) DESC)
#someVariable = 'YES'
ELSE #someVariable = 'NO'
any idea ?
You can do:
SELECT p.Name,
CASE WHEN X.ProductID IS NULL THEN 'NO' ELSE 'YES' END AS InTopTen
FROM Production.Product p
LEFT JOIN
(
SELECT TOP 10 ProductID FROM Sales.SalesOrderDetail
GROUP BY ProductID
ORDER BY COUNT(*) DESC
) X
ON X.ProductID = p.ProductID

Retrieving multiple rows in SQL Server but distinct filtering only on one

I have this:
SELECT Product.ProductID, Product.Name, Product.GroupID, Product.GradeID,
AVG(tblReview.Grade) AS Grade
FROM Product left Join tblReview ON Product.GroupID = tblReview.GroupID
WHERE (Product.CategoryID = #CategoryID)
GROUP BY Product.ProductID, Product.Name, Product.GroupID, Product.GradeID
I would like to return only the rows where Product.Name is unique. If I make a SELECT DISTINCT the ProductID is different on every row so all the rows are unique.
You could do something like this (see below), but this assumes that you don't care if 2 products with the same name have a different GroupID, etc. because you can't really list those unless you use a different approach (multiple queries).
SELECT Product.Name
, max(Product.ProductID) as ProductID
, max(Product.GroupID) as GroupID
, max(Product.GradeID) as GradeID,
, AVG(tblReview.Grade) AS Grade
FROM Product left Join tblReview ON Product.GroupID = tblReview.GroupID
WHERE (Product.CategoryID = #CategoryID)
GROUP BY Product.Name
HAVING COUNT(distinct Product.Name) = 1
Should this work for you?
SELECT Product.ProductID, Product.Name, Product.GroupID, Product.GradeID,
AVG(tblReview.Grade) AS Grade
FROM Product left Join tblReview ON Product.GroupID = tblReview.GroupID
WHERE (Product.CategoryID = #CategoryID)
GROUP BY Product.ProductID, Product.Name, Product.GroupID, Product.GradeID
HAVING COUNT(Product.Name)=1
SELECT p.ProductID, p.Name, p.GroupID, p.GradeID,
(
SELECT AVG(grade)
FROM tblReview r
WHERE r.GroupID = p.GroupID
) AS Grade
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY productID) AS rna,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY productID DESC) AS rnd
FROM Product
WHERE CategoryID = #CategoryID
) p
WHERE rna = rnd