I am using SQL Server. The Formula I need to use is (Good-Bad)/Total_Responses. A Good is when the value is >=9 and a Bad is <=6.
The Data I have is:
DATE Q1 Q2
2012-03-04 9 9
2012-03-04 8 8
2012-03-04 7 9
2012-03-04 4 NA
2012-03-04 10 10
2012-03-04 8 3
2012-03-04 3 4
2012-03-04 2 6
2012-03-04 6 8
2012-03-04 NA 6
I know I am going to have to use a "CASE WHEN ISNUMERIC(Q1)=1" to make sure it does not use the NA values (They are stored as Nvarchar)
So the formula would end up being (5-8)/18=-0.16666
So overall I am trying to get the data to look like:
DATE Promotor_Score
2012-03-04 -0.16666
Thank You!
Does this do the trick?
SELECT Date,
CAST((SUM(CASE WHEN ISNUMERIC(Q1) != 1 THEN 0
WHEN CAST(Q1 AS int) >= 9 THEN 1
WHEN CAST(Q1 AS int) <= 6 THEN -1
ELSE 0 END)
+ SUM(CASE WHEN ISNUMERIC(Q2) != 1 THEN 0
WHEN CAST(Q2 AS int) >= 9 THEN 1
WHEN CAST(Q2 AS int) <= 6 THEN -1
ELSE 0 END)) AS float)
/ (SUM(CASE WHEN ISNUMERIC(Q1) != 1 THEN 0
ELSE 1 END)
+ SUM(CASE WHEN ISNUMERIC(Q2) != 1 THEN 0
ELSE 1 END))
FROM Questions
GROUP BY Date
Or if 'NA' is the only non-numeric value, test for it explicitly.
Buildin on #DavidM answer, I added float conversion and Q2 column awareness:
SELECT [date],
1e0 -- a float multiplier to avoid integer value
* SUM( 0
-- get the positive, negative or neutral from q1
+ CASE WHEN ISNUMERIC(q1) != 1 THEN 0
WHEN CAST(q1 AS int) >= 9 THEN 1
WHEN CAST(q1 AS int) <= 6 THEN -1
ELSE 0 END
-- get the positive, negative or neutral from q2
+ CASE WHEN ISNUMERIC(q2) != 1 THEN 0
WHEN CAST(q2 AS int) >= 9 THEN 1
WHEN CAST(q2 AS int) <= 6 THEN -1
ELSE 0 END
)
/ SUM( 0
-- get the number of valid questions from q1
+ CASE WHEN ISNUMERIC(q1) != 1 THEN 0 ELSE 1 END
-- get the number of valid questions from q2
+ CASE WHEN ISNUMERIC(q2) != 1 THEN 0 ELSE 1 END
)
FROM Questions
GROUP BY Date;
Related
I am relatively new to SQL. I have a dataset as follows:
'ID' 'date'
1 2016-01-01 01:01:06
2 2016-01-02 02:02:07
1 2016-01-03 03:03:08
3 2016-04-04 04:04:09
2 2016-04-05 05:05:00
I want to obtain smth like this:
'ID' 'Count: Jan' 'Count: Feb' 'Count: March' 'Count: April'
1 2 0 0 0
2 1 0 1 0
3 0 0 0 1
I really have no idea how handle this. I could put the data creating a column "month" and another column "count" but I want to be able to have a table like this.
Thanks in advance
You ca use conditional aggregation:
select id,
sum(case when month(date) = 1 then 1 else 0 end) as cnt_jan,
sum(case when month(date) = 2 then 1 else 0 end) as cnt_feb,
. . .
sum(case when month(date) = 12 then 1 else 0 end) as cnt_dec
from t
group by id;
I have troubles to display consecutive holidays from an existing date dataset in Oracle SQL. For example, in December 2017 between 20th and 30th, there are the following days off (because Christmas and weekend days):
23.12.2017 Saturday
24.12.2017 Sunday
25.12.2017 Christmas
30.12.2017 Saturday
Now I want my result dataset to look like this (RUNTOT is needed):
DAT ISOFF RUNTOT
20.12.2017 0 0
21.12.2017 0 0
22.12.2017 0 0
23.12.2017 1 1
24.12.2017 1 2
25.12.2017 1 3
26.12.2017 0 0
27.12.2017 0 0
28.12.2017 0 0
29.12.2017 0 0
30.12.2017 1 1
That means when "ISOFF" changes I want to count (or sum) the consecutive rows where "ISOFF" is 1.
I tried to approach a solution with an analytic function, where I summarize the "ISOFF" to the current row.
SELECT DAT,
ISOFF,
SUM (ISOFF)
OVER (ORDER BY DAT ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS RUNTOT
FROM (TIME_DATASET)
WHERE DAT BETWEEN DATE '2017-12-20' AND DATE '2017-12-27'
ORDER BY 1
What I get now is following dataset:
DAT ISOFF RUNTOT
20.12.2017 0 0
21.12.2017 0 0
22.12.2017 0 0
23.12.2017 1 1
24.12.2017 1 2
25.12.2017 1 3
26.12.2017 0 3
27.12.2017 0 3
28.12.2017 0 3
29.12.2017 0 3
30.12.2017 1 4
How can I reset the running total if ISOFF changes to 0? Or is this the wrong approach to solve this problem?
Thank you for your help!
This is a gaps-and-islands problem. Here is one method that assigns the groups by the number of 0s up to that row:
select t.*,
(case when is_off = 1
then row_number() over (partition by grp order by dat)
end) as runtot
from (select t.*,
sum(case when is_off = 0 then 1 else 0 end) over (order by dat) as grp
from TIME_DATASET t
) t;
You may use the recursive recursive subquery factoring - the precondition is, that your dates are consecutive without gaps (or you have some oder row number sequence to follow in steps of one).
WITH t1(dat, isoff, runtot) AS (
SELECT dat, isoff, 0 runtot
FROM tab
WHERE DAT = DATE'2017-12-20'
UNION ALL
SELECT t2.dat, t2.isoff,
case when t2.isoff = 0 then 0 else runtot + t2.isoff end as runtot
FROM tab t2, t1
WHERE t2.dat = t1.dat + 1
)
SELECT dat, isoff, runtot
FROM t1;
DAT ISOFF RUNTOT
------------------- ---------- ----------
20.12.2017 00:00:00 0 0
21.12.2017 00:00:00 0 0
22.12.2017 00:00:00 0 0
23.12.2017 00:00:00 1 1
24.12.2017 00:00:00 1 2
25.12.2017 00:00:00 1 3
26.12.2017 00:00:00 0 0
27.12.2017 00:00:00 0 0
28.12.2017 00:00:00 0 0
29.12.2017 00:00:00 0 0
30.12.2017 00:00:00 1 1
Another variation, which doesn't need a subquery or CTE but does need all days to be present and have the same time, is - for the holiday dates only (where isoff = 1) - to see how many days it's been since the last non-holiday date:
select dat,
isoff,
case
when isoff = 1 then
coalesce(dat - max(case when isoff = 0 then dat end)
over (order by dat range between unbounded preceding and 1 preceding), 1)
else 0
end as runtot
from time_dataset
order by dat;
DAT ISOFF RUNTOT
---------- ---------- ----------
2017-12-20 0 0
2017-12-21 0 0
2017-12-22 0 0
2017-12-23 1 1
2017-12-24 1 2
2017-12-25 1 3
2017-12-26 0 0
2017-12-27 0 0
2017-12-28 0 0
2017-12-29 0 0
2017-12-30 1 1
The coalesce() is there in case the first date in the range is a holiday - as there is no previous non-holiday date to compare against, that subtraction would get null.
db<>fiddle with a slightly larger data set.
I have a table that holds data about class entries for a certain journal. I'm trying to separate the results by week so I get a count of those entries per week. But when I group by day, I get null values too. I want to omit records with Null Values. How do I do that?
I wrote the following code:
SELECT Year(JournalDate) AS YY
,Month(JournalDate) AS MM
,FromClass
,ToClass
,(SELECT Count(JournalID)
WHERE Day(JournalDate) >= 1 AND Day(JournalDate)=7) AS CountWeek1
,(SELECT Count(JournalID)
WHERE Day(JournalDate) >= 8 AND Day(JournalDate)=14) AS CountWeek2
,(SELECT Count(JournalID)
WHERE Day(JournalDate) >= 15 AND Day(JournalDate)=21) AS CountWeek3
,(SELECT Count(JournalID)
WHERE Day(JournalDate) >= 22 AND Day(JournalDate)=28) AS CountWeek4
,(SELECT Count(JournalID)
WHERE Day(JournalDate) >= 29 AND Day(JournalDate)=31) AS CountWeek5
FROM [tblJournal]
WHERE [JournalDate] >= '2016-09-01 00:00:00.000'
AND FromClass <> ToClass
--AND CountWeek1 IS NOT Null
GROUP BY Year(JournalDate), Month(JournalDate), Day( JournalDate), FromClass, ToClass
ORDER BY YY, MM, FromClass, ToClass
But I get Null values too. I want to remove Null Values.
YY MM FrClass ToClass CntWk1 CntWk2 CntWk3 CntWk4 CntWk5
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL 20 NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 12 NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL 29 NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL NULL NULL
2016 9 1 2 NULL NULL NULL 25 NULL
How do I omit the records with NULL values?
EDIT:
So I would actually like my results to look like this:
YY MM FrmCls ToClsWk1 Wk2 Wk3 Wk4 Wk5
2016 9 1 2 12 20 29 25 0
2016 9 1 3 2 1 6 0 0
2016 9 1 4 0 1 2 0 0
2016 9 2 1 0 3 0 2 0
2016 9 2 3 74 46 84 54 0
2016 9 2 4 0 0 8 5 0
2016 9 3 2 0 813 0 0 0
Take your data above and insert into a temp table. After that you can query on your result by suming data by year, month, etc. like this:
SELECT YY, MM, FrClass,ToClass,SUM(cntwk1),SUM(cntwk2),SUM(cntwk3),SUM(cntwk4),SUM(cntwk5)
FROM #data
GROUP BY YY, MM, FrClass,ToClass
how about this
select * from
(
SELECT Year(JournalDate) AS YY
,Month(JournalDate) AS MM
,FromClass
,ToClass
,isnull((SELECT Count(JournalID)
WHERE Day(JournalDate) >= 1 AND Day(JournalDate)=7),0) AS CountWeek1
,isnull((SELECT Count(JournalID)
WHERE Day(JournalDate) >= 8 AND Day(JournalDate)=14),0) AS CountWeek2
,isnull((SELECT Count(JournalID)
WHERE Day(JournalDate) >= 15 AND Day(JournalDate)=21),0) AS CountWeek3
,isnull((SELECT Count(JournalID)
WHERE Day(JournalDate) >= 22 AND Day(JournalDate)=28),0) AS CountWeek4
,isnull((SELECT Count(JournalID)
WHERE Day(JournalDate) >= 29 AND Day(JournalDate)=31),0) AS CountWeek5
FROM [tblJournal]
WHERE [JournalDate] >= '2016-09-01 00:00:00.000'
AND FromClass <> ToClass
GROUP BY Year(JournalDate), Month(JournalDate), Day( JournalDate), FromClass, ToClass
) x
where CountWeek1 +CountWeek2+CountWeek3+CountWeek4+CountWeek5 <> 0
ORDER BY YY, MM, FromClass, ToClass
Problem: Time Span between two dates. I would like to know how many months are between each date. The trick is: the number of months in each year between the two dates.
For example:
Start date = 1/1/2014
End Date = 3/1/2016
The output:
Column 1: "2014" would have a value of 12
Column 2: "2015" would have a value of 12
Column 3: "2016" would have a value of 2
This would be for a list with many dates (with different years)
EDIT: You would indeed have to have 14 year columns for a date span between 2000-2014. However, it is unlikely that more than 5 columns would need to be added.
Current train of thought
declare #datediff as int
select
#datediff=(Datediff(MONTH,[begin date], [end date]))
from [DateRange]
select
case
when #datediff <= 12 then #datediff
when #datediff <= 24 then #datediff -12
when #datediff <= 36 then #datediff -24
when #datediff <= 48 then #datediff -36
else NULL
end
from [DateRange]
Any ideas on this one?
I am very new to SQL and was only able to get the total months between the two with the following code:
select
datediff(MONTH,[begin date], [end date])
from [tableofdates]
Use below Query, you need to use your table in place of mydates table in below example. I used for maximum 10 year difference (represented by columns Y1,Y2 ... Y10).
The outer Query group by is used transpose the data to match to your requirement where you wanted month difference in column...
Inner query Q3 will provide the same results in rows with no limit to date range (actually there is limit i.e 2048 years due to master table master..spt_values which I guess you will not reach).
select
Q3.begindt,
Q3.enddt,
Q3.Diff_in_Year,
sum(Case when Q3.Year_Counter = 0 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y1,
sum(Case when Q3.Year_Counter = 1 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y2,
sum(Case when Q3.Year_Counter = 2 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y3,
sum(Case when Q3.Year_Counter = 3 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y4,
sum(Case when Q3.Year_Counter = 4 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y5,
sum(Case when Q3.Year_Counter = 5 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y6,
sum(Case when Q3.Year_Counter = 6 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y7,
sum(Case when Q3.Year_Counter = 7 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y8,
sum(Case when Q3.Year_Counter = 8 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y9,
sum(Case when Q3.Year_Counter = 9 Then datediff(mm,Q3.y_start,Q3.y_end)+1 else 0 end) Y10
From
(select
Q1.begindt,
Q1.enddt,
Q1.years Diff_in_Year,
Q2.number as Year_Counter,
(Case when Q2.number = 0 then Q1.begindt else dateadd(yy, datediff(yy,0,dateadd(yy,q2.number,q1.begindt)),0)End) AS y_Start,
(case when ((Q1.years-1) = Q2.number) then Q1.enddt else DATEADD(yy, DATEDIFF(yy,0,dateadd(yy,q2.number+1,q1.begindt) + 1), -1) End) AS y_End,
Year(Q1.begindt)+Q2.number YearInYYYY
from
(select begindt,enddt,DATEDIFF(year,begindt,enddt)+1 as years from mydates) Q1
join master..spt_values Q2 on Q2.type = 'P' and Q2.number < Q1.years
) Q3
Group by Q3.begindt,Q3.enddt,q3.Diff_in_Year
Output of the Above Query
begindt enddt YDif Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10
2010-07-02 2014-02-06 5 6 12 12 12 2 0 0 0 0 0
2011-01-01 2014-12-31 4 12 12 12 12 0 0 0 0 0 0
2012-05-22 2017-12-16 6 8 12 12 12 12 12 0 0 0 0
I have three tables which are like:
table1
id,
created_Date
table2
id
district_ID
status_ID
table3
district_ID
district_Name
Now i need the records in following format
Srno District_name <10 days >10 and <20 days >20 days
1 xxx 12 15 20
2 yyy 8 0 2
count days as per current date
for example: if the created date is 10-08-2013 and current date is 13-08-2013 the date difference will be 3
So what should my query be? Any suggestions will be appreciated.
Thank you
table1
id created_Date
1 2013-07-12 13:32:10.957
2 2013-07-12 13:32:10.957
3 2013-08-01 10:00:10.957
4 2013-08-10 13:32:10.957
5 2013-08-10 14:32:10.957
table2
id district_ID status_id
1 1 3
2 2 3
3 2 7
4 3 4
5 4 3
table1
district_ID district_Name
1 xxx
2 yyy
3 zzz
4 aaa
5 bbb
I would have a look at using DATEDIFF and CASE.
DATEDIFF (Transact-SQL)
Returns the count (signed integer) of the specified datepart
boundaries crossed between the specified startdate and enddate.
Something like
SELECT District_name,
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) < 10
THEN 1
ELSE 0
END
) [<10 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 10 AND DATEDIFF(day,created_Date, getdate()) < 20
THEN 1
ELSE 0
END
) [>10 and <20 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 20
THEN 1
ELSE 0
END
) [>20 days]
FROM Your_Tables_Here
GROUP BY District_name
;with cte as (
select t3.district_Name, datediff(day, t1.created_Date, getdate()) as diff
from table1 as t1 as t1
inner join table2 as t2 on t2.id = t1.id
inner join table3 as t3 on t3.district_id = t2.district_id
)
select
district_Name,
sum(case when diff < 10 then 1 else 0 end) as [<10 days],
sum(case when diff >= 10 and diff < 20 then 1 else 0 end) as [>=10 and < 20 days],
sum(case when diff >= 20 then 1 else 0 end) as [>= 20 days]
from cte
group by district_Name