Confused with sql query - sql

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

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

left join two tables on a non-unique column in right table

I have two tables in sql server and i wanna select and join some data from these table.the first tables have some customer like:
---------------
customer id
Dave 1
Tom 2
---------------
and second table i table of purchases that includes list of last purchases with cost and which customer bought that Product:
------------------
product date customer id
PC 1-1-2000 1
phone 2-3-2000 2
laptop 3-1-2000 1
------------------
i wanna select first table (customers info) with last date of their purchases!
i tried left join but that doesn't give me last purchases becuase customer id is not unique in second table! how can i do this function with SQL server query? Regards
If you just want the max date, use aggregation. I would recommend a left join for customers who have made no purchases:
select c.customer, c.id, max(p.date)
from customers c left join
purchases p
on c.id = p.customer_id
group by c.customer, c.id;
Use the not exists clause for the win!
select c.customer, p.*
from Customer as c
inner join Purchase as p
on p.customer_id = c.id
where not exists (
select 1
from Purchase as p2
where p2.customer_id = p.customer_id
and p2.date > p.date
)
I think you can use inner join and group by
select table1.customer, table1.id, table.max(date)
from table1
inner join table2 on table1.id = table2.id
group by table1.customer, table1.id

Insert Multiple Tables into one Table

Http://i.stack.imgur.com/z0fSP.png
Http://i.stack.imgur.com/Nd3nB.png
Http://i.stack.imgur.com/5qtRh.png
Http://i.stack.imgur.com/01PVc.png
Http://i.stack.imgur.com/wvibY.png
INSERT INTO OrderArchive
(OrderNumber,OrderDate,StockItem,Quantity,UnitPrice,SalesRep,Customer,ArchiveDate)
SELECT "ORDER".OrderNo,
"ORDER".OrderDate,
Stock.StockNo||' '||Stock.StockDesc,
Orderline.Quantity,
Orderline.UnitPrice,
Person.FirstName||' '||Person.Surname,
Person.FirstName||' '||Person.Surname,
OrderArchive.ArchiveDate
FROM "ORDER"
INNER JOIN Stock
ON Stock.StockNo||' '||Stock.StockDesc = OrderAchive.StockItem
INNER JOIN Orderline
ON Orderline.Quantity = OrderArchive.Quantity
INNER JOIN Orderline
ON Orderline.UnitPrice = OrderArchive.UnitPrice
INNER JOIN Person
ON Person.FirstName||' '||Person.Surname = OrderArchive.SalesRep
INNER JOIN Person
ON Person.FirstName||' '||Person.Surname = OrderArchive.Customer
WHERE "ORDER".OrderDate < DATEADD('M',6,SYSDATE);
I tried to work it out first, but just couldnt manage it .... i am trying to move orders that are older than 6 months to OrderArchive...OrderArchive has OrderNo & Orderdate that come from "ORDER"Table Stock item which is a combination of StockID and Stockdesc from stock table quantity and unit cost are from orderline table salesrep and customer are from person Table and datearchived is a sysdate of the date the order was archived
To do this, you need a way to join the Person record to the TableOrder record. This code assumes you have a PersonID on the TableOrder table. You might have a CustomerID or SalesPersonID or something like that on your TableOrder table to join it to the Person table, but I'm not clear on that.
INSERT INTO ArchiveTable (col_1,col_2,col_3,col_4 etc)
SELECT
o.OrderNo,
o.OrderDate,
p.StockNo||' '||p.StockDesc,
p.FirstName||' '|| p.Surname
FROM TableOrder o
INNER JOIN Person p
ON p.PersonID = o.PersonID
WHERE o.orderdate < DATEADD('M',12,SYSDATE)
I think that you are not getting the expected output from the query, because you are joining the Person table with both SalesRep and Customer names at the same time. Thus, only if an Order has the same name for both SalesRep and Customer, will you get any data. Therefore, I have created different table aliases for the Person table, as below:
INSERT INTO OrderArchive
(OrderNumber,OrderDate,StockItem,Quantity,UnitPrice,SalesRep,Customer,ArchiveDate)
SELECT
"ORDER".OrderNo,
"ORDER".OrderDate,
Stock.StockNo||' '||Stock.StockDesc,
Orderline.Quantity,
Orderline.UnitPrice,
Person_SR.FirstName||' '||Person_SR.Surname,
Person_C.FirstName||' '||Person_C.Surname,
OrderArchive.ArchiveDate
FROM "ORDER"
INNER JOIN Stock
ON Stock.StockNo||' '||Stock.StockDesc = OrderAchive.StockItem
INNER JOIN Orderline
ON Orderline.Quantity = OrderArchive.Quantity
INNER JOIN Orderline
ON Orderline.UnitPrice = OrderArchive.UnitPrice
INNER JOIN Person Person_SR
ON Person_SR.FirstName||' '||Person_SR.Surname = OrderArchive.SalesRep
INNER JOIN Person Person_C
ON Person_C.FirstName||' '||Person_C.Surname = OrderArchive.Customer
WHERE "ORDER".OrderDate < DATEADD('M',6,SYSDATE);
INSERT INTO OrderArchive (OrderNumber,OrderDate,StockItem,Quantity,UnitPrice,SalesRep,Customer)
SELECT "ORDER".OrderNo,
"ORDER".OrderDate,
Stock.StockNo ||' '|| Stock.StockDesc,
Orderline.Quantity,
Stock.UnitCost,
"ORDER".SalesRepID,
Person.FirstName||' '||Person.Surname
FROM Person INNER JOIN
("ORDER" LEFT JOIN
(Orderline INNER JOIN Stock
ON Orderline.StockID=Stock.StockNo)
ON"ORDER".OrderNo=OrderLine.OrderNo)
ON Person.PersonID="ORDER".CustomerID
WHERE "ORDER".OrderDate < ADD_MONTHS (SYSDATE,-6)
ORDER BY "ORDER".OrderNo;
SELECT * FROM OrderArchive;
Nearly Done i just have to get SalesRepID to say firstname surname of salesrep but mostly done :)

