MySQL distinct and left, right - mysql

I have a table with day column like this:
2011-04-28, 2011-04-29 ...
day count name surname
2011-04-28 8 titi tutu
2011-04-28 12 tutu toto
2011-04-27 2 tutu toto
2011-03-12 10 tutu toto
I can obtain distinct day but not only month and year.
select distinct(day) from Table where day between "2011-03-01" and "2011-04-28";
I want only distinct month and year.
Can you help me?
Thanks

select DISTINCT EXTRACT(YEAR_MONTH FROM `day`) as yearmonth
from Table
where day between '2011-03-01' and '2011-04-28';

DISTINCT may be applied only to the whole row in mysql. So, you need to extract what you need first from the date.
select distinct(EXTRACT YEAR_MONTH FROM `day`) from Table
where day between "2011-03-01" and "2011-04-28";

Related

Count id for each day in a month

I have a database in mysql for a hospital where the columns are: id, entry_date, exit_date (the last two columns are the hospital patient entry and exit).
I would like to count the number of patients on each day of a given month
The code to count the number of ids for a given day is relatively simple (as described), but the count for each day of an entire month i do not know how to do.
Day 2019-09-01: x patients
Day 2019-09-02: y patients
Day 2019-09-03: z patients
.
.
.
x + y + z + ... = total patients on each day for all days of september
SELECT Count(id) AS patientsday
FROM saps
WHERE entry_date <= '2019-05-02'
AND ( exit_date > '2019-05-02'
OR exit_date IS NULL )
AND hospital = 'X'
First, assuming every day there is at least one patient entering this hospital, I would write a temporary table containing all the possibles dates called all_dates.
Second, I would create a temporary table joining the table you have with all_dates. In this case, the idea is to duplicate the id. For each day the patient was inside the hospital you will have the id related to this day on your table. For example, before your table looked like this:
id entry_date exit_date
1 2019-01-01 2019-01-05
2 2019-01-03 2019-01-04
3 2019-01-10 2019-01-15
With the joined table, your table will look like this:
id possible_dates
1 2019-01-01
1 2019-01-02
1 2019-01-03
1 2019-01-04
1 2019-01-05
2 2019-01-03
2 2019-01-04
3 2019-01-10
3 2019-01-11
3 2019-01-12
3 2019-01-13
3 2019-01-14
3 2019-01-15
Finally, all you have to do is count how many ids you have per day.
Here is the full query for this solution:
WITH all_dates AS (
SELECT distinct entry_date as possible_dates
FROM your_table_name
),
patients_per_day AS (
SELECT id
, possible_dates
FROM all_dates ad
LEFT JOIN your_table_name di
ON ad.possible_dates BETWEEN di.entry_date AND di.exit_date
)
SELECT possible_dates, COUNT(ID)
FROM patients_per_day
GROUP BY 1
Another possible solution, following almost the same strategy, changing only the conditons of the join is the query bellow:
WITH all_dates AS (
SELECT distinct entry_date as possible_dates
FROM your_table_name
),
date_intervals AS (
SELECT id
, entry_date
, exit_date
, datediff(entry_date, exite_date) as date_diference
FROM your_table_name
),
patients_per_day AS (
SELECT id
, possible_dates
FROM all_dates ad
LEFT JOIN your_table_name di
ON datediff(ad.possible_dates,di.entry_date)<= di.date_diference
)
SELECT possible_dates, COUNT(ID)
FROM patients_per_day
GROUP BY 1
This will break it down for number of entries for all dates. You can modify the SELECT to add a specific month and/or year.
SELECT
CONCAT(YEAR, '-', MONTH, '-', DAY) AS THE_DATE,
ENTRIES
FROM (
SELECT
DATE_FORMAT(entry_date, '%m') AS MONTH,
DATE_FORMAT(entry_date, '%d') AS DAY,
DATE_FORMAT(entry_date, '%Y') AS YEAR,
COUNT(*) AS ENTRIES
FROM
saps
GROUP BY
MONTH,
DAY,
YEAR
) AS ENTRIES
ORDER BY
THE_DATE DESC

