How deal with this issue in SQL with Groupby - sql

I have this data called pdays:
id|time|date_time| type_id
1 2 2016-03-05 1
2 5 2016-03-05 1
3 3 2016-03-06 2
4 7 2016-03-07 3
5 2 2016-03-10 1
6 1 2016-03-12 3
I would like to calculate the average number of time SUM(time) for weekdays and weekends grouped by type_id
The output expect like this:
type_id| weekday_time|weekends_time
1 7 2
2 3 0
3 7 1
This is my thoughts:
First I need to extract date number from date_time; Second, identify the date number whether falls into (5,6,12,13,19,20,26,27) which are weekend numbers (note: This data presents a one month case, so I do not need to worry about the changes of weekend date numbers in next month); Finally, do the aggregation and grouping on type_id
CASE WHEN pday.date IN(5,6,12,13,19,20,26,27) THEN 'weekend' ELSE 'weekday' END
This is the case part I think I should use.

First, your output appears to be wrong. Type_id 3 has both a weekend and a weekday entry, but you show one of the output values as 0.
This should get you what you want in SQL Server and it is very close to other RDBMS's. If you update your RBDMS, I'll change:
;with cte AS (
select type_id,
CASE WHEN pday.date IN(5,6,12,13,19,20,26,27) THEN 'weekday' ELSE 'weekend' END AS day_type,
SUM(time) AS time_sum
FROM pdays
GROUP BY
type_id,
CASE WHEN pday.date IN(5,6,12,13,19,20,26,27) THEN 'weekday' ELSE 'weekend' END
)
SELECT type_id,
SUM(CASE WHEN day_type = 'weekday' THEN time_sum ELSE 0 END) AS 'weekday_time',
SUM(CASE WHEN day_type = 'weekend' THEN time_sum ELSE 0 END) AS 'weekend_time'
FROM cte
GROUP BY [type_id]

Related

How to calculate the average per day for different years

I am trying to calculate the average number of times apple with an increment of 3 are shown per day in the years of both 2018 and 2017. To do this I am trying to use setNum and exNum that has a difference of 3.
ID Year Text setNum ExNum
-------------------------------------------------
1 2018-01-21 apple 1 3
2 2017-08-03 apple 2 5
3 2018-03-02 banana 1 3
4 2018-05-22 apple 1 3
5 2018-12-12 apple 3 6
6 2017-04-13 apple 3 6
My current query to obtain this is:
SELECT
2017 = avg(case when Year BETWEEN '2017-01-01' AND '2017-12-31' then 1 else 0 end),
2018 = avg(case when Year BETWEEN '2018-01-01' AND '2018-12-31' then 1 else 0 end)
FROM
exampleTable
WHERE
Text LIKE '%apple%'
This currently outputs:
2017 2018
0 0
Note: The original table had a single text column Increment, which had values like 1-3. That is, the 1-3 represented a setNum of 1 and an ExNum of 3.
Your decision to store a numerical increment range as text is not a good one, and ideally you should be storing the two points of the increment in separate columns. That being said, we can do some string olympics to work around this:
SELECT
YEAR(Year) AS Year,
COUNT(CASE WHEN 3 BETWEEN CAST(LEFT(Increment, CHARINDEX('-', Increment)-1) AS int) AND
CAST(RIGHT(Increment, LEN(Increment) - CHARINDEX('-', Increment)) AS int)
THEN 1 END) AS apple_3_cnt
FROM exampleTable
WHERE
TEXT LIKE '%apple%'
GROUP BY
YEAR(year);
Demo
Here I am aggregating by year, and then taking a conditional count of record, for each year, where the apple increment range contains 3. To do this, I separate out the two ends of the increment range, and then convert them to integers.
Edit:
Based on your updated table, we can try a simpler query:
SELECT
YEAR(Year) AS Year,
COUNT(CASE WHEN 3 BETWEEN setNum AND ExNum THEN 1 END) AS apple_3_cnt
FROM exampleTable
WHERE
TEXT LIKE '%apple%'
GROUP BY
YEAR(year);
Try below
SELECT
avg(case when Year BETWEEN '2017-01-01' AND '2017-12-31' then setNum+ExNum end) as 2017
avg(case when Year BETWEEN '2018-01-01' AND '2018-12-31' then setNum+ExNum end) as 2018
FROM
exampleTable
WHERE
Text LIKE '%apple%'
Your query is fine. The only problem is how and to where you assign the results.
Use this syntax instead
SELECT
avg(case when Year BETWEEN '2017-01-01' AND '2017-12-31' then 1 else 0 end) as A2017,
avg(case when Year BETWEEN '2018-01-01' AND '2018-12-31' then 1 else 0 end) as A2018
FROM
exampleTable
WHERE
Text LIKE '%apple%'
Note that you can't use numbers as variable names.

