Complex SQL query to get outputs from multiple tables - sql

I am using information from multiple tables to try and get the output to be, Supplier ID, Supplier Name, Percent of orders with tracking number.
I need information from many tables, as follows:
Suppliers, this contains supplier ID and supplier name
SupplierSubscriptions, the supplier must have subscriptionid = 91, this contains supplier id.
SalesOrders, this contains each order for every supplier, so it contains supplier id.
Shipments, this contains the salesorder id, with each shipment associated to that order.
Packages, this contains the shipmentid and if the shipment is on the packages table, it contains a tracking number.
What I have so far is:
SELECT DISTINCT so.supplierID, count(*) AS NumberOfOrders FROM SalesOrders so
INNER JOIN suppliers s ON s.SupplierID = so.SupplierID
INNER JOIN SupplierSubscriptions ss ON s.SupplierID = ss.SupplierID
INNER JOIN shipments ship ON ship.SalesOrderID = so.SalesOrderID
INNER JOIN Packages p ON p.ShipmentID = ship.ShipmentID
WHERE ss.SubscriptionID = 91 GROUP BY so.SupplierID
this, obviously, is not what I am after, as it only shows the supplier id and a count of orders...

I'm guessing on parts of the schema, but something like this should work for you:
SELECT so.supplierID,
so.supplierName,
SUM(case when p.trackingNumber is not null then 1 else 0 end) / COUNT(0) as OrdersWithTracking
FROM SalesOrders so
INNER JOIN suppliers s ON s.SupplierID = so.SupplierID
INNER JOIN SupplierSubscriptions ss ON s.SupplierID = ss.SupplierID
INNER JOIN shipments ship ON ship.SalesOrderID = so.SalesOrderID
INNER JOIN Packages p ON p.ShipmentID = ship.ShipmentID
WHERE ss.SubscriptionID = 91
GROUP BY so.SupplierID, so.supplierName

Related

SQL Server stored procedure query multiple tables

I am querying a SQL Server database using a stored procedure.
My database tables include:
Customers
SalesOrders - Linked to the customers with an id
SalesOrderLines - Linked to the SalesOrders with an id
SalesOrderReleases - Linked to the SalesOrderLines with an id, stores the quantity on the order line that has been released and ready to manufacture, the SalesOrderLine quantity can be all on one release or split up on multiple
FinishedGoods - linked to the SalesOrderLines with an id, stores the quantity of the SalesOrderLine where manufacturing is complete, the SalesOrderLine quantity can be all on one FinishedGood entry or split up on multiple
I need to retrieve all the customers that have SalesOrderLines with SalesOrderReleases and FinishedGoods where the total quantity finished is less than the total quantity released
I have tried this SQL code but Customers appear repeatedly in the results
SELECT
Customer.ID, Customer.Name
FROM
Customer
INNER JOIN
SalesOrder ON Customer.ID = SalesOrder.CustomerID
INNER JOIN
SalesOrderLine ON SalesOrder.ID = SalesOrderLine.SalesOrderID
INNER JOIN
SalesOrderRelease ON SalesOrderLine.ID = SalesOrderRelease.SalesOrderLineID
INNER JOIN
FinishedGood ON SalesOrderLine.ID = FinishedGood.SalesOrderLineID AND FinishedGood.Quantity < SalesOrderRelease.Quantity
I am looking for a SQL code snippet that will query multiple tables the way I have described.
try this code:
SELECT Customer.ID, Customer.Name FROM Customer
INNER JOIN SalesOrder ON Customer.ID = Order.CustomerID
INNER JOIN SalesOrderLine ON Order.ID = OrderLine.OrderID
INNER JOIN
(SELECT OrderID, OrderLineID, SUM (Quantity) AS SRQuantity FROM
SalesOrderRelease GROUP BY OrderID, OrderLineID) AS SRQ
ON SRQ.OrderID = SalesOrderLine.OrderID
INNER JOIN
(SELECT OrderLineID, SUM (Quantity) AS FGQuantity FROM
FinishedGoods GROUP BY OrderLineID) AS FGQ
ON SRQ.OrderLineID = FGQ.OrderLineID
WHERE FGQ.FgQuantity < SRQ.SRQuantity
Credits to Sergey for his answer, I was able to use the sample code he provided with several slight modifications:
SELECT Customer.ID, Customer.Name FROM Customer
INNER JOIN SalesOrder ON Customer.ID = SalesOrder.CustomerID
INNER JOIN SalesOrderLine ON SalesOrder.ID = SalesOrderLine.SalesOrderID
INNER JOIN
(SELECT SalesOrderID, SalesOrderLineID, SUM (Quantity) AS SRQuantity FROM
SalesOrderRelease GROUP BY SalesOrderID, SalesOrderLineID) AS SRQ
ON SRQ.SalesOrderLineID = SalesOrderLine.SalesOrderID
LEFT JOIN
(SELECT SalesOrderLineID, SUM (Quantity) AS FGQuantity FROM
FinishedGood GROUP BY SalesOrderLineID) AS FGQ
ON SRQ.SalesOrderLineID = FGQ.SalesOrderLineID
WHERE ISNULL(FGQ.FgQuantity, 0) < SRQ.SRQuantity
The last join needed to be a Left Join
When comparing the FgQuantity and the SRQuantity in the last line, I needed to have it check for NULL values
With these modifications everythings works perfectly!

