I have 2 tables:
Order as master table with the columns OrderID, Amount, date, customer, Amount
OrderDetails as child table with the columns Id, OrderID, Item, status Boolean (yes or No), Price, quantity, SubTotal.
I want sum the subtotal only if the status is YES, then show the Sum in "amount" column in the master
SELECT
Order.OrderId, Order.Date, Order.Customer, Order.Amount,
SUM(OrderDetails.SubTotal ) AS TotalAmount,
FROM
Order
INNER JOIN
OrderDetails ON Order.OrderId = OrderDetails.OrderId
WHERE
(OrderId.status = Yes)
GROUP BY
Order.OrderId, Order.Date, Order.Customer, Order.Amount
This SQL statement only returns lines where the column Status is "Yes", but I want to return all of them but SUM only the lines with Status = Yes.
Example:
OrderDetails table
Order-Id item Price Quantity SubTotal Status
-------------------------------------------------------
M1 Shirt 10 10 100 yes
M1 item2 5 5 25 no
M2 Item3 7 5 35 yes
Order:
order-Id date Cus Amount
------------------------------------------------
M1 2016/8/20 Jean-Claude 100
M2 2016/8/20 Pierre 35
Thank you
You would seem to want something like this:
SELECT o.OrderId, o.Date, o.Customer, o.Amount,
SUM(CASE WHEN od.status = 'YES' THEN od.SubTotal ELSE 0 END)) AS TotalAmount
FROM Order o INNER JOIN
Orderdetails od
ON o.OrderId = od.OrderId
GROUP BY o.OrderId, o.Date, o.Customer, o.Amount;
The key is conditional aggregation -- having a CASE expression as the argument to the SUM().
Related
I have 3 tables: Orders, Returns, Region
OrderID
Sales
RegionID
1
100
1
2
200
2
3
200
2
ReturnID
OrderID
1
1
2
3
RegionID
Region
1
N
2
E
I'm trying to sum the total sales and returns and group them by region. I'm trying to join the third table of returns, to only display the sum of the sales where there is a OrderID in the return table matching an OrderID from the Order table and grouped by RegionID, but I'm having trouble figuring it out.
I have it working for total sales in a region using:
SELECT r.Region, SUM(o.sales)
FROM Orders o
INNER JOIN Region r ON o.RegionID = r.RegionID
GROUP BY o.RegionID
Edit:
Final result should look like:
RegionID
Total Sales
Total Returns
1
100
100
2
400
200
3
0
0
Try this:
SELECT
r.RegionID
, SUM(o.sales) [Total Sales]
, SUM(CASE WHEN rt.orderId IS NOT NULL THEN o.sales ELSE 0 END) [Total Returns]
FROM Orders o
INNER JOIN Region r ON o.RegionID = r.RegionID
LEFT JOIN returns rt ON rt.orderId=o.orderId
GROUP BY o.RegionIDvalues
Here you can use an inner join to join your Region table. This will only take into consideration the orders with a return since you are not using a OUTER JOIN. You then do your SUM the same as before. This will allow you to have the Total Returns.
For the total of sales, my solution would be to do a sub query to select
all of the sales, with or without a return.
SELECT REG.RegionID, SUM(O.SALES) AS Total_Sales, SUM(
SELECT O.SALES
FROM ORDER O
WHERE O.RegionID = REG.RegionID) AS Total_Returns
FROM ORDERS O
INNER JOIN REGION REG
ON O.RegionID = REG.RegionID
INNER JOIN RETURNS RET
ON O.OrderID = RET.OrderID
GROUP BY REG.RegionID
I have 5 tables mentioned below.
Customers:
CustomerID CustomerName ContactName Address City PostalCode Country
1 Alfreds Futterkiste Maria Anders Obere Str. 57 Berlin 12209 Germany
Categories:
CategoryID CategoryName Description
1 Beverages Soft drinks, coffees, teas, beers, and ales
2 Condiments Sweet and savory sauces, relishes, spreads, and seasonings
3 Confections Desserts, candies, and sweet breads
OrderDetails:
OrderDetailID OrderID ProductID Quantity
1 10248 11 12
Orders:
OrderID CustomerID EmployeeID OrderDate ShipperID
10248 90 5 1996-07-04 3
Products:
ProductID ProductName SupplierID CategoryID Unit Price
1 Chais 1 1 10 boxes x 20 bags 18
I need CustomerID, Customername and Country from Customers table only for those customers who have placed orders for all category types from categories table.
I tried following query and its working but i dont need count column in the output. Please help.
select a.customerid, customername, country, count(distinct d. CategoryID)
from customers a join orders b on a.customerid = b.customerid
join orderdetails c on b.orderid = c.orderid
join products d on c.productid = d.productid
join categories e on d.categoryid = e.categoryid
join (select count(distinct f.categoryid) cnt from categories f)
group by CustomerName
having count(distinct d. CategoryID) = cnt
select a.customerid, customername, country,
from customers a
where (select count(distinct d.categoryid)
from orders b on a.customerid = b.customerid
join orderdetails c on b.orderid = c.orderid
join products d on c.productid = d.productid)
= (select count(distinct f.categoryid) cnt from categories f)
You can do the count comparison in the where clause. Your last join isn't actually a join as it will select each time all categories.
I am working on two tables
PRODUCT table
with
PRODUCTID, PRICE
and I am working with
ORDERLINE table
which has
PRODUCTID, QUANTITY, ORDERID
I want to join both tables so that I have
ORDERQUANTITY
which has
PRODUCT.PRODUCTID, ORDERLINE.QUANTITY
GROUPED BY
PRODUCTID
In other words I would like the two tables not to be like this:
PRODUCTID QUANTITY
- 10 4
- 10 2
- 20 1
- 20 6
- 30 4
- 30 6
- 30 2
- 30 2
- 40 2
- 40 2
- 40 5
But like this
PRODUCTID QUANTITY
- 10 6
- 20 7
- 30 14
- 40 9
My current code shown below only does the first table when I try to group by productid it won't work.
SELECT PRODUCT.PRODUCTID, ORDERLINE.QUANTITY
FROM ORDERLINE
FULL OUTER JOIN PRODUCT ON PRODUCT.PRODUCTID = ORDERLINE.PRODUCTID
ORDER BY PRODUCT.PRODUCTID;
You don't need the join if you need only id and sum of ordered quantity :
select PRODUCTID, sum(QUANTITY)
from ORDERLINE
group by PRODUCTID
order by PRODUCTID;
I think a simple SUM aggregate function and GROUP BY query will be enough:
SELECT PRODUCT.PRODUCTID, coalesce( SUM( ORDERLINE.QUANTITY), 0 )
FROM ORDERLINE
FULL OUTER JOIN PRODUCT ON PRODUCT.PRODUCTID = ORDERLINE.PRODUCTID
GROUP BY PRODUCT.PRODUCTID
ORDER BY PRODUCT.PRODUCTID;
I'm not sure about understanding your question, but I think that this sentece should give you the results you are asking for:
SELECT PRODUCT.PRODUCTID, SUM(ORDERLINE.QUANTITY) AS QUANTITY
FROM ORDERLINE
FULL OUTER JOIN PRODUCT ON PRODUCT.PRODUCTID = ORDERLINE.PRODUCTID
GROUP BY PRODUCT.PRODUCTID
ORDER BY PRODUCT.PRODUCTID;
SELECT PRODUCT.PRODUCTID, SUM(ORDERLINE.QUANTITY)
FROM ORDERLINE
FULL JOIN PRODUCT ON PRODUCT.PRODUCTID = ORDERLINE.PRODUCTID
GROUP BY PRODUCT.PRODUCTID
Here it is in action: SQL Fiddle
TABLE : ITEMS
---------------------------------------
Item_ID Description
---------------------------------------
1 Vivel Satin Soap
2 Flake
3 Maggie
4 Mango Juice
---------------------------------------
TABLE : SALES
------------------------------------------------
Sale_ID Sale_Date Item_ID Quantity
------------------------------------------------
1 15-Feb-14 1 2
2 16-Feb-14 1 1
3 16-Feb-14 2 1
4 17-Feb-14 3 1
5 18-Feb-14 1 1
6 18-Feb-14 2 2
------------------------------------------------
I'm having trouble in constructing SQL query as the way i wanted.... Here, i have two
tables in the database as shown above. The "ITEMS" table is for Items' Description Look-up
and "SALES" table for Items' Sale Record Look-up. Now, my requirement is, i want to select a records
from both the tables to generate report (as shown in the following). Report should contain
Items Description and its corresponding Sum of Quantity.
REPORT
------------------------------------------------------
Item_ID Description Total_Quantity
------------------------------------------------------
1 Vivel Satin Soap 4
2 Flake 3
3 Maggie 1
4 Mango Juice (SHOULD BE NULL HERE)
------------------------------------------------------
I tried following SQL query and some more to generate the report but had a logical error....
so, help me to construct better!
1) SELECT I.Item_ID, I.Description, Sum(S.Quantity)
FROM ITEMS I
INNER JOIN SALES S ON I.Item_ID = S.Item_ID
ORDER BY I.Item_ID;
2) Select I.Item_ID, I.Description, Sum(S.Quantity)
From ITEMS I, SALES S
Where S.Item_ID IN (Select Item_ID from ITEMS)
Order by I.Item_ID;
3) etc..........
try this,
SELECT I.Description, Sum(S.Quantity)
FROM ITEMS I
LEFT JOIN SALES S ON I.Item_ID = S.Item_ID
GROUP BY I.Description
Instead of Inner just try with Left Join...
And you need to use Group by Clause
SELECT I.Item_ID, I.Description, Sum(S.Quantity) -- It will return Null for Mango Juice
FROM ITEMS I
LEFT JOIN SALES S ON I.Item_ID = S.Item_ID
Group By I.Item_ID, I.Description
ORDER BY I.Item_ID;
OR:
SELECT I.Item_ID, I.Description, CASE WHEN Sum(S.Quantity) IS NULL THEN 0 ELSE Sum(S.Quantity) END Quantity -- It will return 0 for Mango Juice
FROM ITEMS I
LEFT JOIN SALES S ON I.Item_ID = S.Item_ID
Group By I.Item_ID, I.Description
ORDER BY I.Item_ID;
I am struggling to get my head around this sql.
I have a function that returns a list of items associated with a Bill of Materials BOM.
The result of the sql select
SELECT
BOM,
ITEMID,
QTY
FROM boms
WHERE
bom='A'
is
BOM | ITEMID | QTY
A | ITEMB | 1
A | ITEMC | 2
Now using that result set I am looking to query my salestable to find sales where ITEMB and ITEMC were sold in enough quantity.
The format of the salestable is as follows
SELECT
salesid,
itemid,
sum(qtyordered) 'ordered'
FROM salesline
WHERE
itemid='ITEMB'
or itemid='ITEMC'
GROUP BY salesid, itemid
This would give me something like
salesid | itemid | ordered
SO-10000 | ITEMB | 1
SO-10001 | ITEMB | 1
SO-10001 | ITEMC | 1
SO-10002 | ITEMB | 1
SO-10002 | ITEMC | 2
ideally I would like to return only SO-10002 as this is the only sale where all necessary units were sold.
Any suggestions would be appreciated. Ideally one query would be ideal but I am not sure if that is possible. Performance is not a must as this would be run once a week in the early hours of the morning.
EDIT
with the always excellent help, the code is now complete. I have wrapped it all up into a UDF which simply returns the sales for a specified BOM over a specified period of time.
Function is
CREATE FUNCTION [dbo].[BOMSALES] (#bom varchar(20),#startdate datetime, #enddate datetime)
RETURNS TABLE
AS
RETURN(
select count(q.SALESID) SOLD FROM (SELECT s.SALESID
FROM
(
SELECT s.SALESID, ITEMID, SUM(qtyordered) AS SOLD
FROM salesline s inner join SALESTABLE st on st.salesid=s.SALESID
where st.createddate>=#startdate and st.CREATEDDATE<=#enddate and st.salestype=3
GROUP BY s.SALESID, ITEMID
) AS s
JOIN dbo.BOM1 AS b ON b.ITEMID = s.ITEMID AND b.QTY <= s.SOLD
where b.BOM=#bom
GROUP BY s.SALESID
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.BOM1 WHERE BOM = #bom)) q
)
This should return all sales with an exact match, i.e. same itemid and same quantity:
SELECT s.salesid
FROM
(
SELECT salesid, itemid, SUM(qtyordered) AS ordered
FROM salesline AS s
GROUP BY salesid, itemid
) AS s
JOIN
boms AS b
ON b.itemid = s.itemid
AND b.QTY = s.ordered
WHERE b.BOM='A'
GROUP BY s.salesid
HAVING COUNT(*) = (SELECT COUNT(*) FROM boms WHERE BOM='A');
If you want to return a sale where the quantity is greater than boms.qty youhave to change the join accordingly:
JOIN
boms AS b
ON b.itemid = s.itemid
AND b.QTY <= s.ordered
Untested...
You can do this aggregation and a having clause:
select salesid
from salesline sl
group by salesid
having sum(case when itemid = 'ITEMB' then 1 else 0 end) > 0 and
sum(case when itemid = 'ITEMA' then 1 else 0 end) > 0;
Each condition in the having clause is counting the number of rows with each item.
I think this may get you the results you need. You'll have to replace #BOM with your bom:
SELECT
DISTINCT salesid
FROM
salesline sl
INNER JOIN boms b ON
b.bom = #BOM
AND b.itemid = sl.itemid
GROUP BY salesid, itemid
HAVING SUM(qtyordered) >= b.qty
From what I gather, the first query is used to get the thresholds for returning qualifying sales? Based on your example data rows I assumed that there will only be one line per salesid + itemid (basically acting as a dual field primary key) in the salesline table? If that is true I don't think there is a need to do a SUM as you have in your second example query. Let me know if I'm mistaken in any of my assumptions and I'll adjust my answer.