MYSQL , Count week wise and also show sum with empty dates

I have two tables
Table_1 : Routes_Day_plan
Date Status_Id
------------------------
2019-06-09 1
2019-06-10 2
2019-06-09 2
2019-06-11 3
2019-06-14 4
2019-06-14 6
2019-06-15 8
Table_2 : Codes
id code
-------
1 Leave
2 Half_leave
3 Holiday
4 Work
5 Full_Hours
Now my task is to count week wise from table 1 where code (from second table) = Leave,Half_leave,work and than also show the sum , and where date not found show 0 , i write this query it's return data but not empty dates can someone please help ,
My Query:
select COUNT(*) as available, DATE(date)
from Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
group by date
UNION ALL
SELECT COUNT(date), 'SUM' date
FROM Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
Result Something Like ,
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
2 2019-06-14
2 2019-06-15
17 SUM
I want like this
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
0 2019-06-13
2 2019-06-14
2 2019-06-15
17 SUM
Your best bet here would be to have a Date Dimension/Lookup table which contains pre-populated dates for the entire year. By joining your record table to this lookup, you essentially allocate your data to each date that actually exist (ex. 2019-06-13) and if your data is not found in the lookup, you will find a null in that field.
The Count function will count a null as a 0. Just make sure you group on the date field from your lookup table and not from your record table.
Make a table, a date dimension that contains all the dates value, from beginning to end. Like this:
Set EndDate = '2099-01-01';
Set RunDate = '1900-01-01';
WHILE RunDate <= EndDate DO
insert into dim_date
(`DATE`)
select
RunDate as DATE
;
Set RunDate = ADDDATE(RunDate,1);
END WHILE;
Create temporary table with dim_date left join Routes_Day_plan and set Status as 0 maybe for record that dont match. Use this temporary table then instead of Routes_Day_plan in your queries.

Check if instances have occurred minimum once, every year in a specific range

In MySQL I'm tasked with a big dataset, with data from 1970 to 2010.
I want to check for consistency: check if each instance occurs minimum one time per year. I took a snippet from 1970-1972 as example to demonstrate my problem.
input:
id year counts
-- ---- ---------
1 1970 1
1 1971 1
2 1970 3
2 1971 8
2 1972 1
3 1970 4
expected:
id 1970-1972
-- ----------
1 no
2 yes
3 no
I though about counting within the date range and then taking those out who had 3 counts: 1970, 1971, 1972. The following query doesn't force the check on each point in the range though.
select id, count(*)
from table1
WHERE (year BETWEEN '1970' AND '1972') AND `no_counts` >= 1
group by id
What to do?
You can use GROUP BY with CASE / inline if.
Using CASE. SQL Fiddle
select id,CASE WHEN COUNT(distinct year) = 3 THEN 'yes'ELSE 'No' END "1970-72"
from abc
WHERE year between 1970 and 1972
GROUP BY id
Using inline IF. SQL Fiddle
select id,IF( COUNT(distinct year) = 3,'yes','No') "1970-72"
from abc
WHERE year between 1970 and 1972
GROUP BY id
You can use a having clause with distinct count:
select `id`
from `table1`
where `year` between '1970' and '1972'
group by id
having count(distinct `year`) = 3
Do you expect this?
select id, count(*)
from table1
WHERE (year BETWEEN '1970' AND '1972')
group by id
having count(distinct year) = 3

SQL to return record counts in X intervals