Row is listed twice in simple query

One row is Repeated twice and I can't seem to figure out why. I tried using Group by but couldn't figure that out either lol. Using Left outer Join, to list suppliers who have a discounted product, in the Northwind Database
Select *
From Suppliers s
Left Outer Join products p
On s.SupplierID = p.SupplierID
Where p.Discontinued = 1
You have two discontinued products for a supplier, and a row is created for each row in products that matches the join condition and the Discontinued = 1 predicate. You want something like that:
SELECT * FROM Suppliers s
WHERE EXISTS (SELECT 1
FROM Products p
WHERE p.SupplierID = s.SupplierID
AND p.Discontinued = 1)
You have two rows in one of those tables. You can determine which by querying both tables by themselves on that supplierId.
Now, to your query, by putting p.discontinued in the where, that join effectively becomes an inner join, so you should either flip it to an inner join or move that condition to the join.
To get suppliers with discontinued products, you can do this:
Select * from supplier where supplierId in (
select supplierId from products
where discontinued =1)
There is clearly a supplier that has multiple discontinued products.
If you want suppliers with at least one discounted product, then use exists:
select s.*
from suppliers s
where exists (select 1
from products p
where p.supplierid = s.supplierid and
p.Discontinued = 1
);
If you want the list of suppliers with the number of discontinued products, use join:
select s.*, p.num_discontinued
from supplier s join
(select p.supplierid, count(*) as num_discontinued
from products
where p.Discontinued = 1
group by p.supplierid
) p
on p.SupplierID = s.SupplierID ;
If you want the list of products that are discontinued with their suppliers, than use your query but change the left join to an inner join. An outer join is not necessary.

I need my query to return where it will return where an item was purchased by more than 3 customers. However, my query keeps returning Null

I have confirmed that there is instances where an item was purchased more than 3 times by 3 SEPERATE customers. However, my code keeps returning Null. I have tried several different variations of the code below, but I get either Null or an error message stating "Ambiguous column name 'Customer_ID'."
I have also tried aliasing it, but with no luck. Where am I going wrong?
SELECT First_Name, Last_Name, Country, Address, State, Zip, Product_Name
FROM Orders
JOIN Customer ON Orders.Customer_ID = Customer.Customer_ID
JOIN Amazon_Inventory ON Orders.Inventory_ID = Amazon_Inventory.Inventory_ID
JOIN Shipment ON Amazon_Inventory.Shipment_ID = Shipment.Shipment_ID
JOIN Product ON Shipment.Product_ID = Product.Product_ID
JOIN Product_Listing ON Product.Listing_ID = Product_Listing.Listing_ID
WHERE ORDER_ID IN
(SELECT Customer_ID, Inventory_ID
FROM Orders
GROUP BY Customer_ID, Inventory_ID
HAVING COUNT (Order_ID) >3 AND COUNT (INVENTORY_ID) >3);
The error is on IN subquery,you can't use IN to compare multiple fields.
If I understand correct you might expect this.
You could provide some sample data and expect result.I will edit my answer.
SELECT First_Name, Last_Name, Country, Address, State, Zip, Product_Name
FROM Orders
JOIN Customer ON Orders.Customer_ID = Customer.Customer_ID
JOIN Amazon_Inventory ON Orders.Inventory_ID = Amazon_Inventory.Inventory_ID
JOIN Shipment ON Amazon_Inventory.Shipment_ID = Shipment.Shipment_ID
JOIN Product ON Shipment.Product_ID = Product.Product_ID
JOIN Product_Listing ON Product.Listing_ID = Product_Listing.Listing_ID
WHERE Customer.Customer_ID IN
(SELECT Customer_ID
FROM Orders
GROUP BY Customer_ID
HAVING COUNT (1) >3 );
You are almost there. I would suggest you to use alias to your tables (that would solve the ambiguous errors), and also, you are using an IN referring to a SELECT with more than 1 column being selected (A tip: I would use an EXISTS instead of a IN whenever possible - but that's not the case - or at least it doesn't seems like the case with the info provided).
So, using aliases I would end up with something like this:
SELECT
*
/* Place appropriate alias in each field selected => First_Name, Last_Name, Country, Address, State, Zip, Product_Name */
FROM Orders AS OR
JOIN Customer AS CU ON Orders.Customer_ID = Customer.Customer_ID
JOIN Amazon_Inventory AS AI ON Orders.Inventory_ID = Amazon_Inventory.Inventory_ID
JOIN Shipment AS SH ON Amazon_Inventory.Shipment_ID = Shipment.Shipment_ID
JOIN Product AS PR ON Shipment.Product_ID = Product.Product_ID
JOIN Product_Listing AS PL ON Product.Listing_ID = Product_Listing.Listing_ID
WHERE
EXISTS
(SELECT 1 FROM Orders OREX
WHERE OREX.Inventory_ID = OR.Inventory_ID
GROUP BY OREX.Customer_ID, OREX.Inventory_ID
HAVING COUNT(1)>3);
I'm thinking something like this:
SELECT
c.Customer_ID, i.Inventory_ID,
c.First_Name, c.Last_Name, c.Country, c.Address, c.State, c.Zip,
p.Product_Name
FROM Orders o
JOIN Customer c ON o.Customer_ID = c.Customer_ID
JOIN Amazon_Inventory i ON o.Inventory_ID = i.Inventory_ID
JOIN Shipment s ON i.Shipment_ID = s.Shipment_ID
JOIN Product p ON s.Product_ID = p.Product_ID
JOIN Product_Listing l ON p.Listing_ID = l.Listing_ID
)
WHERE Inventory_ID IN (
SELECT Inventory_ID
FROM Orders JOIN Customer ON Orders.Customer_ID = Customer.Customer_ID
GROUP BY Inventory_ID
HAVING COUNT (DISTINCT Customer_ID) > 3
);