Fetch data from more than one tables using Group By

I am using three tables in a PostgreSql database as:
Customer(Id, Name, City),
Product(Id, Name, Price),
Orders(Customer_Id, Product_Id, Date)
and I want to execute a query to get from them "the customers that have have ordered at least two different products alnong with the products". The query I write is:
select c.*, p.*
from customer c
join orders o on o.customer_id = c.id
join product p on p.id = o.product_id
group by (c.id)
having count(distinct o.product_id)>=2
It throws the error:
"column "p.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: select c.*, p.*".
However if I remove the the p.* from select statement (assuming that I one does not want the products, only the customers), it runs fine. How can I get the products as well?
Update: Having ordered two or more products, a customer must appear on the output as many times as its product he has ordered. I want as output a table with 5 columns:
Cust ID | Cust Name | Cust City | Prod ID | Prod Name | Prod Price
Is it possible in SQL given that group by should be used? Shoul it be used on more than one columns on different tables?
Try this out :
SELECT distinct c.* ,p.*
FROM Customer c
JOIN
(SELECT o.customer_id cid
FROM Product P
JOIN Orders o
ON p.id= o.product_id
GROUP BY o.customer_id
HAVING COUNT(distinct o.product_id)>=2) cp
ON c.id =cp.cid
JOIN Orders o
on c.id=o.customer_id
JOIN Product p
ON o.product_id =p.id
I hope it solves your problem.
I think you can use following query for this question -
SELECT C1.*, p1.*
FROM Customer C1
JOIN Orders O1 ON O1.Customer_Id = C1.Id
JOIN Product P1 ON P1.Id = O1.Product_Id
WHERE C1.Id IN (SELECT c.Id
FROM Customer c
JOIN Orders o ON o.Customer_Id = c.Id
GROUP BY (c.Id)
HAVING COUNT(DISTINCT o.Product_Id) >= 2)

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.