Getting first week of date in mysql - mysql

I have a lot of table and i need to get the gross income of a movie, now my problem is i don't know how to get the sum of first week only of a movie.
This is what i need.
+-------------------------------------------+
| title | Week one | Week one |
| | (Wed-Sun) | (Mon-Tue) |
+-------------------------------------------+
| title 1 | 50000 | 10000 |
+-------------------------------------------+
If the starting show of a movie is wed then i should make 3 column, first column is title, second column is the wed-sun and third is mon-tue.
Is this possible to query like select movie, sum(wed-sun), sum(mon-tue)
Thanks in advance

This is my answer based on how I understand your question.
SELECT movie, sum(wed-sun), sum(mon-tue) CONVERT(date, getdate()) as day
FROM thetable
WHERE thedate(BETWEEN first AND last)
GROUP BY day

You can user DAYOFWEEK() if you are using date type for that. See http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_dayofweek
For week days from mon-tue
SUM(CASE WHEN DAYOFWEEK(DATE)=2 THEN 1 WHEN DAYOFWEEK(DATE)=3 THEN 1 ELSE 0 END)
For week days from wed-sun
SUM(CASE WHEN DAYOFWEEK(DATE)=4 THEN 1 WHEN DAYOFWEEK(DATE)=5 THEN 1 WHEN DAYOFWEEK(DATE)=6 THEN 1 WHEN DAYOFWEEK(DATE)=7 THEN 1 WHEN DAYOFWEEK(DATE)=1 THEN 1 ELSE 0 END)

If you use WEEKDAY instead of DAYOFWEEK you can shorten the case statements:
SELECT
movie_id,
title,
SUM(CASE WHEN WEEKDAY(date_field) < 2 THEN field_to_sum ELSE 0 END) `mon-tue`,
SUM(CASE WHEN WEEKDAY(date_field) > 1 THEN field_to_sum ELSE 0 END) `wed-sun`
FROM
movies
/* optional WHERE */
GROUP_BY movie_id

Obviously you want WEEKDAY FUNCTION, it returns the weekday index starting from 0-Monday.
Assume you have table Movies with title and starting_show_date columns, and value_table with action_date and amount columns.
You can sum amount by splitting amounts to two parts like this:
select
movies.title,
sum(case when value_table.action_date
< dateadd(movies.starting_show_date , interval 7 -WEEKDAY(movies.starting_show_date) day)
then value_table.amount else 0 end) as FirstWeek,
sum(case when value_table.action_date
>= dateadd(movies.starting_show_date , interval 7 -WEEKDAY(movies.starting_show_date) day)
then value_table.amount else 0 end) as OtherWeeks
from
movies
inner join
value_table
on
movies.id = value_table.movie_id
group by
movies.title

Related

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;

Count and Percentage of records in range of values

I have a table with columns
TicketID - ID of the ticket
AssignedTo - UserID of person to whom ticket is assigned
CreatedTime - Time when Ticket is received
HandleTime - Time when Ticket is picked up for handling
FinishTime - Time when Ticket is finished handling
I need to retrieve the following data grouped to individual AssignedTo ID:
AssignedTo
Picking Rate in the following ranges(both % and count)
<1 minutes
1-2 minutes
2-5 minutes
Closing Rate in the following ranges(both % and count)
same ranges as above
Total Tickets
I have come up with a initial query as
SELECT
User,
sum(case when PickupTime <=1 then 1 else 0 end) as range1,
sum(case when PickupTime <=2 then 1 else 0 end) as range2,
...
FROM
(SELECT
((HandleTime - CreatedTime)/60000) as PickupTime,
((FinishTime - CreatedTime)/60000) as CompletedTime,
AssignedTo as User
FROM
TicketTable
)T
GROUP BY
User
Here I am able to get only the Pickup range counts.I still need Pickup range percentages and also Closing range counts and percentages.How do I get them?
EDIT:
Let us consider a sample dataset and only two ranges <=1 and >1 and also consider time as minutes directly here whereas in original table its stored as timestamp.
TicketID | AssignedTo | CreatedTime | HandleTime | FinishTime
1 001 2 3 3
2 001 4 6 8
3 002 1 2 3
In the above table User 001 is assigned a total of 2 tickets and User 002 is assigned a total of 1 ticket.
The PickupTime and CompletedTime for the tickets are
TicketID | PickupTime | CompletedTime
1 1 1
2 2 4
3 1 2
So for User-001 out of the two tickets assigned to him, he has picked 1 ticket within 1 minute range and 1 greater than 1 minute range.So percentage of tickets within 1 minute range is 50% and over 1 minute range is 50% for him.Same applies with regards to CompletedTime and also to the User-002 too.
So the final result what i want is.
AssignedTo | Pickup_range1_count | Pickup_range2_count | Pickup_range1_percentage |
001 1 1 0.5
002 1 0 1
Pickup_range2_percentage | Complete_range1_count | Complete_range2_count |
0.5 1 1
0 0 1
Complete_range1_percentage | Complete_range2_percentage
0.5 0.5
0 1
According to your example you already almost got it. All you need is the ratio of the individual sums and the total sum (or the count would have done it to). Something like
SELECT AssignedTo,
sum(1) AllCount,
sum(CASE
WHEN HandleTime - CreatedTime <= 1
THEN 1
ELSE 0
END) Range1PickupCount,
sum(CASE
WHEN HandleTime - CreatedTime > 1
THEN 1
ELSE 0
END) Range2PickupCount,
...
sum(CASE
WHEN HandleTime - CreatedTime <= 1
THEN 1
ELSE 0
END) / sum(1) * 100 Range1PickupPercentage,
sum(CASE
WHEN HandleTime - CreatedTime > 1
THEN 1
ELSE 0
END) / sum(1) * 100 Range2PickupPercentage,
...
FROM Tickets
GROUP BY AssignedTo;
should be a valid demonstration and something you can continue upon.
(Disclaimer: Not tested at all, as no DDL and DML was provided.)

