Sql Query for finding Orders having same order lines - sql

How I can write a query that can find me orders having same order lines (details)?
Sample Data
Table: Order
ORDER_ID
--------
A
B
C
D
Table: OrderDetails
OrderID ProductID
------------------
A ProductX
A ProductY
A ProductZ
B ProductX
B ProductY
C ProductZ
D ProductX
D ProductY
D ProductZ
Now I want to pass ProductX,ProductY,ProductZ and get back A and D.
Can this be done in one query?

Maybe something like this is what you want?
SELECT DISTINCT Orders.OrderID
FROM Orders
INNER JOIN OrderDetails ON Orders.OrderID = OrderDetails.OrderID
WHERE OrderDetails.ProductID IN ('ProductX', 'ProductY', 'ProductZ')
GROUP BY Orders.OrderID
HAVING COUNT(*) = 3
Also note that Order is a reserved keyword and should not be used as a table name.

SELECT OrderId FROM
(SELECT DISTINCT o.OrderId, p.Product
FROM Orders o
INNER JOIN OrderDetails p
ON o.OrderId = p .OrderId
WHERE p.Product IN ('ProductX', 'ProductY', 'ProductZ') ) tab
GROUP BY OrderId
HAVING COUNT(*) = 3

I have done the required thing without using the Order table..
SELECT id from ProductT
group by id
having count(*)=3;
SQL Fiddle

Try this
SELECT P.OrderID
FROM Order1 P JOIN OrderDetails D ON
P.OrderID = D.OrderID
WHERE P.OrderID IN (SELECT OrderID FROM OrderDetails WHERE ProductID IN ('ProductX', 'ProductY', 'ProductZ'))
Having Count(P.OrderID)=3
GROUP BY P.OrderID
FIDDLE DEMO

Related

How to Sum Total in Header Detail Tables

Please, I need your help, I'm new to the subject, so I have tow tables Order table and Order Detail table. I want to sum order amount in the order table and group by the product id exists in the order detail table. I'm getting repeated rows.
select p.productName
SUM(o.Amount - o.discount) as OrdersTotal
FROM dbo.order o
inner join
OrderDetail d
ON o.orderid = d.orderid
inner join
dbo.product p
ON d.productid = p.productid
where o.orderdate >= #fromdate
and o.orderdate <= #todate
group by p.productname, o.discount
the result I'm getting is as follow
product name orders total
------------ ------------
product A 150
product A 20
product B 45
product B 13
so please, how can I fix this result? Thanks
You should only group on the product name, so that all records with the same product name are included in the sum of the amount:
select p.productName
SUM(o.Amount) as OrdersTotal
FROM dbo.order o
inner join
OrderDetail d
ON o.orderid = d.orderid
inner join
dbo.product p
ON d.productid = p.productid
where o.orderdate >= #fromdate
and o.orderdate <= #todate
group by p.productname

SQL Selecting distinct data

Let's say I have tables called Orders and OrdersInfo. Orders table looks like:
OrderID
1
2
3
And OrdersInfo
OrderID ProductID Amount
1 1 2
1 2 1
2 3 4
I'd like to get all information with the newest OrderID.
In this case the answer should be an information of OrderID 3 which is gonna be empty. My problem is that I have to group it and my information does not show up properly.
I've tried something like this:
SELECT OI.OrderID, OI.ProductID, OI.Amount
FROM OrdersInfo OI
JOIN Orders O
ON OI.OrderID = O.OrderID
GROUP BY OI.OrderID, OI.ProductID, OI.Amount
HAVING OI.OrderID = MAX(O.OrderID)
You can try this-
SELECT
O.OrderID
,OI.ProductID
,OI.Amount
FROM
(
SELECT
MAX(OrderID) AS OrderID
FROM Orders
) AS O
LEFT JOIN OrdersInfo AS OI
OI.OrderID=O.OrderID
USE LEFT JOIN and you will get NULLs for OrderID = 3
SELECT TOP 1 O.OrderID, OI.ProductID, OI.Amount
FROM Orders O
LEFT JOIN OrdersInfo OI
ON OI.OrderID = O.OrderID
ORDER BY O.OrderId DESC
USE TOP 1 for MSQL Server. LIMIT 1 for postgresql

Insufficient output from SQL query

I'm using the northwind db: http://dev.assets.neo4j.com.s3.amazonaws.com/wp-content/uploads/Northwind_diagram.jpg
I have to output all orders placed by CustomerID ALFKI with more than one unique product. I get the correct orders out, but I can't figure out why it's only printing one product name per order.
My query:
SELECT a.OrderID, p.ProductName
FROM Products p
INNER JOIN 'Order Details' a
ON (p.ProductID = a.ProductID)
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE (b.CustomerID = 'ALFKI')
GROUP BY a.OrderID
HAVING COUNT(DISTINCT a.ProductID) > 1
You need the GROUP BY and HAVING to be part of a subquery, with your primary query selecting the detail using the list of OrderIDs returned from the subquery as filter criteria. Try the following syntax for T-SQL:
SELECT
a.OrderID,
p.ProductName
FROM
Products p
INNER JOIN [Order Details] a
ON (p.ProductID = a.ProductID)
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE
a.OrderID IN
(
SELECT a.OrderID
FROM [Order Details] a
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE (b.CustomerID = 'ALFKI')
GROUP BY a.OrderID
HAVING COUNT(DISTINCT a.ProductID) > 1
)

