Split SQL column values and group by date and return single row - sql

I have SQL Server query , using this , I am splitting event id sum columns to two columns based on some condition. Query executed successfully, but the result is not desired. It's half useful. Please help me to get expected result. I want one row for both split columns instead two rows and empty spaces.
SQL Query:
select convert(date, paymenttime)) , SUM(case when eventid = 33 then 1 ELSE 0 END) AS column1,
SUM(case when eventid = 36 then 1 ELSE 0 END) AS column2
from tbltransMain_backup where
paymentime <= '20160731' and PaymentTime >= '20160701'
group by convert(date,paymenttime),event_id
order by convert(date,paymenttime)
Result view:
Expected Result:
2016-07-01 27 1
2016-07-02 28 2
2016-07-03 30 15

The query you posted (perhaps unknowingly) into your question should already give you the desired results:
SELECT CONVERT(DATE, paymenttime),
SUM(CASE WHEN event_id = 33 THEN 1 ELSE 0 END) AS column1,
SUM(CASE WHEN event_id = 36 THEN 1 ELSE 0 END) AS column2
FROM tbltransMain_backup
WHERE paymentime <= '20160731' AND
paymentime >= '20160701'
GROUP BY CONVERT(DATE, paymenttime)
ORDER BY CONVERT(DATE, paymenttime)
The reason you were getting two rows for every date is that your query had the following grouping:
GROUP BY CONVERT(DATE, paymenttime),
event_id
In other words, each date would have two groups, one for event_id = 33 and one for event_id = 36.

Related

Count average with multiple conditions

I'm trying to create a query which allows to categorize the average percentage for specific data per month.
Here's how my dataset presents itself:
Date
Name
Group
Percent
2022-01-21
name1
gr1
5.2
2022-01-22
name1
gr1
6.1
2022-01-26
name1
gr1
4.9
2022-02-01
name1
gr1
3.2
2022-02-03
name1
gr1
8.1
2022-01-22
name2
gr1
36.1
2022-01-25
name2
gr1
32.1
2022-02-10
name2
gr1
35.8
...
...
...
...
And here's what I want to obtain with my query (based on what I showed of the table):
Month
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
01
1
1
0
0
02
1
1
0
0
...
...
...
...
...
The result needs to:
Be ordered by month
Have the average use for each name counted and categorized
So far I know how to get the average of the Percent value per Name:
SELECT Name,
AVG(Percent)
from `table`
where Group = 'gr1'
group by Name
and how to count iterations of Percent in the categories created for the query:
SELECT EXTRACT(MONTH FROM Date) as Month,
COUNT(CASE WHEN Percent <= 25 AND Group = 'gr1' THEN Name END) `_25`,
COUNT(CASE WHEN Percent > 25 AND Percent <= 50 AND Group = 'gr1' THEN Name END) `_50`,
COUNT(CASE WHEN Percent > 50 AND Percent <= 75 AND Group = 'gr1' THEN Name END) `_75`,
COUNT(CASE WHEN Percent > 75 AND Percent <= 100 AND Group = 'gr1' THEN Name END) `_100`,
FROM `table`
GROUP BY Month
ORDER BY Month
but this counts all iterations of every name where I want the average of those values.
I've been struggling to figure out how to combine the two queries or to create a new one that answers my need.
I'm working with the BigQuery service from Google Cloud
This query produces the needed result, based on your example. So basically this combines your 2 queries using subquery, where the subquery is responsible to calculate AVG grouped by Name, Month and Group, and the outer query is for COUNT and "categorization"
SELECT
Month,
COUNT(CASE
WHEN avg <= 25 THEN Name
END) AS _25,
COUNT(CASE
WHEN avg > 25
AND avg <= 50 THEN Name
END) AS _50,
COUNT(CASE
WHEN avg > 50
AND avg <= 75 THEN Name
END) AS _75,
COUNT(CASE
WHEN avg > 75
AND avg <= 100 THEN Name
END) AS _100
FROM
(
SELECT
EXTRACT(MONTH from Date) AS Month,
Name,
AVG(Percent) AS avg
FROM
table1
GROUP BY Month, Name, Group
HAVING Group = 'gr1'
) AS namegr
GROUP BY Month
This is the result:
Month
_25
_50
_75
_100
1
1
1
0
0
2
1
1
0
0
See also Fiddle (BUT on MySql) - http://sqlfiddle.com/#!9/16c5882/9
You can use this query to Group By Month and each Name
SELECT CONCAT(EXTRACT(MONTH FROM Date), ', ', Name) AS DateAndName,
CASE
WHEN AVG(Percent) <= 25 THEN '1'
ELSE '0'
END AS '<=25%',
CASE
WHEN AVG(Percent) > 25 AND AVG(Percent) <= 50 THEN '1'
ELSE '0'
END AS '25<_<=50%',
CASE
WHEN AVG(Percent) > 50 AND AVG(Percent) <= 75 THEN '1'
ELSE '0'
END AS '50<_<=75%',
CASE
WHEN AVG(Percent) > 75 AND AVG(Percent) <= 100 THEN '1'
ELSE '0'
END AS '75<_<=100%'
from DataTable /*change to your table name*/
group by EXTRACT(MONTH FROM Date), Name
order by DateAndName
It gives the following result:
DateAndName
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
1, name1
1
0
0
0
1, name2
0
1
0
0
2, name1
1
0
0
0
2, name2
0
1
0
0