Issue on Count of total calls

On a 'CALLS' table each call has a call_start, contact_id, operator_id and so on.
I want to count the tot calls for each client on a specific weekday so I extract weekday (extract weekday from call_start) and I get 0 to 6 results.
I used a case to show weekdays (case when (extract(weekday from call_start)=1) then 'monday' and so on.
Now I enter count( client_id) and I get 2 row for 2 calls, 4 rows for 4 calls, rather than 1 row with 2 calls?
Am I missing something silly here?
I am using Firebird 1.5 by the way
u can try something like this
select
sum(case when extract(weekday from cast(call_start as date))=0 then 1 else 0 end) as qty_sun,
sum(case when extract(weekday from cast(call_start as date))=1 then 1 else 0 end) as qty_mon,
sum(case when extract(weekday from cast(call_start as date))=2 then 1 else 0 end) as qty_tue,
....

How can i get the multiple aggregated data from one column in sql

Suppose i have a table as
days count
0 6 1 7 4 18 1 12 6 8 7 25 2 4 6 30 5 15
and i want the result as three column data
day_range total_count above_threshold_count
0-3 4 1 (assuming threshold as 8)
4-7 5 2 (assuming threshold as 20)
I am able to get the only 2 at a time with the query
select
case when days <=3 then "0-3"
when days <=7 then "4-7" end as day_range,
count(*) from t1
group by case when days <=3 then "0-3"
when days <=7 then "4-7" end
Using conditional aggregation:
SELECT
CASE
WHEN days <=3 THEN '0-3'
WHEN days <=7 THEN '4-7'
END AS day_range,
COUNT(*) AS total_count,
SUM(
CASE
WHEN days <=3 AND [count] > 8 THEN 1
WHEN days <=7 AND [count] > 20 THEN 1
END
) AS above_treshold_count
FROM t1
GROUP BY
CASE
WHEN days <=3 THEN '0-3'
WHEN days <=7 THEN '4-7'
END
Please try below SQL SELECT statement
;with cte as (
select
case when days between 0 and 3 then '0-3' else '4-7' end as day_range,
case
when days between 0 and 3 then
case when count >= 8 then 1 else 0 end
else
case when count >= 20 then 1 else 0 end
end as above_threshold
from
DayCount
)
select
day_range,
count(*) total_count,
sum(above_threshold) above_threshold_count
from cte
group by day_range

SQL - How to count records for each status in one line per day?

I have a table Sales
Sales
--------
id
FormUpdated
TrackingStatus
There are several status e.g. Complete, Incomplete, SaveforLater, ViewRates etc.
I want to have my results in this form for the last 8 days(including today).
Expected Result:
Date Part of FormUpdated, Day of Week, Counts of ViewRates, Counts of Sales(complete), Counts of SaveForLater
--------------------------------------
2015-05-19 Tuesday 3 1 21
2015-05-18 Monday 12 5 10
2015-05-17 Sunday 6 1 8
2015-05-16 Saturday 5 3 7
2015-05-15 Friday 67 5 32
2015-05-14 Thursday 17 0 5
2015-05-13 Wednesday 22 0 9
2015-05-12 Tuesday 19 2 6
Here is my sql query:
select datename(dw, FormUpdated), count(ID), TrackingStatus
from Sales
where FormUpdated <= GETDATE()
AND FormUpdated >= GetDate() - 8
group by datename(dw, FormUpdated), TrackingStatus
order by datename(dw, FormUpdated) desc
I do not know how to make the next step.
Update
I forgot to mention, I only need the Date part of the FormUpdated, not all parts.
You can use SUM(CASE WHEN TrackingStatus = 'SomeTrackingStatus' THEN 1 ELSE 0 END)) to get the status count for each tracking status in individual column. Something like this. SQL Fiddle
select
CONVERT(DATE,FormUpdated) FormUpdated,
DATENAME(dw, CONVERT(DATE,FormUpdated)),
SUM(CASE WHEN TrackingStatus = 'ViewRates' THEN 1 ELSE 0 END) c_ViewRates,
SUM(CASE WHEN TrackingStatus = 'Complete' THEN 1 ELSE 0 END) c_Complete,
SUM(CASE WHEN TrackingStatus = 'SaveforLater' THEN 1 ELSE 0 END) c_SaveforLater
from Sales
where FormUpdated <= GETDATE()
AND FormUpdated >= DATEADD(D,-8,GetDate())
group by CONVERT(DATE,FormUpdated)
order by CONVERT(DATE,FormUpdated) desc
You can also use a PIVOT to achieve this result - you'll just need to complete the list of TrackingStatus names in both the SELECT and the FOR, and no GROUP BY required:
WITH DatesOnly AS
(
SELECT Id, CAST(FormUpdated AS DATE) AS DateOnly, DATENAME(dw, FormUpdated) AS DayOfWeek, TrackingStatus
FROM Sales
)
SELECT DateOnly, DayOfWeek,
-- List of Pivoted Columns
[Complete],[Incomplete], [ViewRates], [SaveforLater]
FROM DatesOnly
PIVOT
(
COUNT(Id)
-- List of Pivoted columns
FOR TrackingStatus IN([Complete],[Incomplete], [ViewRates], [SaveforLater])
) pvt
WHERE DateOnly <= GETDATE() AND DateOnly >= GetDate() - 8
ORDER BY DateOnly DESC
SqlFiddle
Also, I think your ORDER BY is wrong - it should just be the Date, not day of week.

