aggregate function error in case expression - sql

I have this query
SELECT mylearning.Employee_Id,
case
when max(case when not mylearning.CourseStatusTXT = 'Completed' then 1 else 0 end) = 0 then '2018 Complete'
when max(case when mylearning.CourseStatusTXT in ('Started', 'Not Started') then 1 else 0 end) = 1 then '2018 Not Complete'
end as Completion_Status
FROM Analytics.myLearning_Completions as mylearning inner join Analytics.Workday WD on mylearning.Employee_ID = WD.Employee_ID
And I want to add a condition to the first when statement to make it like this
when max(case when not mylearning.CourseStatusTXT = 'Completed' then 1 else 0 end) = 0
and WD.Adjusted_Hire_Date like '2019% '
and mylearning.CourseTimeCompletedH < cast (WD.Adjusted_Hire_Date as date format 'YYYY/MM/DD') +7
then '2018 Complete'
but I keep getting this error
Executed as Single statement. Failed [3504 : HY000] Selected non-aggregate values must be part of the associated group.
Elapsed time = 00:00:00.069
How can I fix it?

Like a couple others mentioned, you are trying to mix grouped data with non-aggregated data in your calculation, which is why you're getting the 3504 error. You need to either include the referenced columns in your GROUP BY or include them inside an aggregate function (i.e. MAX).
I'm not 100% sure if this is what you're after, but hopefully it can help you along.
SELECT
mylearning.Employee_Id,
CASE
WHEN
MAX(CASE WHEN NOT mylearning.CourseStatusTXT = 'Completed' THEN 1 ELSE 0 END) = 0 AND
WD.Adjusted_Hire_Date like '2019% ' AND
-- Check if most recently completed course is before Hire (Date + 1 week)
MAX(mylearning.CourseTimeCompletedH) <
CAST(WD.Adjusted_Hire_Date AS DATE FORMAT 'YYYY/MM/DD') + 7
THEN '2018 Complete' -- No incomplete learnings
WHEN MAX(
CASE WHEN mylearning.CourseStatusTXT IN ('Started', 'Not Started') THEN 1 ELSE 0 END
) = 1 THEN '2018 Not Complete' -- Started / Not Started learnings exist
END AS Completion_Status
FROM Analytics.myLearning_Completions as mylearning -- Get learning info
INNER JOIN Analytics.Workday WD on mylearning.Employee_ID = WD.Employee_ID -- Employee info
GROUP BY mylearning.Employee_Id, WD.Adjusted_Hire_Date
This will give you a summary per employee, with a couple assumptions:
Assuming employee_ID value in Analytics.Workday is a unique value (one-to-one join), to use WD.Adjusted_Hire_Date in your comparisons, you just need to include it in the GROUP BY.
Assuming you have multiple courses per employee_Id, in order to use mylearning.CourseTimeCompletedH in your comparisons, you'd need to wrap that in an aggregate like MAX.
The caveat here is that the query will check if the most recently completed course per employee is before the "hire_date" expression, so I'm not sure if that's what you're after.
Give it a try and let me know.

The issue here is that you are mixing detail row by row information in the same query as group or aggregated data. Aggregated data will output a single value for all the rows unless you have a group by clause. If you have a group by clause then it will output a single value for each group. When you are grouping you can also include any values that are in the group by clause since they will be unique for the group.
if you want this data for each employee, then you could group by employee_id. Any other data would need to also be an aggregate like Max(Adjusted_Hire_Date)

Maybe this is what you want?
SELECT
mylearning.employee_id
, case
when CourseStatusTXT = 'Completed' and WD.Adjusted_Hire_Date like '2019%'
and mylearning.CourseTimeCompletedH < cast (WD.Adjusted_Hire_Date as date format 'YYYY/MM/DD') +7
then '2018 Complete'
else '2018 Not Complete'
end CompletionStatus
FROM myLearning_Completions mylearning, Workday WD
WHERE mylearning.employee_id = WD.employee_id

Related

SQL Summing columns based on date key