Sum all the repeat event based on dates, aggregate by 7 days ,30 days >30 days

I am trying to calculate repeat if there is a repeat event in 3,7,30 and >30 days.
In the image below the the yellow is the sql table,
the green is transformation needed, where I find out what is the first event for Event A and Event B. and then find out what is the gap between the first event of A and next events of A.
Finally I need to aggregate and achieve the blue table where data is aggregate for the unique events.
I have been trying to achieve this in SQL but I am stuck as I am not sure how to filter and loop.
Original data and Expected outcome image
DECLARE #reference_date DATE = '2022-08-02';
SELECT
Event,
MIN(Date) as First_date,
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date) BETWEEN 1 AND 2
THEN 1 ELSE 0 END) as "Within_3_Days",
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date) BETWEEN 1 AND 6
THEN 1 ELSE 0 END) as "Within_7_Days",
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date) BETWEEN 1 AND 29
THEN 1 ELSE 0 END) as "Within_30_Days",
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date)>=30
THEN 1 ELSE 0 END) as ">_30_Days"
FROM event e0
GROUP BY Event
output:
Event
First_date
Within_3_Days
Within_7_Days
Within_30_Days
>_30_Days
A
2022-08-01
0
1
2
1
B
2022-09-15
0
0
0
1
The #reference_date is used to reference the date needed to determine if a date is within x days.
DBFIDDLE
P.S. I use dates in the format YYYY-MM-DD, because that's the only way I am SURE about the ordering of the Day and the Month part.
EDIT:
When using the first date of an event to determine the 'within' columns, you can do:
SELECT
e0.Event,
MIN(e0.Date) as First_date,
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date) BETWEEN 1 AND 2
THEN 1 ELSE 0 END) as "Within_3_Days",
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date) BETWEEN 1 AND 6
THEN 1 ELSE 0 END) as "Within_7_Days",
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date) BETWEEN 1 AND 29
THEN 1 ELSE 0 END) as "Within_30_Days",
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date)>=30
THEN 1 ELSE 0 END) as ">_30_Days"
FROM event e0
INNER JOIN (SELECT Event,MIN(Date) as Date from event GROUP BY Event) e1 on e1.Event=e0.Event
GROUP BY e0.Event
see: DBFIDDLE2

How to join 3 records as 1 record base on a same date?

