Error Message in a Case Statement - plsql

I have written the following statement which doesn't work because of the In clause i've added. Can someone help suggest a workable solution?
What I want to do is measure the min/max values of grades for each record key. Some have more than one grade so thats why I've added the In clause so it will factor this?
case when MIN("Grade - Current"."Grade Equivalency")=MIN("Grade - Current"."Grade Equivalency")
IN (People." Record Key") then 'y' else 'n' end
The data in the table looks like this:
RecordKey Version Grade
165 2009 1
165 2012 2
175 2009 1
189 2012 1
200 2009 2
200 2012 1

You already have a Boolean condition:
"MIN("Grade - Current"."Grade Equivalency")=MIN("Grade - Current"."Grade Equivalency")" in your when, so you cannot also do an IN clause too.
Also when you use the IN clause in the parenthesis you have to put values not table columns.
Maybe you need something like:
case
when MIN("Grade - Current"."Grade Equivalency")=MIN("Grade - Current"."Grade Equivalency") AND MIN("Grade - Current"."Grade Equivalency") IN (one or more values...) then 'y'
else 'n'
end
Second answer...
It's a little more complex, as it uses analytical functions.
Take a look below:
select RECORDKEY, VERSION_YEAR, GRADE,
case
when GRADE_PREV = 0 and GRADE_NEXT >= 0 then 'Stayed the same'
when GRADE_PREV = 0 and GRADE_NEXT > 0 then 'Stayed the same'
when GRADE_PREV > 0 and GRADE_PREV < GRADE then 'increased'
when GRADE_PREV > 0 and GRADE_PREV > GRADE then 'decreased'
else null
end as grade_change
from
(
select RECORDKEY, VERSION_YEAR, GRADE
,LAG(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_PREV
,LEAD(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_NEXT
from PLCH_GRADES
)
order by 1,2
Third answer...
Here it is, now integrating your "original" query:
select RECORDKEY, CALENDAR_YEAR, HEADCOUNT, GRADE,
case
when GRADE_PREV = 0 and GRADE_NEXT >= 0 then 'Stayed the same'
when GRADE_PREV = 0 and GRADE_NEXT > 0 then 'Stayed the same'
when GRADE_PREV > 0 and GRADE_PREV < GRADE then 'increased'
when GRADE_PREV > 0 and GRADE_PREV > GRADE then 'decreased'
else NULL
end as GRADE_CHANGE
from
(
select RECORDKEY, CALENDAR_YEAR, HEADCOUNT, GRADE
,LAG(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_PREV
,LEAD(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_NEXT
from
(
select
PEOPLE."Record Key" as RECORDKEY,
CALENDAR.year as CALENDAR_YEAR,
"Grade - Current"."Grade Equivalency" as GRADE,
"Fact - People".HEADCOUNT
from test
where location = 'NI'
and PEOPLE."Status Group" = 'CURRENT'
and PEOPLE."Headcount Marker" in ('Paid', 'Unpaid')
AND Calendar.Year IN ('2009', '2012')
)
)
order by 1,2

Related

WITH RECURSIVE looping through every day in the database and SUM number between two dates for each

I struggle with the last part below, the "with recursive". Of course I could loop over TimestampOrigin using C#, for every day in the database. Which would mean hundreds of times the same query. But it may be possible with one query using "with recursive".
Test data:
CREATE TABLE tblData(
Id INT, ComputerName TEXT, TimestampOrigin TEXT, Timestamp TEXT, Number INT
);
DELETE FROM tblData;
INSERT INTO tblData VALUES (1, "Computer1", '2021-02-10 12:00:00', '2021-02-27 12:00:00', 35);
INSERT INTO tblData VALUES (2, "Computer2", '2021-02-10 12:00:00', '2021-02-27 12:00:00', 24);
INSERT INTO tblData VALUES (3, "Computer3", '2021-02-09 12:00:00', '2021-02-26 12:00:00', 23);
INSERT INTO tblData VALUES (3, "Computer4", '2021-02-09 12:00:00', '2021-02-26 12:00:00', null);
INSERT INTO tblData VALUES (4, "Computer5", '2021-02-08 12:00:00', '2021-02-25 12:00:00', 7);
INSERT INTO tblData VALUES (5, "Computer6", '2021-02-08 12:00:00', '2021-02-25 12:00:00', 0);
INSERT INTO tblData VALUES (7, "Computer7", '2021-02-07 12:00:00', '2021-02-24 12:00:00', 9);
Query grouped by TimestampOrigin:
SELECT DATE(TimestampOrigin) AS TimestampOrigin,
SUM(CASE WHEN Number < 1 THEN 1 ELSE 0 END) AS Less1,
SUM(CASE WHEN Number >= 0 AND Number < 10 THEN 1 ELSE 0 END) AS Less10,
SUM(CASE WHEN Number >= 10 AND Number < 25 THEN 1 ELSE 0 END) AS Less25
FROM tblData WHERE Number NOT NULL GROUP BY DATE(TimestampOrigin) ORDER BY TimestampOrigin DESC
What I need is for every day the sum for the current up to Timestamp which is current day +17 days. Example for day 2021-02-08, sum of all rows with TimestampOrigin 2021-02-08 up to 2021-02-08 +17 days (column Timestamp).
Don't know if the extra column Timestamp which is noon time of TimestampOrigin +17 days is really required. But the over time query was the reason why I created it at the very beginning of the project.
SELECT DATE(TimestampOrigin) AS TimestampOrigin,
SUM(CASE WHEN Number < 1 THEN 1 ELSE 0 END) AS Less1,
SUM(CASE WHEN Number >= 0 AND Number < 10 THEN 1 ELSE 0 END) AS Less10,
SUM(CASE WHEN Number >= 10 AND Number < 25 THEN 1 ELSE 0 END) AS Less25
FROM tblData WHERE Number NOT NULL AND DATE(TimestampOrigin) >= DATE('2021-02-08') AND DATE(TimestampOrigin) <= DATE('2021-02-08', '+17 day')
Instead of executing the above query hundreds of times for each day and sum, I thought "with recursive" is the right approach". But was not able so far to make it work. Where to add the 17 days?
WITH RECURSIVE cte AS (
SELECT Id, ComputerName, Timestamp, DATE(Timestamp,'+1 day') totime, Number, TimestampOrigin
FROM tblData
UNION ALL
SELECT Id, ComputerName, DATE(Timestamp,'+1 day'), DATE(totime,'+1 day'), Number, TimestampOrigin
FROM cte
WHERE Number NOT NULL AND DATE(Timestamp,'+1 day') < DATE('2021-02-11')
)
SELECT DATE(TimestampOrigin),
SUM(CASE WHEN Number < 1 THEN 1 ELSE 0 END) AS Less1,
SUM(CASE WHEN Number >= 0 AND Number < 10 THEN 1 ELSE 0 END) AS Less10,
SUM(CASE WHEN Number >= 10 AND Number < 25 THEN 1 ELSE 0 END) AS Less25
FROM cte GROUP BY DATE(TimestampOrigin) ORDER BY DATE(TimestampOrigin) DESC
Expected result would be (Like when I would run the above query for each of the 4 days in the test data):
There is no need for a recursive CTE.
Join the distinct TimestampOrigins to the table under your condition and aggregate:
SELECT t1.TimestampOrigin,
SUM(t2.Number < 1) AS Less1,
SUM(t2.Number >= 0 AND t2.Number < 10) AS Less10,
SUM(t2.Number >= 10 AND t2.Number < 25) AS Less25
FROM (SELECT DISTINCT DATE(TimestampOrigin) TimestampOrigin FROM tblData) t1
INNER JOIN tblData t2
ON DATE(t2.TimestampOrigin) BETWEEN t1.TimestampOrigin AND DATE(t1.TimestampOrigin, '+17 days')
GROUP BY t1.TimestampOrigin
ORDER BY t1.TimestampOrigin DESC
See the demo.
Results:
TimestampOrigin
Less1
Less10
Less25
2021-02-10
0
0
1
2021-02-09
0
0
2
2021-02-08
1
2
2
2021-02-07
1
3
2
The result was wrong. I've found that my initial query was wrong. But with the solution from #forpas it worked at the end.
Initial single query
SELECT
SUM(Number < 1) AS Less1,
SUM(Number >= 1 AND Number < 10) AS Less10,
SUM(Number >= 10 AND Number < 25) AS Less25
FROM tblPCHardwareInformation WHERE UniqueInventoryKey IN
(
SELECT UniqueInventoryKey FROM tblPCHardwareInformation WHERE Number NOT NULL AND DATE(Timestamp) BETWEEN DATE('2020-10-09') AND DATE('2020-10-09', '+17 day') GROUP BY ComputerName ORDER BY Timestamp DESC
)
Result:
SELECT t1.TimestampOrigin,
SUM(t2.Number < 1) AS Less1,
SUM(t2.Number >= 1 AND t2.Number < 10) AS Less10,
SUM(t2.Number >= 10 AND t2.Number < 25) AS Less25
FROM (SELECT DISTINCT DATE(TimestampOrigin) TimestampOrigin FROM tblPCHardwareInformation) t1
INNER JOIN tblPCHardwareInformation t2
ON UniqueInventoryKey IN
(
SELECT UniqueInventoryKey FROM tblPCHardwareInformation WHERE Number NOT NULL AND DATE(Timestamp) BETWEEN DATE(t1.TimestampOrigin) AND DATE(t1.TimestampOrigin, '+17 day') GROUP BY ComputerName ORDER BY Timestamp DESC
)
GROUP BY t1.TimestampOrigin
ORDER BY t1.TimestampOrigin DESC

two counts in the same row

is't possible to set 2 counts in the same row.
my result from query is like this:
enter image description here
and i will that the end result seem like this :
enter image description here
and at the end build the precent count1 to count2
my attempt trough case was not successful : SELECT Date,Shift , CASE description WHEN 'Defects' THEN count ELSE 0 END AS Defect_Count , CASE description WHEN 'Total' THEN count ELSE 0 END AS Total_Count FROM ("Queries union)
Here you go. Hope this helps. Thanks.
MYSQL:
select
t.dates, t.shift,
sum(case when t.description = 'Defects' then t.counts else 0 end) as `Defects`,
sum(case when t.description = 'Total' then t.counts else 0 end) as `Total`
from (
select *
from tbl ) t
group by t.dates, t.shift
order by t.dates, t.shift
ORACLE:
SELECT dates, shift, defects , total
FROM
(
SELECT *
FROM tbl
)
PIVOT
(
sum(counts)
FOR description IN ('Defects' as defects, 'Total' as total)
)
ORDER BY dates
Result:
dates shift Defects Total
2018-01-20 AM 21 56
2018-01-20 PM 19 54
2018-01-23 AM 16 58
2018-01-23 PM 20 45
many Thanks is working for the first Step (counts in the same Row).
i will try now to build the percent (Defects to Total).
Thanks.
to build the percent (defects to Total):
select dates,shift,defects,total,round((100*defects/total),2) Percent2Total from(select t.dates, t.shift,
sum(case when t.description = 'Defects' then t.counts else 0 end) as 'Defects',
sum(case when t.description = 'total' then t.counts else 0 end) as 'Total'
from (
select *
from tbl ) t
group by t.dates, t.shift
)q order by dates,Shift.
may be it's possible to build that only with Pivot or?

group by time interval

Assume I have a table like
how can I create a table like
where the groups are created of timeintervals with the length of 1 second.
Thank you in advance!
Here is an idea, but you need a table of numbers
select (m.startts + n.n - 1) as starttime,
(m.startts + n.n) as enddtime,
sum(case when vehicle_type = 'bus' then 1 else 0 end) as bus,
sum(case when vehicle_type = 'car' then 1 else 0 end) as car
from (select min(Timestamp) as startts from table t) m cross join
(select 1 as n union all select 2 union all select 3) n left join
table t
on t.timestamp >= m.startts + n.n - 1 and
t.timestamp < m.startts + n.n
group by m.startts + n.n;
This is a little dangerous because of the floating point arithmetic, but it will probably work for your purposes.

count results from a case statement

I'm trying to figure out how to count the number of occurrences based on a case statement:
select
case
when name.ssn > 0
then 'YES'
when name.taxid > 0
then 'NO'
else 'OTHER' end "Category",
name.created
from
name
where
name.id = 11111
I now want to return the count of YESs, OTHERs, and NOs in one column but can't seem to figure out how to do that.
You just need to count the result over group by statement
select count(col),col from(
select
case
when name.ssn > 0
then 'YES'
when name.taxid > 0
then 'NO'
else 'OTHER' end as col,
name.created
from
name
where
name.id = 11111
) group by col;

SQL Server 2012 query to compute calculations

I am building a query within SQL Server that is calculating scores we receive for our surveys. We have a column called overall_score, where the user inputs a number from 1-5 as a rating. I am trying to create a stored procedure that will calculate ratings based off the scores.
Score rating = (Total count of scores 4 and 5)/(Total number of responses) * 100
I have three separate select statements that create results I need, but when I go to combine them together my output is 0.
Can someone please guide me on what I am doing wrong here?
Separate SQL Statements:
SELECT count(overall_score) FROM Layer1_DataMerge WHERE overall_score = 4;
SELECT count(overall_score) FROM Layer1_DataMerge WHERE overall_score = 5;
SELECT count(overall_score) FROM Layer1_DataMerge;
Combined together:
SELECT distinct
(
(
(SELECT count(overall_score) FROM Layer1_DataMerge WHERE Overall_Score = 4) +
(SELECT count(overall_score) FROM Layer1_DataMerge WHERE overall_score = 5)
) / (SELECT count(overall_score) FROM Layer1_DataMerge)
) AS CSAT
FROM Layer1_DataMerge;
Well the reason you're getting zero is because you're doing integer division. With integer division 1/3 = 0. You need to convert to floating-point arithmetic, plus you can do it all in one query:
SELECT 100.0 *
(SUM(CASE WHEN overall_score = 4 THEN 1 ELSE 0 END) +
SUM(CASE WHEN overall_score = 5 THEN 1 ELSE 0 END)) /
COUNT(overall_score)
or
SELECT 100.0 *
SUM(CASE WHEN overall_score IN (4,5) THEN 1 ELSE 0 END) /
COUNT(overall_score)
To only show 2 decimals you can either cast to a numeric type with 2 decimals:
SELECT CAST(
100.0 *
SUM(CASE WHEN overall_score IN (4,5) THEN 1 ELSE 0 END) /
COUNT(overall_score)
AS NUMERIC(5,2))
Or use STR to convert to a string:
SELECT STR(
100.0 *
SUM(CASE WHEN overall_score IN (4,5) THEN 1 ELSE 0 END) /
COUNT(overall_score)
,5,2)

Resources