SQL nested SELECT with JOIN

I wasted all the day on one query without success , SOS I need a help :) with a given #CustomerId , I need to query all the Products that linked to customer seller can sell but not sold to him before , the Commissions table is indication of what products seller can sell
Thanks in advance
SELECT sellableProduct
FROM (SELECT Comissions.ProductId AS sellableProduct, Sellers.SellerId AS sellableSeller FROM Comissions INNER JOIN Sellers ON Comissions.SellerId=Sellers.SellerId INNER JOIN Customers ON Sellers.SellerId=Customers.SellerId WHERE Customers.CustomerId = #customerid) AS tblSellable
LEFT JOIN (SELECT Sales.ProductId AS soldProduct, Customers.SellerId as soldSeller FROM Customers INNER JOIN Sales ON Customers.CustomerId=Sales.CustomerId WHERE Customers.CustomerId = #customerid) AS tblSold
ON tblSellable.sellableProduct=tblSold.soldProduct AND tblSellable.sellableSeller=tblSold.soldSeller
WHERE tblSold.soldProduct IS NULL
this way you avoid time-consuming IN statements
If a Customer can only have one Seller, then you can omit the seller link:
SELECT sellableProduct
FROM (SELECT Comissions.ProductId AS sellableProduct FROM Comissions INNER JOIN Sellers ON Comissions.SellerId=Sellers.SellerId INNER JOIN Customers ON Sellers.SellerId=Customers.SellerId WHERE Customers.CustomerId = #customerid) AS tblSellable
LEFT JOIN (SELECT Sales.ProductId AS soldProduct FROM Sales WHERE Sales.CustomerId = #customerid) AS tblSold
ON tblSellable.sellableProduct=tblSold.soldProduct
WHERE tblSold.soldProduct IS NULL
Basically, you're looking for products that have a record in commissions, but not in sales. Using :id to denote the specific ID:
SELECT *
FROM products
WHERE productid IN (SELECT productid
FROM commissions
WHERE sellerid = :id) AND
productid NOT IN (SELECT productid
FROM sales
JOIN customers ON sales.customerid = cusomers.customerid
WHERE sellerid = :id)
Would this work?
SELECT sell.*, prod.* FROM
Sellers sell
INNER JOIN Customers cust ON cust.SellerId = sell.SellerId
LEFT JOIN Commissions comm ON sell.SellerId = comm.SellerId
LEFT JOIN Products prod ON prod.ProductId = comm.ProductId
WHERE prod.ProductId NOT IN (
SELECT ProductId
FROM Products p INNER JOIN
Sales s ON s.ProductId = p.ProductId
WHERE s.CustomerId = #CustomerId
It get all the sellers and the respective product from commission, where the product Id is NOT associated with any sale of the client

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)