I have a dataset as given in the link, DataSet
I want to segregate the column "order_item_unit_status" as separate column and bring respective transaction amount for the same. Desired output is given below.
Objective is to consolidate the txn_amt into respective categories and group them based on txn_date_key. (Basically pivoting based on order_item_unit_status column and bringing txn_amt respectively.)
I used the below code,
Select *, CASE WHEN order_item_unit_status ='DELIVERED'
THEN txn_amt ELSE 0 END as DELIVERED,
CASE WHEN order_item_unit_status ='RETURNED'
THEN txn_amt ELSE 0 END as RETURNED
from sales
Got output as referred in the link Output
The output is not grouping based on txn_date_key and multiple line items found. If i use GROUP BY txn_date_key an error is thrown.
Also I was informed that server is supported by HiveSQL and does not support of using ":", date time, and temp tables can not be created. I'm currently stuck on how to go about given the constraints.
Help would be much appreciated
You have to use your columns in the group by:
EDIT: also SUM() added for the correct output...
Select *,
SUM(CASE WHEN order_item_unit_status ='DELIVERED'
THEN txn_amt ELSE 0 END) as DELIVERED,
SUM(CASE WHEN order_item_unit_status ='RETURNED'
THEN txn_amt ELSE 0 END) as RETURNED
from sales
group by txn_amt,txn_date_key,order_item_unit_status
In hivesql you can use from_unixtime command
Unixtime
All columns which are not aggregated and selected shold be in group by.
This query produces result you need:
Select txn_date_key,
sum(CASE WHEN order_item_unit_status ='DELIVERED'
THEN txn_amt ELSE 0 END) as DELIVERED,
sum(CASE WHEN order_item_unit_status ='RETURNED'
THEN txn_amt ELSE 0 END) as RETURNED
from sales
group by txn_date_key
Result:
txn_date_key delivered returned
20190701 3200 0
20210631 0 3000

Using SUM SEC_TO_TIME in MariaDB

Reference from How to sum time using mysql
I want to SUM Field LogsFormatted.Late Every month with query :
SELECT
SUM(CASE
WHEN MONTH (LogsFormatted.DateIn) = 1
THEN SEC_TO_TIME( SUM( TIME_TO_SEC(LogsFormatted.Late)))
ELSE 0 END
) AS '1'
FROM
HrAttLogsFormatted AS LogsFormatted
But the result is
1111 - Invalid use of group function
Where is the problem with the query? resulting in an error output.. Thank you in advance
[EDIT-SOLVED] It's Solved with simply apply
Change format SUM at the beginning of the query
SEC_TO_TIME(SUM(
CASE WHEN MONTH(LogsFormatted.DateIn) = 1 THEN
TIME_TO_SEC(LogsFormatted.Late) END)
) AS '1'
You don't need to call the sum() so many times. You can also move the case condition to the WHERE clause:
SELECT SUM(TIME_TO_SEC(lf.Late))
FROM HrAttLogsFormatted lf
WHERE MONTH(lf.DateIn) = 1 ;
If you want conditional aggregation, then do:
SELECT SUM(CASE WHEN MONTH(lf.DateIn) = 1 THEN TIME_TO_SEC(lf.Late) END)
FROM HrAttLogsFormatted lf;

Converting dates into weekdays then correlating it and summing it

