Fetch data from more than one tables using Group By - sql

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)

Related

Best way of excluding customers with a specific order

I'm running a pretty basic query. The issue is I'm trying to get results with all of our customers who never ordered product Y. The problem is, if I use a simple WHERE ProductColumn <> 'Product Y', it doesn't work because almost all of our customers have ordered other products.
Basically, I'm wondering how I could exclude on the customer level (instead of the order level) - if a customer has ordered Product Y, I don't want them showing up in my results at all.
Thanks.
You are probably looking for EXISTS().
If I want to find customers who have placed orders:
SELECT c.*
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customerid = c.customerID
AND productID = 'Y'
)
If I want to find customers who have not placed orders:
SELECT c.*
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customerid = c.customerID
AND productID = 'Y'
)
Try this:
select * from customers c
where not exists(select 1 from customers
where cutomer_id = c.customer_id
and productcolumn = 'product y')
This assumes you have 'customer_id' column (or at least some id column in your table).
Simple LEFT JOIN should work:
SELECT c.*
FROM customers c
LEFT OUTER JOIN orders o
ON o.customerid = c.customerID
WHERE o.ProductColumn <> 'Product Y'

How can I show order quantity relative to cities where customers in cities have at least three orders?

I use this SQL statement to be able to join three tables (Order1, Order2, and Customers) to show the order quantity for each customer from each city they're addressed to. But how can I show the rows of order quantities for customers in cities who have done at least three orders? In other words I'm trying to aggregate on the cities connected to the customers who have done more than three orders.
Table structures:
Customers has the columns CustomerNr, City Name
Order1 has the columns Ordernr, CustomerNr
Order2 has the columns Ordernr, Order quantity
The SQL statement so far:
SELECT
Customers.CityName, Order2.OrderQuantity
FROM
Order1
INNER JOIN
Order2 ON Order1.ordernr = Order2.ordernr
INNER JOIN
Customers ON Customers.CustomerNr = Order1.CustomerNr
What you're missing are aggregate functions. To get the sum of a column, you can use SUM(columnName) in your select statement. To get proper results, you will have to group by a field as well. In this case, you want the sum per customer so you can do something like this:
SELECT c.customerNumber, c.name, SUM(o2.quantity) AS totalQuantity
FROM customers c
JOIN order1 o1 ON o1.customerNumber = c.customerNumber
JOIN order2 o2 ON o2.orderNumber = o1.orderNumber
GROUP BY c.customerNumber, c.name;
To filter on an aggregate condition, you need to add a having clause. Here, you can require that each group have a minimum of 3 rows:
SELECT c.customerNumber, c.name, SUM(o2.quantity) AS totalQuantity
FROM customers c
JOIN order1 o1 ON o1.customerNumber = c.customerNumber
JOIN order2 o2 ON o2.orderNumber = o1.orderNumber
GROUP BY c.customerNumber, c.name
HAVING COUNT(*) >= 3;
Here is an SQL Fiddle with some dummy data that I tested with.
select c.CityName, Sum(o2.OrderQuantity) as Quantity
from Customers c
inner join Order1 o1 on c.CustomerNr = o1.CustomerNr
inner join Order2 o2 on o1.OrderNr = o2.OrderNr
group by c.CityName
having sum(o2.OrderQuantity) >= 3

Oracle: Using Sub-Queries, JOIN and distinct function together

Here is how I contructed the step-by-step:
M1. create a sub-query that will return CustomerId and total invoiced for that customer
M2. A second subquery that will give a list of distinct ProductIDs (along with product SKUs) and CustomerIDs.
M3. The M1 and M2 subqueries will be joined to make association between customer totals and products (for the same CustomerId).
M4. The query M3 will be fed to the final query that will just find the top 5 products.
I'm stuck on creating the distinct ProductID and customerID because they would have to be in aggregate functions in order to make them distinct.
Attached is an image that is the erwin diagram which helps understand the system.
If you can help me with M1-M4, I will greatly appreciate it. I'm not a programmer by trade but a business analyst.
--M1--
select C.CustomerId, COUNT(I.InvoiceId) TotalNumInvoices
from Customer C
JOIN Invoice I ON (I.CustomerId = C.CustomerId)
group by C.CustomerId
--M2: Incomplete--
select P.ProductID, P.SKU, C.CustomerID
from Product P
JOIN InvoiceLine IL ON (IL.ProductId = P.ProductId)
JOIN Invoice I ON (IL.InvoiceId = I.InvoiceId)
JOIN Customer C ON (C.CustomerId = I.CustomerId)
you can also use the DISTINCT keyword your select clause in order to get unique values. Try this for m2:
select DISTINCT p.productID, p.sku, i.customerID
from invoice i INNER JOIN invoiceLine il
ON i.invoiceID = il.invoiceID
JOIN product p
ON il.productID = p.productID;

