(Advanced) Sql queries on database association table - sql

Assuming one has the following tables on an association in a database:
Customer(Id, Name, City),
Orders(Cust_Id, Prod_Id),
Product(Id, Name, Price, Country)
Taken for granted that a Customer has ordered a particular Product only once, I would like to execute the following queries:
1) Get the Customers ordered all the Products coming from Country "XY".
Is that the solution?:
Select *
from Customers c
join Orders o on c.id = o.orders.cust_id
join Product p on o.prod_id = p.id
where p.id = (Select id from Product where Product.country = "XY")
2) Get the Customers ordered Products only from the Country "XY"
What are the right queries in both cases?

1) Customers who ordered all the products of a specific country:
DECLARE #Country AS VARCHAR(100)
SET #Country = 'XY'
;WITH OrdersCTE AS
(
SELECT *
FROM Orders
WHERE Prod_Id IN (SELECT Id FROM Product WHERE Country = #Country)
)
SELECT *
FROM Customers
WHERE Id IN
(
SELECT Cust_Id
FROM OrdersCTE
GROUP BY Cust_Id
HAVING COUNT(DISTINCT Prod_Id) = (SELECT COUNT(*) FROM Product WHERE Country = #Country)
)
2) Customers who bought only products of a specific country:
DECLARE #Country AS VARCHAR(100)
SET #Country = 'XY'
SELECT C.Id,
C.Name,
C.City
FROM Customers C
Left JOIN Orders O
ON C.Id = O.Cust_Id
LEFT JOIN Product P
ON P.Id = O.Prod_Id
GROUP BY C.Id,
C.Name,
C.City
HAVING COUNT(DISTINCT Country) = 1

Related

Customer product sale query incorrect result in sql server 2016

My DDL looks like below:
CREATE TABLE CUSTOMER
(
ID INT PRIMARY KEY,
CUSTOMER_NAME VARCHAR(50),
CITY_ID INT,
)
CREATE TABLE product
(
id int,
sku VARCHAR(50),
product_name varchar(100),
stock_qty int
)
create table Invoice
(
id int,
invoice_number varchar(100),
customer_id int
)
CREATE TABLE Invoice_item
(
id int,
invoice_id int,
product_id int,
quantity decimal(5,2),
price decimal(5,2),
line_total_price decimal(5,2)
)
I am trying to get sales details of all customer and products
output should return all customer even customer without invoices and
also all product even those product that were not sold.
I need to print customer even not have invoice and even those product
that were not sold
than customer and product as NA and quantity as o
Code i have written:
SELECT ISNULL(c.customer_name,'N/A')AS customer_name,ISNULL(p.product_name,'N/A') AS product_name,
sum(ISNULL(invitm.quantity,'0')) as quantity
FROM customer as c left outer join product as p
on c.id = p.id
left outer join invoice as inv on c.id = inv.id
left outer join invoice_item as invitm on c.id = invitm.id
group by c.customer_name,p.product_name
But this is giving incorrect result. am i doing any mistake with join. please share your suggestion
If you want all customer and product combinations, then I would suggest:
select c.customer_name, p.product_name,
coalesce(sum(ii.quantity), 0) as quantity
from customer c cross join
product p left join
invoice i
on c.id = i.customer_id left join
invoice_item ii
on ii.invoice_id = i.id and ii.product_id = p.id
group by c.customer_name, p.product_name;
If you want all customer/product combinations that exist and then extras for the customers and products that don't exist, I would suggest union all:
select c.customer_name, p.product_name,
coalesce(sum(ii.quantity), 0) as quantity
from invoice i join
customer c
on c.id = i.customer_id join
invoice_item ii
on ii.invoice_id = i.id join
product p
on ii.product_id = p.id
group by c.customer_name, p.product_name
union all
select c.customer_name, null, 0
from customer c
where not exists (select 1 from invoice i where i.customer_id = c.id)
union all
select null, p.product_name, 0
from product p
where not exists (select 1 from invoice_item ii where ii.product_id = p.id);
Maybe like this (I have not checked syntax) - all your joins were totally wrong; you need to join on corresponding fields (foreign keys), not on id-s:
SELECT ISNULL(c.customer_name,'N/A')AS customer_name,ISNULL(p.product_name,'N/A') AS product_name,
sum(ISNULL(invitm.quantity,'0')) as quantity
FROM customer as c full outer join product as p
on c.product_id = p.id
left outer join invoice as inv on c.id = inv.customer_id
left outer join invoice_item as invitm on invitm.invoice_id = inv.id and invitm.product_id = p.id
group by c.customer_name,p.product_name
This is actually a interview question. Below query might be correct:
SELECT c.customer_name,
p.product_name,
Coalesce((ii.quantity), 0) AS quantity
FROM customer c
LEFT JOIN invoice i
on c.id = i.customer_id
LEFT JOIN invoice_item ii
ON ii.invoice_id = i.id
LEFT JOIN product p
ON ii.product_id = p.id
ORDER BY c.customerid,
p.product_id,
ii.id
UNION
SELECT 'N/A',
p.product_name,
0
FROM products p ORDER p.id

Subquery "Finding customer who has the most purchases"

I'm having trouble creating a query with a sub query to find the one customer in my DB who has made the most purchases. I need to list his/her full name, product name, price and quantity. Here is what I have so far
select first_name ||' '|| last_name "FullName", pt.name p.price, sum(ps.quantity)
from customers c
join purchases ps on c.customer_id = ps.customer_id
join products p on p.product_id = ps.product_id
join product_types pt on p.product_type_id = pt.product_type_id;
I need to use these three tables
Customers Table
Customer_ID
First_Name
Last_Name
DOB
Phone
Purchases Table
Product_ID
Customer_ID
Quantity
Products Table
Product_ID
Product_Type_ID
Name
Description
Price
Product Types Table
Product_Type_ID
Name
I am confused as where I should place the sub query (in the select row, from, having or where clause), if the arithmetic function should be placed in the select outer query or sub query. I know there are Nested subqueries, Correlated subqueries, Multiple-column subqueries, Multiple-row subqueries, Single-row subqueries. By the way, I am trying to do this in Oracle.
Here is an image with my result, except I removed sum from quantity column. Also, updated link.
(http://i1294.photobucket.com/albums/b618/uRsh3RRaYm0nD/Capture100_zps1f951b07.jpg)
I'm sorry, I forgot to include a fourth table, as you can see there are two name columns, in products table and product type table. The difference is that in products table "Name" is the specific name of the product, as shown in my link. The product type "Name" column is the more general name of the product, such as books, dvds, cds, etc. I need to include the product type "Name column in my query not product's name column. Therefore, the end result should look something like this
FullName ProductTypeName Price Quantity
John Brown Book Sumof4books 4
John Brown DVD Sumof2DVDs 2
John Brown Magazine Sumof1Mag 1
Here's one way to do it. It uses an analytic function to order customers by the total quantity of purchases: row_number() over (order by sum(quantity) desc). If there's more than one person with the same quantity, this will pick out only one.
It then takes this customer id and joins the rest of the tables in the obvious way to get the break down by product type.
Select
c.FullName,
pt.name,
Sum(p.price * ps.quantity) price,
sum(ps.quantity) quantity
From (
Select
c.Customer_ID,
c.first_name ||' '|| c.last_name FullName,
row_number() over (order by Sum(Quantity) desc) r
From
Purchases ps
Inner Join
Customers c
On ps.Customer_ID = c.Customer_ID
Group By
c.Customer_ID,
c.first_name ||' '|| c.last_name
) c
Inner Join
Purchases ps
On c.Customer_ID = ps.Customer_ID
Inner Join
Products p
On ps.Product_ID = p.Product_ID
Inner Join
Product_Types pt
On p.Product_Type_ID = pt.Product_Type_ID
Where
c.r = 1
Group By
c.FullName,
pt.name
Example Fiddle
For the second problem (show the customer who has the highest quantity for each product type, together with what they've spent on that product type)
Select
c.FullName,
c.name,
c.price,
c.quantity
From (
Select
c.first_name ||' '|| c.last_name FullName,
pt.name,
sum(p.price * ps.quantity) price,
sum(ps.quantity) quantity,
row_number() over (partition by pt.name order by Sum(Quantity) desc) r
From
Purchases ps
Inner Join
Customers c
On ps.Customer_ID = c.Customer_ID
Inner Join
Products p
On ps.Product_ID = p.Product_ID
Inner Join
Product_Types pt
On p.Product_Type_ID = pt.Product_Type_ID
Group By
c.first_name ||' '|| c.last_name,
pt.name
) c
Where
c.r = 1
Example Fiddle
Here is the general idea. You can adapt it for your database tables.
select fred, barney, maxwilma
from bedrock join
(select max(wilma) maxwilma
from bedrock
group by fred ) flinstone on wilma = maxwilma
SELECT CLIENT.CLIENTNO, CLIENT.CNAME, SUM(PURCHASE.AMOUNT) AS AMOUNT
FROM CLIENT
INNER JOIN PURCHASE
ON CLIENT.CLIENTNO = PURCHASE.CLIENTNO
WHERE CLIENT.CLIENTNO IN (
SELECT CLIENTNO
FROM (
SELECT PURCHASE.CLIENTNO, SUM(PURCHASE.AMOUNT) AS AMOUNT
FROM PURCHASE
GROUP BY PURCHASE.CLIENTNO
ORDER BY AMOUNT DESC
)
WHERE ROWNUM = 1)
GROUP BY CLIENT.CLIENTNO, CLIENT.CNAME;
select first_name ||' '|| last_name "FullName",name,quantity from customers,purchases,products where products.product_id = purchases.product_id and purchases.customer_id = customers.customer_id order by quantity;
This is the query you want

Return records from a table which have a match on all records of another table

Having the following three tables in a DBMS:
Customer(Id, Name, City),
Product(Id, Name, Price),
Orders(Cust_Id, Prod_Id, Date)
What is the query which fetches the Customers (if any) who have ordered all Products?
select c.id
from customer c
inner join orders o on o.cust_id = c.id
inner join product p on p.id = o.prod_id
group by c.id
having count(distinct p.id) = (select count(id) from product)

Confused with sql query

I have the following tables:
Customer(login varchar, town varchar)
Orders (Ordno int , login varchar) >>login Fk from Customer
combination (Id int, ordno int ,Product_Id int) >>ordno fk from orders
I need to show the products that have been sold in ALL the cities.
Example:
Insert into Customer (log1 , NY) (log2, NY) (log3, London)
Insert into Orders (1,log1) (2,log1) (3,log3)
Insert into combination (1,1,1) (2,2,2) (3,3,1)
Product 1 sold in NY
product 2 sold in NY
product 1 sold in London
if the available cities are only NY and London, then the only product that must be the result of the query is product 1
SELECT a.ProductID
FROM Combination a
INNER JOIN Orders b
ON a.OrdNo = b.OrdNo
INNER JOIN Customer c
ON b.Login = c.LogIn
GROUP BY a.ProductID
HAVING COUNT(DISTINCT a.ID) = (SELECT COUNT(DISTINCT town) FROM Customer)
SQLFiddle Demo
Not sure what exactly you are trying to do here.
SELECT c.Town, cc.Product_Id FROM from Customer c
JOIN Orders o ON c.login = o.login
JOIN Combination cc ON o.Ordno = cc.ordNo
GROUP BY c.town
This will group the towns together and show you the Product_Id
You still need a Product table to display the product table.
This query excludes the product table
Assuming Products table looks like this:
Products (Product_Id int, Name)
You need to join stuff all the way down (or up) to customer...
SELECT p.Name, c.town
FROM Products p
INNER JOIN Combination comb ON comb.Product_Id=p.Product_Id
INNER JOIN Orders o ON o.Ordno=comb.ordno
INNER JOIN Customer cust ON cust.login=o.login
GROUP BY p.Name, c.town

question about SQL query

I'm working on a small project involving oracle database,
and I have the following tables:
CUSTOMER ( Cid, CName, City, Discount )
PRODUCT ( Pid, PName, City, Quantity, Price )
ORDERS ( OrderNo, Month, Cid, Aid, Pid, OrderedQuantity, Cost )
How can retrieve the names of all customers who ordered all the products?
For example if customer x ordered product1, product2 and product3 (which are all the products the company offers) he will be selected. And if customer y only ordered product 1 and 2 but not 3 he will not be selected.
How can I achieve this?
You want "relational division".
select *
from customer c
where not exists( -- There are no product
select 'x'
from product p
where not exists( -- the customer did not buy
select 'x'
from orders o
where o.cid = c.cid
and o.pid = p.id));
or
select c.cid
,c.name
from customer c
join orders o using(cid)
group
by c.id
,c.name
having count(distinct o.pid) = (select count(*) from product);
Here is a great article by Joe Celko that shows several ways of implementing relational division (and variations): Divided We Stand: The SQL of Relational Division
You can use group by and use a having clause to demand that the customer has ordered all products there are:
select c.CName
from Customers c
join Orders o
on o.Cid = c.Cid
group by
c.Cid
, c.CName
having count(distinct o.Pid) = (select count(*) from products)
IMHO more readable than the "relational divison" approach, but less efficient.