How to show different dates data (from the same table) as columns in Oracle

I'm sorry if the title wasn't too clear, but the following explanation will be more accurate.
I have the following view:
DATE USER CONDITION
20140101 1 A
20140101 2 B
20140101 3 C
20140108 1 C
20140108 3 B
20140108 2 C
What I need to do is present how many users where in all conditions this week and 7 days before today.
Output should be like this:
Condition Today Last_Week (Today-7)
A 0 1
B 1 1
C 2 1
How can I do this in Oracle? I will need to do this for 4 weeks so itll be Today-7,14-21.
I've tried this with group by but I get the "week2" as rows. Then I've tried something like Select conditions, (select count(users) from MyView where DATE='Today') FROM MyView(looking at something thats actually working) but it doesnt work for me.
Achieved this with a little modification of the accepted answer:
select condition,
count(case when to_date(xdate) = to_date(sysdate) then 1 end) to_day,
count(case when to_date(xdate) = to_date(sysdate-7) then 1 end) last_7_days
from my_table
group by condition
select condition, count(case when to_date(xdate) = to_date(sysdate) then 1 end) to_day,
count(case when to_date(xdate) < to_date(sysdate) then 1 end) last_7_days
from my_table
where to_date(xdate) >= to_date(sysdate) - 7
group by condition
select condition
, sum
( case
when date between trunc(sysdate) - 7 and trunc(sysdate) - 1
then 1
else 0
end
)
last_week
, sum
( case
when date between trunc(sysdate) and trunc(sysdate + 1)
then 1
else 0
end
)
this_week
from table
group
by condition
By using the conditional count (as a sum) and grouping on condition you can filter out all desired dates. Note that using trunc will cause to use the begin of the day.