This are some sample queries I wrote:
SELECT
CAST(datecolumn AS DATE) AS DateColumn,
COUNT(*) AS count
FROM
dbo.myTableName
WHERE
status = 'stage1'
GROUP BY CAST(datecolumn AS DATE) ORDER BY DateColumn DESC;
SELECT
CAST(datecolumn AS DATE) AS DateColumn,
COUNT(*) AS count
FROM
dbo.myTableName
WHERE
status = 'stage2'
GROUP BY CAST(datecolumn AS DATE) ORDER BY DateColumn DESC;
This is the output from the 1st query:
DateColumn count
------------------
2022-05-26 23
2022-05-25 51
2022-05-24 39
2022-05-23 55
2022-05-22 27
2022-05-21 90
and this is the output from the 2nd query:
DateColumn count
-----------------
2022-05-26 31
2022-05-25 67
2022-05-24 38
2022-05-23 54
2022-05-22 28
I want to only have a single query that will output it like this
DateColumn stage1count stage2count
-----------------------------------
2022-05-26 23 31
2022-05-25 51 67
2022-05-24 39 38
2022-05-23 55 54
2022-05-22 27 28
Thanks for answer
Can you try this:
select cast(datecolumn as DATE) as DateColumn,
sum(case when status = 'stage1' then 1 else 0 end) as stage1count,
sum(case when status = 'stage2' then 1 else 0 end) as stage2count
from dbo.myTableName
where status in ('stage1', 'stage2')
group by cast(datecolumn as DATE)
order by DateColumn DESC
Another note: Most SQL systems treat datecolumn and DateColumn the same, so it is somewhat ambiguous which it is actually using in the group by and order by clauses. I think the order by is using the casted value in the select list, and the groupby might be using the base column (uncasted) but I'm not sure about that. If you want to avoid the ambiguity, you can use a delimited identifier "DateColumn" instead.
#hewszz, you mention that you also need this for the case where you have two tables. This might do the job if you have two tables:
select t1.DateColumn, stage1count, stage2count
from (select cast(datecolumn as DATE) as DateColumn,
count(*) as stage1count
from dbo.myTableName1
where status = 'stage1'
group by cast(datecolumn as DATE)) t1
full outer join
(select cast(datecolumn as DATE) as DateColumn,
count(*) as stage2count
from dbo.myTableName2
where status = 'stage2'
group by cast(datecolumn as DATE)) t2
on t1.DateColumn = t2.DateColumn
order by t1.DateColumn DESC
By grouping each table separately we make sure that DateColumn is unique on each side, so each row will join with at most one row from the other grouped query. By using a full outer join we make sure no rows get lost when we have only a stage1 or a stage2 record for a given day.

SQL COUNT column where value is greater than value

I have a basic select query that is looking at some sample data in my table. I am trying to get three pieces of information.
Total Samples (total records)
How many with a Score greater than or equal to 85
How many with a Score less than 85
Data:
ScoreID RecordID Score ErrorMarkedToQID ErrorActionID
1 2 30 Q00019 1
2 2 100 Q20039 3
3 3 30 Q10091 3
4 3 35 Q00019 5
6 4 5 Q10091 3
This is what I attempted:
DECLARE #startDate DATE = '2018/09/12', #endDate DATE = '2018/09/24'
SELECT COUNT(s.ScoreID) AS totalSamples,
COUNT(CASE WHEN s.Score >= 85 THEN 1 ELSE 0 END) AS Pass,
COUNT(CASE WHEN s.Score < 85 THEN 1 ELSE 0 END) AS Fail
FROM [SubmissionScores] AS s
JOIN Submission AS sub
ON sub.SubmissionID = s.RecordID
WHERE sub.DateSubmittedUTC BETWEEN #startDate AND #endDate
My current output is that all fields are outputting 5 which is the total number of records. So it seems like my CASE logic isn't correct.
Can this be done in a simple query like I am attempting?
DECLARE #startDate DATE = '2018/09/12', #endDate DATE = '2018/09/24'
SELECT COUNT(s.ScoreID) AS totalSamples,
COUNT(CASE WHEN s.Score >= 85 THEN 1 ELSE NULL END) AS Pass,
COUNT(CASE WHEN s.Score < 85 THEN 1 ELSE NULL END) AS Fail
FROM [SubmissionScores] AS s
JOIN Submission AS sub
ON sub.SubmissionID = s.RecordID
WHERE sub.DateSubmittedUTC BETWEEN #startDate AND #endDate
The Count() function will return the number of rows that match a specified criteria, but your Case() has a result for both match and no match, so it returns the same (total) number of rows in all case
with Case() 0 or 1 you can use sum() which will summarize the result of the case
DECLARE #startDate DATE = '2018/09/12', #endDate DATE = '2018/09/24'
SELECT COUNT(s.ScoreID) AS totalSamples,
SUM(CASE WHEN s.Score >= 85 THEN 1 ELSE 0 END) AS Pass,
SUM(CASE WHEN s.Score < 85 THEN 1 ELSE 0 END) AS Fail
FROM [SubmissionScores] AS s
JOIN Submission AS sub
ON sub.SubmissionID = s.RecordID
WHERE sub.DateSubmittedUTC BETWEEN #startDate AND #endDate

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.