sql select count of multiple relationships with left join

I have a table for "branches", "orders" and "products. Each order and product are connected to a branch with branch_id. I need an sql statement to get a list of all branches with a field for how many orders and a field for how many products.
This works:
SELECT b.*, COUNT(o.id) AS orderCount FROM branches b
LEFT JOIN orders o ON (o.branch_id = b.id) GROUP BY b.id
but it only gets the amount of orders, not products.
If I change it to add amount of products, the amounts are wrong because it's getting amount of orders * amount of products.
How can I get the amount of both the orders and the products in the same SQL statement?
Something like this should work (on sql server at least - you didn't specify your engine).
SELECT
b.id
,COUNT(distinct o.id) AS orderCount
,COUNT(distinct p.id) AS productCount
FROM branches b
LEFT JOIN orders o
ON (o.branch_id = b.id)
left join products p
on p.product_id=b.id)
GROUP BY
b.id
Please try:
select
*,
(select COUNT(*) from Orders o where o.branch_id=b.id) OrderCount,
(select COUNT(*) from Products p where o.branch_id=p.id) ProductCount
From
branches b

sql issue to query product name

I am new to SQL , I have been looking for on line resources but have not find anything yet to solve my problem. Basically i have three tables below:
ORDERTBL(ORDERID,ORDERDATE,ORDERSTATUS),
PRODUCT(PRODUCTID,PRODUCT_NAME),
ORDERLINKPRODUCTS(ORDERID,PRODUCTID,QUANTITY,ORDERLINKPRODUCTID)
I want to get all the product name from the products tables for a specific order which i should query from ORDERLINKPRODUCTS since it contains all the orders.
for instance please find test data available in 3 tables:
Table ORDERTBL:
ORDERID=1,ORDERDATE= 24May, ORDERSTATUS=Process
Table PRODUCTS:
PRODUCID =1 PRODUCT_NAME = spoon PRODUCID =2 PRODUCT_NAME = soap
Table :ORDERLINKPRODUCTS:
ORDERID=1 PRODUCTID = 1 QUANTITY=3 ORDERLINKPRODUCTID=1 ORDERID=1 PRODUCTID = 2 QUANTITY=1 ORDERLINKPRODUCTID=2
I am trying to make a select statements that display all the product name of an order. For instance display all product name of orderid=1 which will return spoon,soap.
Any suggestion how to do it please?
Thanks in advance.
You should use JOIN keyword in SQL to join the three tables to be able to access PRODUCTNAME and show that table data. More about Join clause
SELECT prod.PRODUCT_NAME
FROM ORDERTBL ord
INNER JOIN ORDERLINKPRODUCTS link ON ord.ORDERID = link.ORDERID
INNER JOIN PRODUCT prod ON link.PRODUCTID = prod.PRODUCTID
WHERE ord.ORDERID = 1
SQLfiddle Demo
You can find orders with products ilsted using this
SELECT O.ORDERID, RTRIM(
XMLAGG(XMLELEMENT(e, P.PRODUCT_NAME ||',') ORDER BY O.ORDERID).EXTRACT('//text()'), ',') as Products
FROM ORDERTBL O
INNER JOIN ORDERLINKPRODUCTS L
ON O.ORDERID = L.ORDERID
INNER JOIN PRODUCT P
ON L.PRODUCTID = P.PRODUCTID
GROUP BY O.ORDERID
and products listed with its quantity using this:
SELECT O.ORDERID, RTRIM(
XMLAGG(XMLELEMENT(e, P.PRODUCT_NAME || '(' || L.QUANTITY || '),') ORDER BY O.ORDERID).EXTRACT('//text()'), ',') as Products
FROM ORDERTBL O
INNER JOIN ORDERLINKPRODUCTS L
ON O.ORDERID = L.ORDERID
INNER JOIN PRODUCT P
ON L.PRODUCTID = P.PRODUCTID
GROUP BY O.ORDERID
You can add WHERE clause clause to filted orders as you whish.
SQL FIDDLE DEMO