how to write query to get the data based on month? - mysql

My Database table is::
attendence date admission number attendence
2013-10-2 LSTM-0008/2013-2014 present
2013-10-19 LSTM-0008/2013-2014 absent
2013-9-20 LSTM-0008/2013-2014 present
above one is my database table.
i want to display table like this based on database table:
MonthName totalWorkingDays Present absent
october 26 1 1
november 26 1 0
i wrote mysql query like this:
SELECT DISTINCT monthname(attendencedate)as monthname , COUNT (*) as totalworking days,
(SELECT COUNT(*) FROM lstms_attendence WHERE attendence='present' AND addmissionno='LSTM-0008/2013-2014') as present,
(SELECT COUNT(*) FROM lstms_attendence WHERE attendence='absent' AND addmissionno='LSTM-0008/2013-2014') as absent
FROM lstms_attendence
WHERE addmissionno='LSTM-0008/2013-2014'
GROUP BY attendencedate;
its not working for me any one give me suggestions.

Try this:
SELECT monthname(attendencedate) AS monthname,
COUNT(*) AS totalworking_days,
SUM(CASE WHEN attendence = 'present' THEN 1 ELSE 0 END) AS present,
SUM(CASE WHEN attendence = 'absent' THEN 1 ELSE 0 END AS absent
FROM lstms_attendence
WHERE addmissionno = 'LSTM-0008/2013-2014'
GROUP BY monthname(attendencedate);
It will SUM 1 for every row that has attendence = 'present' in the present column and 0 otherwise. The same for attendence = 'absent'

Related

Mysql Query sum and group by not showing a row with null values

I have this query:
SELECT Customer, SUM(SoldUnits) AS SoldUnits
FROM Uploads
WHERE Year = 2021
AND Week = 11
GROUP BY Customer;
And Returns me:
Customer
SoldUnits
CUSTOMER A
55
CUSTOMER B
32
CUSTOMER D
17
CUSTOMER C exist, but it doesn't have data for the week 11 and I want to show CUSTOMER C with 0 SoldUnits. How Can I do that?
Assuming your table does have all customers you want to appear in the report, you could do a conditional summation and remove the WHERE clause:
SELECT Customer,
SUM(CASE WHEN Year = 2021 AND Week = 11
THEN SoldUnits ELSE 0 END) AS SoldUnits
FROM Uploads
GROUP BY Customer;

Selecting multiple columns from two tables in which one column of a table has multiple where conditions and group them by two columns and order by one

I have two tables namely "appointment" and "skills_data".
Structure of appointment table is:
id_ap || ap_meet_date || id_skill || ap_status.
And the value of ap_status are complete, confirm, cancel and missed.
And the skills_data table contains two columns namely:
id_skill || skill
I want to get the count of total number of appointments for each of these conditions
ap_status = ('complete' and 'confirm'),
ap_status = 'cancel' and
ap_status = 'missed'
GROUP BY id_skill and year and
order by year DESC
I tried this query which only gives me count of one condition but I want to get other two based on group by and order by clauses as mentioned.
If there is no record(for example: zero appointments missed in 2018 for a skill) matching for certain conditions, then it should display the output value 0 for zero count.
Could someone please suggest me with a query whether I should implement multiple select query or CASE clause to achieve my expected results. I have lot of records in appointment table and want a efficient way to query my records. Thank you!
SELECT a.id_skill, YEAR(a.ap_meet_date) As year, s.skill,COUNT(*) as count_comp_conf
FROM appointment a,skills_data s WHERE a.id_skill=s.id_skill and a.ap_status IN ('complete', 'confirm')
GROUP BY `id_skill`, `year`
ORDER BY `YEAR` DESC
Output from my query:
id_skill | year | skill | count_comp_conf
-----------------------------------------
1 2018 A 20
2 2018 B 15
1 2019 A 10
2 2019 B 12
3 2019 C 10
My expected output should be like this:
id_skill | year | skill | count_comp_conf | count_cancel | count_missed
------------------------------------------------------------------------
1 2018 A 20 5 1
2 2018 B 15 8 0
1 2019 A 10 4 1
2 2019 B 12 0 5
3 2019 C 10 2 2
You can use conditional aggregation using case when expression
SELECT a.id_skill, YEAR(a.ap_meet_date) As year, s.skill,
COUNT(case when a.ap_status IN ('complete', 'confirm') then 1 end) as count_comp_conf,
COUNT(case when a.ap_status = 'cancel' then 1 end) as count_cancel,
COUNT(case when a.ap_status = 'missed' then 1 end) as count_missed
FROM appointment a inner join skills_data s on a.id_skill=s.id_skill
GROUP BY `id_skill`, `year`
ORDER BY `YEAR` DESC
SELECT a.id_skill,
YEAR(a.ap_meet_date) As year,
s.skill,
SUM(IF(a.ap_status IN ('complete', 'confirm'),1,0)) AS count_comp_conf,
SUM(IF(a.ap_status='cancel',1,0)) AS count_cancel,
SUM(IF(a.ap_status='missed',1,0)) AS count_missed
FROM appointment a,skills_data s WHERE a.id_skill=s.id_skill
GROUP BY `id_skill`, `year`
ORDER BY `YEAR` DESC;
Please try to use if condition along with sum.
With below query you will get output.
select id_skill ,
year ,
skill ,
count_comp_conf ,
count_cancel ,
count_missed ( select id_skill, year, skill, if ap_status ='Completed' then count_comp_conf+1, elseif ap_status ='cancelled' then count_cancel +1 else count_missed+1
from appointment a join skills_data s on (a.id_skill = s.id_skill) group by id_skill, year) group by id_skill,year
order by year desc;

Create view that shows how much a student a spent

I need to create a view like this:
STUDENT JANUARY FEBRUARY MARCH ........ DECEMBER
miki 10.23 23.23 0 0
Goku 10 0 0 0
I have a table studentMovement(id_studentmovement,id_student,month,year,cost,date) that represents every sigle cost for the student in this month and year. it contains the real cost that some students had done.
Another table is Month(id_month), that has all month id (January==1 February==2 etc).
Table Students(id_student,name)
Another view is Years(id_year), it contains some year.
I want to get for a year, for all students in the table student(also the student that don't have outputs) and for all month(if there is an output in this month the value is 0) , I want get the sum all cost. SO my view is this
CREATE
ALGORITHM = UNDEFINED DEFINER = "***" #"%" SQL SECURITY DEFINER VIEW "schema"."v_student_table" AS select
"s"."id_student" AS "id_student",
"s"."name" AS "name",
"m"."id_month" AS "id_month",
coalesce(sum("sm"."amount"),0) AS "amount",
coalesce(month("sm"."date"),"month"."id_month") AS "month",
coalesce(year("sm"."date"),"year"."id_year") AS "anno"
from
((("schema"."studentMovement" "sm"
left join "schema"."students" "s" on "s"."id_student"="sm"."id_student")
left join "schema"."month" "m" on "m"."id_month"="sm".id_month")
inner join "schema"."years" "y" on "y"."id_year"="sm".id_year")
group by
coalesce(year("sm"."date"),"year"."id_year"),
coalesce(month("sm"."date"),"month"."id_month"),
"s"."id_student",
"s"."name",
"m"."id_month"
The problem is if there isn't a cost for a month in a year, I need to put 0 like value but with this query it doesn't do this.
the problem is the studentMovement has the real outputs. in the example above Goku has only one cost that is in jenuary but the student goku is not present for FEBRUARY etc, Anyone can help me?
You seem to want something like this:
select year(sm.date) as year, s.id_student, s.name,
sum(amount) as year_amount,
sum(case when month(sm.date) = 1 then amount else 0 end) as january,
sum(case when month(sm.date) = 2 then amount else 0 end) as february,
. . .
sum(case when month(sm.date) = 12 then amount else 0 end) as december,
"m"."id_month" AS "id_month",
coalesce(sum("sm"."amount"),0) AS "amount",
from schema.students s join
schema.studentMovement sm
on s.d_student = sm.id_student
group by year(sm.date) as year, s.id_student, s.name;
The . . . is the logic for the remaining months.

Group Totals from Logs by Month

I have a log table that stores media requests by act_datetime, app_id, location_id, media_id and media_type_id. What I want is each resultset row to contain type totals for each month. For example, log records contain:
I tried using temp tables to extract records by app_id and grouping by month, but I get multiple rows for each total. I can use sub-queries, but how do I get a total row by type for each month?
Any help is greatly appreciated.
Thanks,
Brandon
EDIT
The follow code works combining shared ideas:
This query takes about 13 seconds parsing about 8.1 million rows. Is that acceptable? Lastly how do you display date as 2018-1 as one column? I'm getting errors when converting to string since the date is also used in the group and order by clauses.
I also want to try code construct sum( case when media_type_id = 1 then 1 else 0 end )... to see if get same results and speed.
Thanks for everyone's help!
Assuming this is SQL Server, and not MySQL:
SELECT DATEPART(MONTH, act_datetime) AS [Month],
COUNT(CASE WHEN app_id = 14 AND media_type_id = 1 AND location_id = 1 THEN act_datetime END) AS MP3_Messages_MO,
COUNT(CASE WHEN app_id = 14 AND media_type_id = 1 AND location_id = 2 THEN act_datetime END) AS MP3_Messages_FL,
COUNT(CASE WHEN app_id = 14 AND media_type_id = 3 AND location_id = 1 THEN act_datetime END) AS MP3_Messages_MO,
COUNT(CASE WHEN app_id = 14 AND media_type_id = 3 AND location_id = 2 THEN act_datetime END) AS MP3_Messages_FL,
COUNT(CASE WHEN app_id = 55 AND media_type_id = 1 THEN act_datetime END) AS MP3_Music,
COUNT(CASE WHEN app_id = 55 AND media_type_id = 9 THEN act_datetime END) AS ZIP_Music
FROM YourTable
GROUP BY DATEPART(MONTH, act_datetime);
Note you have included no logic for differing years, data for each Month will do a count irrespective of year.
This is also completely untested, due to lack of consumable data.

Is it possible to group by a few different date periods in mysql?

There is a table likes:
like_user_id | like_post_id | like_date
----------------------------------------
1 | 2 | 1399274149
5 | 2 | 1399271149
....
1 | 3 | 1399270129
I need to make one SELECT query and count records for specific like_post_id by grouping according periods for 1 day, 7 days, 1 month, 1 year.
The result must be like:
period | total
---------------
1_day | 2
7_days | 31
1_month | 87
1 year | 141
Is it possible?
Thank you.
I have a created a query for Oracle syntax please change it according to your db
select '1_Day' as period , count(*) as Total
from likes
where like_date>(sysdate-1)
union
select '7_days' , count(*)
from likes
where like_date>(sysdate-7)
union
select '1_month' , count(*)
from likes
where like_date>(sysdate-30)
union
select '1 year' , count(*)
from likes
where like_date>(sysdate-365)
here idea is to get single sub query for single period and apply the filter in where to match the filter.
This code shows how to build a cross-tab style query that you will likely need. This aggregates by like_post_id and you may want to put restrictions on it. Further, in terms of last month I don't know whether you mean month to date, last 30 days or last calendar month so I've left that to you.
SELECT
like_post_id,
-- cross-tab example, rinse and repeat as required
-- aside of date logic, the SUM(CASE logic is designed to be ANSI compliant but you could use IF instead of CASE
SUM(CASE WHEN FROM_UNIXTIME(like_date)>=DATE_SUB(CURRENT_DATE(), interval 1 day) THEN 1 ELSE 0 END) as 1_day,
...
FROM likes
-- to restrict the number of rows considered
WHERE FROM_UNIXTIME(like_date)>=DATE_SUB(CURRENT_DATE(), interval 1 year)
GROUP BY like_post_id
To be flexible, simply make a table time_intervals which holds from_length and to_length in seconds:
CREATE TABLE time_intervals
( id int(11) not null auto_increment primary key,
name varchar(255),
from_seconds int,
to_seconds int
);
The select is then quite straight:
select like_post_id, ti.name as interval, count(*) as cnt_likes
from time_intervals ti
left /* or inner */ join likes on likes.like_post_id = 175
and likes.like_date between unix_timestamp(now()) - ti.to_seconds and unix_timestamp(now()) + ti.from_seconds
group by ti.id
With left join you get always all intervals (even when holes exist), with inner join only the intervals which exist.
So you change only table time_intervals and can get what you want. The "175" stands for the post you want, and of course you can change to where ... in () if you want.
Here is an alternative using CROSS JOIN. First, the time difference is calculated using the TIMESTAMPDIFF function and the appropriate parameter (DAY/WEEK/MONTH/YEAR). Then, if the counts are equal to 1, then the value is added up. Finally, the CROSS JOIN is made with an inline view containing the names of the periods.
SELECT
periods.period,
CASE periods.period
WHEN '1_day' THEN totals.1_day
WHEN '7_days' THEN totals.7_days
WHEN '1_month' THEN totals.1_month
WHEN '1_year' THEN totals.1_year
END total
FROM
(
SELECT
SUM(CASE days WHEN 2 THEN 1 ELSE 0 END) 1_day,
SUM(CASE weeks WHEN 1 THEN 1 ELSE 0 END) 7_days,
SUM(CASE months WHEN 1 THEN 1 ELSE 0 END) 1_month,
SUM(CASE years WHEN 1 THEN 1 ELSE 0 END) 1_year
FROM
(
SELECT
TIMESTAMPDIFF(YEAR, FROM_UNIXTIME(like_date), NOW()) years,
TIMESTAMPDIFF(MONTH, FROM_UNIXTIME(like_date), NOW()) months,
TIMESTAMPDIFF(WEEK, FROM_UNIXTIME(like_date), NOW()) weeks,
TIMESTAMPDIFF(DAY, FROM_UNIXTIME(like_date), NOW()) days
FROM likes
) counts
) totals
CROSS JOIN
(
SELECT
'1_day' period
UNION ALL
SELECT
'7_days'
UNION ALL
SELECT
'1_month'
UNION ALL
SELECT
'1_year'
) periods