I am trying to generate a report, and so far have one completed that gives me how many orders, for each day, are in status 1-9.
TableA structure looks like this:
Sales Order | Order Status | Order Date
123456789 | 1 | 2017-02-22 00:00:00.000
123456790 | 0 | 2017-02-21 00:00:00.000
TableB structure looks like this:
Sales Order | Price
123456789 | 123.00
123456789 | 42.00
123456790 | 56.00
123456790 | 28.00
This code:
SELECT
MAX(year([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
Day([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN 1 ELSE 0 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN 1 ELSE 0 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN 1 ELSE 0 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN 1 ELSE 0 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN 1 ELSE 0 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN 1 ELSE 0 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN 1 ELSE 0 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN 1 ELSE 0 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN 1 ELSE 0 END) AS 'STATUS"/"'
FROM
SorMaster
WHERE
YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month, DateAdd(month, Month([OrderDate]) - 1, Cast('2008-01-01' AS Datetime))), Day([OrderDate])
ORDER BY
Yr DESC, M DESC, Day DESC
Returns this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 2 0 1 0 0 5 0 0
2017 2 21 0 0 0 7 0 0 0 0 0
This is PERFECT for my first report.
Now, comes the trouble. My Problem is that I need to nest-query Table B, so that instead of returning a count(orders), I need the sum(orders) those totals for each order are in Table B.
Using the above example, the query would need to return something like this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 165 0 0 0 0 0 0 0
2017 2 21 84 0 0 0 0 0 0 0 0
Any pointers?
Just join to TableB:
SELECT MAX(year([t1.OrderDate])) AS Yr,
MAX(MONTH([t2.OrderDate])) AS M,
DAY([t1.OrderDate]) AS Day,
SUM(CASE WHEN [OrderStatus] = '0' THEN t2.Price ELSE 0 END) AS 'STATUS"0"',
SUM(CASE WHEN [OrderStatus] = '1' THEN t2.Price ELSE 0 END) AS 'STATUS"1"',
SUM(CASE WHEN [OrderStatus] = '2' THEN t2.Price ELSE 0 END) AS 'STATUS"2"',
SUM(CASE WHEN [OrderStatus] = '4' THEN t2.Price ELSE 0 END) AS 'STATUS"4"',
SUM(CASE WHEN [OrderStatus] = '8' THEN t2.Price ELSE 0 END) AS 'STATUS"8"',
SUM(CASE WHEN [OrderStatus] = '9' THEN t2.Price ELSE 0 END) AS 'STATUS"9"',
SUM(CASE WHEN [OrderStatus] = 'S' THEN t2.Price ELSE 0 END) AS 'STATUS"S"',
SUM(CASE WHEN [OrderStatus] = '*' THEN t2.Price ELSE 0 END) AS 'STATUS"*"',
SUM(CASE WHEN [OrderStatus] = '/' THEN t2.Price ELSE 0 END) AS 'STATUS"/"'
FROM SorMaster t1
LEFT JOIN TableB t2
ON t1.[Sales Order] = t2.[Sales Order]
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY Yr DESC, M DEACLLSC, Day DESC
That's not too difficult, just a matter of LEFT JOINing in table B and then summing the prices in that. There's a couple of small tricks here. You want to LEFT JOIN to ensure that rows in table A always show up, even if there are no corresponding rows in table B. Secondly, in your SUM() statement, you'll need to add a COALESCE(...,0.00) to ensure you're summing decimals and no NULL values creep in from the LEFT JOIN. Oddly in databases, NULL + {anything} = NULL.
For the below query, you'll need to change the name of TableB to whatever the table name is, and the JOIN predicate will need to have the column names named accurately, and delimited correctly if they contain spaces. For example, in MSSQL the delimiters are [ and ], e.g. MyTable.[My Column With Spaces]
SELECT
MAX(YEAR([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
DAY([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"/"'
FROM SorMaster
LEFT OUTER JOIN TableB
ON TableB.SalesOrder = SorMaster.SalesOrder
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY
Yr DESC,
M DESC,
Day DESC
By (left) joining tableB and replacing your 'count' ones by tableB.price you should get the sum of all positions of orders with the according status.
I have two tables...
MODULES ENROLMENTS
GroupNo StudentNo
Title GroupNo
Tutor CourseworkMark
DayNo ExamMark
Time
Room
Semester
I wish to create a view that displays the average mark achieved in coursework and exam for each module and also a count of the number of students who achieved >70, 60-69, 50-59, 40-49 and <40. Is this possible?
I have the average marks worked out with...
SELECT Title,
AVG(CourseworkMark) AS AverageCoursework,
AVG(ExamMark) AS AverageExam
FROM tblModules INNER JOIN tblEnrolments
ON tblModules.GroupNo = tblEnrolments.GroupNo
GROUP BY Title;
You can use a SUMmed CASE expression to do this;
SELECT Title,
AVG(CourseworkMark) AS AverageCoursework,
AVG(ExamMark) AS AverageExam,
SUM(CASE WHEN CourseworkMark > 70 THEN 1 ELSE 0 END) AS CourseworkMarkOver70,
SUM(CASE WHEN CourseworkMark BETWEEN 60 AND 70 THEN 1 ELSE 0 END) AS CourseworkMarkOver60To69,
SUM(CASE WHEN CourseworkMark BETWEEN 50 and 59 THEN 1 ELSE 0 END) AS CourseworkMarkOver50To59,
SUM(CASE WHEN CourseworkMark BETWEEN 40 and 49 THEN 1 ELSE 0 END) AS CourseworkMarkOver40To49,
SUM(CASE WHEN CourseworkMark < 40 THEN 1 ELSE 0 END) AS CourseworkMarkUnder40
FROM tblModules INNER JOIN tblEnrolments
ON tblModules.GroupNo = tblEnrolments.GroupNo
GROUP BY Title;
I have Plant, Material, Movement type and Date.
My requirement is I want the MAX date in Material and Plant combination, with Movement type condition
First I need MAX date in Material and Plant combination, where Movement type is 602 , if 602 is null then 601, if 601 is null then 102, if 102 is null then 101 if 101 also is null then other Movement types.
For this I used below code in derived table in IDT but I am not able to get the correct results:
SELECT
DISTINCT
Table__1."0PLANT",
Table__1."0MATERIAL",
Max(Table__1."0PSTNG_DATE") as Last_Sales_Date
FROM
"NM1"."PUBLIC"."IZDSO_DMR" Table__1
Where
CASE
WHEN (Table__1."0MOVETYPE"=602) THEN (Table__1."0MOVETYPE"=602)
WHEN (Table__1."0MOVETYPE"=602) IS NULL THEN (Table__1."0MOVETYPE"=601)
ELSE
(Table__1."0MOVETYPE"=601) END
Group By
Table__1."0MATERIAL",
Table__1."0PLANT"
I tried only for 602, 601 Movement types only
Please help me to get the correct result
This is your where clause:
Where (CASE WHEN (Table__1."0MOVETYPE"=602) THEN (Table__1."0MOVETYPE"=602)
WHEN (Table__1."0MOVETYPE"=602) IS NULL THEN (Table__1."0MOVETYPE"=601)
ELSE (Table__1."0MOVETYPE"=601)
END)
This will actually work with some SQL engines, because a comparison is turned into a number. However, I don't think this is what you want. You are looking to prioritize the max() value, based on the 0MoveType column.
SELECT "0PLANT", "0MATERIAL",
(case when sum(case when "0MOVETYPE" = 602 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 602 then "0PSTNG_DATE" end)
when sum(case when "0MOVETYPE" = 601 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 601 then "0PSTNG_DATE" end)
when sum(case when "0MOVETYPE" = 102 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 102 then "0PSTNG_DATE" end)
when sum(case when "0MOVETYPE" = 101 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 101 then "0PSTNG_DATE" end)
end) as Last_Sales_Date
\FROM "NM1"."PUBLIC"."IZDSO_DMR" Table__1
Group By "0MATERIAL", "0PLANT";
This returns the last sales date for "602" if any are present. If none are present, then it returns the last sales date of "601". If neither "601" nor "602" are present, then it goes to "102" and so on.
I have data in a table called transaction, I have derived purchase value i.e final_rat1 * quantity and sum of purchase quantity
Buysell Quantity Final_rat1
B 50 88.14
B 230 88.14
B 75 88.14
B 87 88.14
B 187 88.14
B 150 88.14
B 221 88.14
Below is the code for it, but when I am averaging purchase value / sum of purchase quantity I'm unable to get proper average. Could you please guide me on this. Below is the code, which I have mentioned
sum(case
when sauda.buysell = 'B' then
sauda.quantity * 1
else
0
end) as "P.Qty",
sum(case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)
else
0
end) As "P.value",
sum(case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)/sauda.quantity
else
0
end) as "P.Avg"
Actual Average should be 88.14 where as i m getting an average of 616.98 and if i remove the sum from below average query
case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)/sauda.quantity
else
0
end as "P.Avg"
it says "not a group by function"
Perhaps you mean something like this:
sum(case
when sauda.buysell = 'B' then
sauda.quantity * 1
else
0
end) as "P.Qty",
sum(case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)
else
0
end) As "P.value",
avg(case
when sauda.buysell = 'B' then
sauda.final_rat1 + sauda.brokpercontract
else
0
end) as "P.Avg"
I have a huge database with over 4 million rows that look like that:
Customer ID Shop
1 Asda
1 Sainsbury
1 Tesco
2 TEsco
2 Tesco
I need to count customers that within last 4 weeks had shopped in all 3 shops Tesco Sainsbury and Asda. Can you please advice if its possible to do it with subqueries?
This is an example of a "set-within-sets" subquery. You can solve it with aggregation:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
This structure is quite flexible. So if you wanted Asda and Tesco but not Sainsbury, then you would do:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) = 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
EDIT:
If you want a count, then use this as a subquery and count the results:
select count(*)
from (select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0
) t