The query is simple but not functioning the way I want it,
I am trying to check the date I inspected is the correct day I am checking against.
Input
SELECT TO_CHAR(date '1982.03.09', 'DAY'),
(CASE When lower(TO_CHAR(date '1982.03.09', 'DAY')) like lower('TUESDAY')
then 1 else 0 end)
Output
The answer should have been 1 for the case statement.
I added lower to check if it had to something with the capitals
Reason
The reason why I use a case statement is because when a student has an afterschool activity on monday, I want to place either 1 or 0 in the table and calculate the sum of how many students have afterschool acitivity on monday and so on.
Need eventually
I am doing this so that I can create a table of the week with the number of children doing aftershool activities for each day.
Any help regarding fixing my query would be greatly appreciated!
Thanks
For whatever reason there are spaces behind the TUESDAY to_char() produces. You can trim() them away. But instead of relying on a string representation (that probably might change when the locale changes) you should better use extract() to get the day of the week in numerical representation, 0 for Sunday, 1 for Monday and so on.
SELECT to_char(DATE '1982.03.09', 'DAY'),
CASE
WHEN trim(to_char(DATE '1982.03.09', 'DAY')) = 'TUESDAY' THEN
1
ELSE
0
END,
CASE extract(dow FROM DATE '1982.03.09')
WHEN 2 THEN
1
ELSE
0
END;
I'm a personal fan of extract (<datepart> from <date>) in lieu of to_char for problems like this.
Based on the output you are trying to achieve, I might also recommend a poor man's pivot table:
select
student_id,
max (case when extract (dow from activity_date) = 1 then 1 else 0 end) as mo,
max (case when extract (dow from activity_date) = 2 then 1 else 0 end) as tu,
max (case when extract (dow from activity_date) = 3 then 1 else 0 end) as we,
max (case when extract (dow from activity_date) = 4 then 1 else 0 end) as th,
max (case when extract (dow from activity_date) = 5 then 1 else 0 end) as fr
from activities
where activity_date between :FROM_DATE and :THRU_DATE
group by
student_id
Normally this would be a good use case for filter (where, but that would leave null values on date/student records where there is no activity. Depending on how you render your output, that may or may not be okay (Excel would handle it fine).
select
student_id,
max (1) filter (where extract (dow from activity_date) = 1) as mo,
max (1) filter (where extract (dow from activity_date) = 2) as tu,
max (1) filter (where extract (dow from activity_date) = 3) as we,
max (1) filter (where extract (dow from activity_date) = 4) as th,
max (1) filter (where extract (dow from activity_date) = 5) as fr
from activities
group by
student_id

compare two different date ranges sales in two columns

I want to compare two different date ranges sales in two columns.. I am using query below but its giving wrong sales.. please correct my query
select s1.Itm_cd,s1.Itm_Name,Sum(S1.amount),Sum(s2.amount)
from salestrans s1,salestrans s2
where s1.Itm_cd = S2.Itm_cd
and S1.Tran_dt between '20181101' and'20181130'
and S2.Tran_dt between '20171101' and '20171130'
group by s1.Itm_cd,s1.Itm_Name
Order by s1.Itm_cd
I suspect that you want conditional aggregation here:
WITH cte AS (
SELECT
s1.Itm_cd,
s1.Itm_Name,
SUM(CASE WHEN s1.Tran_dt BETWEEN '20181101' AND '20181130'
THEN s1.amount ELSE 0 END) AS sum_2018,
SUM(CASE WHEN s1.Tran_dt BETWEEN '20171101' AND '20171130'
THEN s1.amount ELSE 0 END) AS sum_2017
FROM salestrans s1
GROUP BY
s1.Itm_cd,
s1.Itm_Name
)
SELECT
Itm_cd,
Itm_Name,
sum_2018,
sum_2017,
CASE WHEN COALESCE(sum_2017, 0) <> 0
THEN FORMAT(100.0 * (sum_2018 - sum_2017) / sum_2017, 'N', 'en-us')
ELSE 'NA' END AS growth_pct
FROM cte
ORDER BY
Itm_cd;
Please try the following
select s1.Itm_cd,s1.Itm_Name,Sum(S1.amount),Sum(s2.amount)
from salestrans s1,salestrans s2
where s1.Itm_cd = S2.Itm_cd
and Convert(Varchar(10),S1.Tran_dt,112) between '20181101' and'20181130'
and Convert(Varchar(10),S2.Tran_dt,112) between '20171101' and '20171130'
group by s1.Itm_cd,s1.Itm_Name
Order by s1.Itm_cd
Here the logic is that in right side while comparision you are providing only date and not any separator and time. The same way should be applied to the column in left side for comparision.
if(Convert(Varchar(10), getdate(),112) = '20181224')
print 'Matched'
else
print 'Not Matched'
if(getdate() = '20181224')
print 'Matched'
else
print 'Not Matched'
Here the output is Matched for first and Not Matched because in first case both side same format has been taken for comparison.

Transact-SQL Sub Query

I'm struggling to find the logic of how to accomplish a sub query, or at least that's what I think is required! I'll show what I have:
SELECT CH.SFA,
convert(datetime, RE.START_DATE, 103) AS 'START DATE',
Count(Distinct CH.CHNO) AS 'TOTAL CH',
Count(CH.STATUS) AS 'COMPLETED CH',
count(distinct CH.CHNO + CH.STATUS) As 'COMPLETED CH2'
FROM CUSTOMER.dbo. CH CH, CUSTOMER.dbo.RE RE
WHERE
RE.SFA = CH.SFA
GROUP BY
CH.SFA, RE.START_DATE
What I am trying to do is where I have COMPLETED CH2 I need to specify that it ends with a C, the Status Column is either blanks or C's and by doing a distinct count of CHNO and C together give me the result I need but I cannot for the life of me find out how to write it!
I am using Microsoft Query to take the data from its source straight into the Excel spreadsheet.
Many thanks for taking a look.
Been ages since I've used MS Query so I'm fuzzy on syntax, but this is the general idea of how to write a subquery containing a WHERE clause and an aggregation to get you started:
SELECT
CH.SFA,
convert(datetime, RE.START_DATE, 103) AS 'START DATE',
Count(DISTINCT CH.CHNO) AS 'TOTAL CH',
Count(CH.STATUS) AS 'COMPLETED CH',
CCH.COMPLETED_CH2 AS 'COMPLETED CH2'
FROM CUSTOMER.dbo.CH CH
INNER JOIN CUSTOMER.dbo.RE RE
ON RE.SFA = CH.SFA
LEFT JOIN (
SELECT SFA, COUNT(DISTINCT CH.CHNO) AS COMPLETED_CH2
FROM CUSTOMER.dbo.CH
WHERE STATUS = 'C'
GROUP BY SFA
) AS CCH
ON RE.SFA = CCH.SFA
GROUP BY CH.SFA, RE.START_DATE
if you just want to know count of records where CH.STATUS = 'C' than add another COUNT statement with CASE logic.
COUNT(CASE WHEN CH.STATUS = 'C' then 1 else null end) as 'COMPLETED CH2'
when combining COUNT and CASE statement remember to have NULL for ELSE statement, otherwise all rows will be counted.
as an alternative you can do it with a SUM
SUM(CASE WHEN CH.STATUS = 'C' then 1 else 0 end) as 'COMPLETED CH2'