I have a table like this:
id | created_on
1 2013-09-03 20:05:09
2 2013-09-05 17:03:13
...
How do I write a query to return a result of record counts that was created from Date X to Date Y in 7-day intervals?
So the result would look like this:
count | created_on
4 2013-09-17 00:00:00
2 2013-09-24 00:00:00
1 2013-09-31 00:00:00
10 2013-10-07 00:00:00
...
You can go to the beginning of the week by subtracting the day of the week. Here is one way to do that:
select date(created_on - interval dayofweek(created_on) day), count(*)
from t
group by date(created_on - interval dayofweek(created_on) day);
If this is not the day you want the week to start, then you can add an offset day.
Group by the date field, floored to the week:
SELECT
count(*),
YEARWEEK(created_on) as week
FROM
yourtable
GROUP BY week
This assumes that created_on is a type that can be interpreted as a date:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_yearweek
This will get you weekly groupings, but you may want to then convert that field (which will look like YYYYWW) back to something more readable.
You can try this
SELECT created_on, count( id ) AS count
FROM `test_table`
WHERE created_on
BETWEEN '2013-09-01'
AND '2013-10-10'
GROUP BY WEEK( created_on )

Rush Hour table for every day in a month MySQL

I'm trying to make a query to get rush hours for everyday on a specific month.
The table I have looks like this:
id idproduct created_at
1 021354684 2011-10-01 20:25:48
2 033546835 2011-10-01 20:30:15
3 055965654 2011-10-01 20:45:20
4 012975343 2011-10-02 14:03:36
5 021354684 2011-10-02 15:55:48
6 033546835 2011-10-02 16:30:15
7 055965654 2011-10-02 16:45:20
8 012975343 2011-10-02 18:53:36
9 021354684 2011-10-03 08:55:48
10 033546835 2011-10-03 09:30:15
11 055965654 2011-10-03 14:03:20
12 012975343 2011-10-03 14:03:36
What I try to get is something like this...:
day rush_hour number_of_rows
1 20:00 3
2 16:00 5
3 14:00 4
Is it possible to get a table like this? can you guys help me?
I made a mistake, sorry for this. The number of rows should be the total of items sold that day, not in that hour :( sorry.
http://sqlfiddle.com/#!2/5b87b/7
First, count every day's every hour's count (into a view, because we will use it twice below):
CREATE VIEW hours AS
SELECT
DATE( created_at ) AS d,
HOUR( created_at ) AS h,
COUNT(*) AS c
FROM item
GROUP BY DATE(created_at), HOUR(created_at);
Final query:
SELECT
hours.d AS `day`,
hours.h AS `rush_hour`,
hours.c AS `count`
-- get the max count for every day
FROM (
SELECT
d, -- the day
MAX(c) as c -- the count
FROM hours
GROUP BY d
) AS maxc
-- find the actual hour(s) with the max count for every day:
INNER JOIN hours ON hours.c = maxc.c
AND hours.d = maxc.d;
You're going to want to look at the MySQL Date Functions, they offer you some help with this
SELECT
day(created_at) as day,
hour(created_at) as rush_hour,
count(1) as num_rows
FROM item
GROUP BY
day(created_at), hour(created_at)
http://sqlfiddle.com/#!2/62a15/2/0
Try this:
SELECT dayofyear(created_at) as day, hour(created_at) as rush_hour, count(*) as number_of_rows
FROM table
GROUP BY dayofyear(created_at), hour(created_at);
Here it is without making a view:
SELECT ddd.day, eee.rush_hour, ddd.maxo
FROM
(select day, max(num_rows) as maxo from (
SELECT
day(created_at) as day,
hour(created_at) as rush_hour,
count(1) as num_rows
FROM item
GROUP BY
day(created_at), hour(created_at)
) as groupo group by day) as ddd
LEFT JOIN
(SELECT
day(created_at) as day,
hour(created_at) as rush_hour,
count(1) as num_rows
FROM item
GROUP BY
day(created_at), hour(created_at)
) as eee on ddd.day=eee.day and ddd.maxo=eee.num_rows
I could imagine it being formatted more nicely or having more relevant aliases, but there's just so much subselecting going on here.
And thanks SQLfiddlers for putting the data there.
And I think that if you have two hours tied for the highest number of whatever it is you are counting, they both will show up, so you'll get two (or more) records returned for that day of the month.