MySQL duplicate entries search with selective date criteria

Having trouble wrapping my head around having an efficient "duplicate entries" select in a single query.
In the below example, duplicate StockNo can exist spanning multiple Date. I want to search StockNo for duplicate entries, and if at least 1 StockNo record is found within the Date current YEAR-MONTH, then I also need to select its partner that could exist in any other YEAR-MONTH. Is this possible?
Example Query:
SELECT * FROM `sales`
WHERE `StockNo` IN
(SELECT `StockNo` FROM `sales` GROUP BY `StockNo` HAVING COUNT(*) > 1)
AND `Date` LIKE '2016-11-%'
ORDER BY `StockNo`, `TransactionID`;
Example Data:
ID | StockNo | Date
1 | 1 | 2016-11-01
2 | 1 | 2016-11-10
3 | 2 | 2016-11-05
4 | 2 | 2016-10-29
5 | 3 | 2016-10-25
6 | 3 | 2016-10-15
With my example query and data, I have 3 pairs of duplicate entries. It's pretty obvious that I will only return 3 records (ID's 1, 2 & 3) due to AND Date LIKE '2016-11-%', however I need to return ID's 1, 2, 3, 4. I want to ignore ID's 5 & 6 because neither of them fall within the current month.
Hope that makes sense. Thanks for any help you can provide.
SELECT StockNo
FROM sales
GROUP BY StockNo
HAVING SUM(CASE WHEN DATE_FORMAT(Date, '%Y-%m') = '2016-11' THEN 1 ELSE 0 END) > 0
If you also want to retrieve the full records for those matching stock numbers in the above query, you can just add a join:
SELECT s1.*
FROM sales s1
INNER JOIN
(
SELECT StockNo
FROM sales
GROUP BY StockNo
HAVING SUM(CASE WHEN DATE_FORMAT(Date, '%Y-%m') = '2016-11' THEN 1 ELSE 0 END) > 0
) s2
ON s1.StockNo = s2.StockNo
Demo here:
SQLFiddle
Thank you very much Tim for pointing me in the right direction. Your answer was close but it still only returned records from the current month and in the end I used the following query:
SELECT s1.* FROM `sales` s1
INNER JOIN
(
SELECT * FROM `sales` GROUP BY `StockNo` HAVING COUNT(`StockNo`) > 1
AND SUM(CASE WHEN DATE_FORMAT(`Date`, '%Y-%m')='2016-11' THEN 1 ELSE 0 END) > 0
) s2
ON s1.StockNo=s2.StockNo
This one had been eluding me for some time.

MySQL - get COUNT depends on the value

How can I get the COUNT() of the specific field depends on the value of the field? For example I have the field typeOfAssistance , in the query below I got the total numbers of the typeOfAssistance but I have different values in it which is financial medical and burial, How can I add custom column that will divide the total value depends on the value?
SELECT date,COUNT(*) AS num
FROM requests
WHERE date BETWEEN DATE_ADD(CURDATE(),INTERVAL -20 DAY) AND CURDATE()
GROUP BY date
desired output:
date | financial | burial | medical | total
2014-04-25 | 1 | 2 | 3 | 6
Thanks. Sorry for the explanation. :)
Typically for something like that I would use SUM rather than COUNT for the item breakdowns.
Something like
SELECT date,
SUM(CASE WHEN typeOfAssistance = 'financial' THEN 1 ELSE 0 END) AS financial,
SUM(CASE WHEN typeOfAssistance = 'burial' THEN 1 ELSE 0 END) AS burial,
SUM(CASE WHEN typeOfAssistance = 'medical' THEN 1 ELSE 0 END) AS medical,
COUNT(1) AS Total
FROM requests
GROUP BY date

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