SQL Change output of column if duplicate

I have a table which has rows for each product that a customer has purchased. I want to output a column from a SELECT query which shows the time it takes to deliver said item based on whether the customer has other items that need to be delivered. The first item takes 5 mins to deliver and all subsequent items take 2 mins to deliver e.g. 3 items would take 5+2+2=9 mins to deliver.
This is what I have at the moment(Using the Northwind sample database on w3schools to test the query):
SELECT orders.customerid,
orders.orderid,
orderdetails.productid,
CASE((SELECT Count(orders.customerid)
FROM orders
GROUP BY orders.customerid))
WHEN 1 THEN '00:05'
ELSE '00:02'
END AS DeliveryTime
FROM orders
LEFT JOIN orderdetails
ON orderdetails.orderid = orders.orderid
This outputs '00:05' for every item due to the COUNT in my subquery(I think?), any ideas on how to fix this?
Try this
SELECT orders.customerid,
orders.orderid,
orderdetails.productid,
numberorders,
2 * ( numberorders - 1 ) + 5 AS deleveryMinutes
FROM orders
INNER JOIN (SELECT orders.customerid AS countId,
Count(1) AS numberOrders
FROM orders
GROUP BY orders.customerid) t1
ON t1.countid = orders.customerid
LEFT JOIN orderdetails
ON orderdetails.orderid = orders.orderid
ORDER BY customerid
Gregory's answer works a treat and here's my attempts
-- Without each product line item listed
SELECT O.CustomerId,
O.OrderId,
COUNT(*) AS 'NumberOfProductsOrderd',
CASE COUNT(*)
WHEN 1 THEN 5
ELSE (COUNT(*) * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
GROUP BY O.CustomerId, O.OrderId
-- Without each product line item listed
SELECT O.CustomerId,
O.OrderId,
D.ProductId,
CASE
WHEN P.ProductsInOrder = 1 THEN 5
ELSE (P.ProductsInOrder * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
INNER JOIN (
SELECT OrderId, COUNT(*) AS ProductsInOrder
FROM OrderDetails
GROUP BY OrderId
) AS P ON P.OrderId = O.OrderId
GROUP BY O.CustomerId,
O.OrderId,
D.ProductId,
P.ProductsInOrder
Final code is below for anyone interested:
SELECT O.CustomerId,
O.OrderId,
Group_Concat(D.ProductID) AS ProductID,
CASE COUNT(*)
WHEN 1 THEN 5
ELSE (COUNT(*) * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
GROUP BY O.CustomerId

SQL Server: fill Null Fields from Not Null Column for multiple rows having same id

I built following Select query to get below results
SELECT Orders.OrderID, OrderDetails.ProductCode, OrderDetails.Coupon
From Orders, OrderDetails
WHERE Orders.OrderID=OrderDetails.OrderID
Results
Order ID Product Code Coupon
22 A
22 B XYZ
22 C
23 D 123
24 E
I want it to display like this:
Order ID Product Code Coupon
22 A XYZ
22 B XYZ
22 C XYZ
23 D 123
24 E
so that it fills empty coupons from not empty coupon field where order id matches.
Your help will be greatly appreciated. Thanks.
SELECT
t1.OrderID,
t1.ProductCode,
MAX(ISNULL(t2.Coupon,'')) as CouponCode,
t1.CustomerName
--Here you have select list by using alias 't'
--don't forget it to add in group by clause
FROM
(
select O.OrderID,OD.ProductCode,OD.CouponCode as Coupon,C.CustomerName
--Here add the list of columns
from Orders O
inner join OrderDetails OD on O.OrderID=OD.OrderID
Inner join customers C on O.CustomerID=C.CustomerID
)t1
INNER JOIN (
select O.OrderID
from Orders O
inner join OrderDetails OD on O.OrderID=OD.OrderID
Inner join customers C on O.CustomerID=C.CustomerID
)t2 ON
CAST(t1.OrderID AS VARCHAR)=
CAST(t2.OrderID AS VARCHAR)
GROUP BY t1.OrderID,
t1.ProductCode,
t1.CustomerName
--Add the extra fields.
order by t1.OrderID
SQL Fiddle with Your Data
Assuming Coupon is unique for each OrderID.
SELECT o1.OrderID, o2.Coupon
FROM OrderDetails o1 LEFT JOIN
(SELECT DISTINCT OrderID, Coupon FROM OrderDetails WHERE NOT Coupon IS NULL) AS o2 ON o1.OrderID = o2.OrderID
This is kind of ugly but does the job:
SELECT o.OrderID, od1.ProductCode, COALESCE(od1.Coupon,od2.Coupon)
From
Orders o
inner join
OrderDetails od1
on
o.OrderID=od1.OrderID
left join
(select OrderID,MAX(Coupon) as Coupon from OrderDetails
where Coupon is not null group by OrderID) od2
on
o.OrderID=od2.OrderID
It's using GROUP BY and MAX to ensure that there's only one row in od2 for each OrderID value, even if multiple rows in OrderDetails already have Coupon set.