Update columns based on calculation - mysql

My table looks like this:
id entry_date
1 21/12/2020 15:00
1 21/12/2020 17:00
1 21/12/2020 19:00
2 24/12/2020 00:00
2 24/12/2020 12:00
I have a list of id's connected to datestamps. I can manage to calculate the difference between their latest and first entry as follows:
SELECT id, TIMESTAMPDIFF(hour, MIN(entry_date), MAX(entry_date))
FROM mytable
GROUP BY id;
However, I am unsure how I can update my table to reflect these calculations. What I want is the following:
id entry_date time_difference
1 21/12/2020 15:00 4
1 21/12/2020 17:00 4
1 21/12/2020 19:00 4
2 24/12/2020 00:00 12
2 24/12/2020 12:00 12

In MySQL, you can self-join:
update mytable t
inner join (
select id,
timestampdiff(hour, min(entry_date), max(entry_date)) as time_difference
from mytable
group by id
) t1 on t1.id = t.id
set t.time_difference = t1.time_difference
I would not necessarily recommend storing this derived information, because it is hard to keep it up to date. Instead, you can create a view. If you are running MySQL 8.0:
create view myview as
select t.*,
timestampdiff(
hour,
min(entry_date) over(partition by id),
max(entry_date) over(partition by id)
) as timedifference
from mytable t

You can use a join in the update:
update mytable t join
(SELECT id, TIMESTAMPDIFF(hour, MIN(entry_date), MAX(entry_date)) as diff
FROM mytable
GROUP BY id
) tt
using (id)
set t.time_difference = tt.diff;

Related

SQL: Select the last record for each day given datetime

I have a table of stock data (the db is MySQL):
trade_time price
2013-01-02 09:43:00 515.61
2013-01-03 09:39:00 525.90
2013-01-03 11:38:00 539.44
2013-01-03 13:22:00 509.16
2013-01-04 09:47:00 507.40
2013-01-04 14:33:00 517.45
2013-01-07 09:33:00 550.42
2013-01-07 13:13:00 524.85
2013-01-07 14:51:00 536.44
I would like to return the last traded price for each day
trade_date price
2013-01-02 515.61
2013-01-03 509.16
2013-01-04 517.45
2013-01-07 536.44
What makes this question different from other "selecting the latest record based on datetime" questions on this site is that input is in datetime but output is in date. Let me know this question has already been answered.
You may join to a subquery which finds the maximum datetime for each date.
SELECT t1.trade_time, t1.price
FROM yourTable t1
INNER JOIN
(
SELECT DATE(trade_time) AS trade_date, MAX(trade_time) AS max_trade_time
FROM yourTable
GROUP BY DATE(trade_time)
) t2
ON t2.trade_date = DATE(t1.trade_time) AND
t2.max_trade_time = t1.trade_time
ORDER BY
t1.trade_time;
Demo
Here is an efficient solution using window function ROW_NUMBER() over a type cast of the timestamp column to date:
select trade_date, price
from (
select trade_date, price, row_number() over
(partition by date(trade_date)
order by trade_date desc) as row_num
from stock) as subquery
where row_num = 1
order by trade_date
You can use a correlated subquery:
select t.*
from t
where t.trade_date = (select max(t2.trade_date)
from t t2
where date(t2.trade_date) = date(t.trade_date)
);
I understand this is an implementation in MY-SQL, but I tried in SQL-Server just for fun
and this query gives the requisite output:
SELECT CAST(SQ.TT AS DATE) AS TRADED_DATE, PRICE
FROM STOCK
INNER JOIN
(SELECT MAX(TRADE_TIME) AS TT
FROM STOCK
GROUP BY CAST(TRADE_TIME AS DATE)) SQ
ON SQ.TT = TRADE_TIME
Output as
TRADED_DATE PRICE
----------- ---------------------------------------
2013-01-02 515.61
2013-01-03 509.16
2013-01-04 517.45
2013-01-07 536.44
(4 rows affected)

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

Create date_from and date_to columns in mysql

I've got a table named 'T1' which I want to transpose and have date_from and date_to columns. The table itself has the data of who is a manager of a particular company. So I want to know since when to when a user was responsible for a company. I can do it easily in BigQuery with the following query but I'm struggling to do the same in MySQL.
WITH T1 AS ( SELECT 9 as rating, 'company1' as cid, 100 as user, '2017-08-20' AS created UNION ALL
SELECT 9 as rating, 'company1' as cid, 101 as user, '2017-08-22' AS created UNION ALL
SELECT 10 as rating, 'company1' as cid, 101 as user, '2017-08-21' AS created
)
SELECT cid, rating, user, CAST(created as DATE) as date_from,
CAST(COALESCE(MIN(CAST(created as DATE)) OVER(PARTITION BY cid, rating ORDER BY CAST(created as DATE) DESC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING),
DATE_ADD(current_date(), INTERVAL 1 DAY)) as DATE) AS date_to
FROM T1
The original table format:
rating cid user created
9 company1 100 2017-08-20
9 company1 101 2017-08-22
10 company1 101 2017-08-21
The final table should have the following format:
cid rating user date_from date_to
1 company1 9 101 2017-08-22 2018-02-24
2 company1 9 100 2017-08-20 2017-08-22
3 company1 10 101 2017-08-21 2018-02-24
Thank you!
You really need lead(), which is not available in MySQL (and which would make the BigQuery query simpler). One method uses a correlated subquery:
select t1.*, t1.created as date_from,
(select min(tt1.created)
from t1 tt1
where tt1.cid = t1.cid and tt1.created > t1.created
) as date_to
from t1;

Count number of rows of a column SQL

How to make the count of rows of a specific column in a table:
ReportID Reader ReadTime
100 A 12:00
100 A 12:10
100 A 12:15
200 B 15:00
200 B 15:00
200 B 15:05
Expected OutCome:
ReportID Reader ReadTime Count Read by Reader and Time
100 A 12:00 1
100 A 12:10 1
100 A 12:15 1
200 B 15:00 2
200 B 15:00 2
200 B 15:05 1
You want to count without group by, this is done via over (so-called window functions)
COUNT(*) OVER (PARTITION BY ReportID, Reader, ReadTime)
Whether this works in your DB or not, I cannot tell (because you didn't tag).
However, here are some slides that explain window functions and also show which DBs support them.
https://www.slideshare.net/MarkusWinand/modern-sql/75
If your dbms doesn't support window functions, a simple correlated sub-query will do the trick:
select t1.ReportID, t1.Reader, t1.ReadTime,
(select count(*) from tablename t2
where t2.ReportID = t1.ReportID
and t2.Reader = t1.Reader
and t2.ReadTime = t1.ReadTime) as cnt
from tablename t1
Or, join with a derived table:
select t1.ReportID, t1.Reader, t1.ReadTime, t2.cnt
from tablename t1
join (select ReportID, Reader, ReadTime, count(*) as cnt
from tablename
group by ReportID, Reader, ReadTime) t2
on t2.ReportID = t1.ReportID
and t2.Reader = t1.Reader
and t2.ReadTime = t1.ReadTime
You could use :
Select reportid,reader,readtime,count(*) over (partition by reportid,reader,readtime) from table;
Simple do count(*) over()...
SELECT *, COUNT(*) OVER (PARTITION BY Reader, ReadTime) [Count] FROM <table>
Try
Select reportid,reader,readtime,count(*) from table1
group by Reader,readtime
http://sqlfiddle.com/#!9/2b938d/12

how to get latest record or record with max corresponding date of all distinct values in a column in mysql?

For Example, I have table like this:
Date | Id | Total
-----------------------
2014-01-08 1 15
2014-01-09 3 24
2014-02-04 3 24
2014-03-15 1 15
2015-01-03 1 20
2015-02-24 2 10
2015-03-02 2 16
2015-03-03 5 28
2015-03-09 5 28
I want the output to be:
Date | Id | Total
---------------------
2015-01-03 1 20
2014-02-04 3 24
2015-03-02 2 16
2015-03-09 5 28
Here the distinct values are Id. I need latest Total for each Id.
You can use left join as
select
t1.* from table_name t1
left join table_name t2
on t1.Id = t2.Id and t1.Date >t2.Date
where t2.Id is null
http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html
You can also use Max() in sql:
SELECT date, id, total
FROM table as a WHERE date = (SELECT MAX(date)
FROM table as b
WHERE a.id = b.id
)
You can do it as below
SELECT *
FROM YourTable D
WHERE date = (SELECT MAX(date) FROM YourTable WHERE ID = D.ID)
Another way is by using INNER JOIN
Find the latest date per ID then join result back to the table to get the value
select A.ID,A.Date,A.value
from yourtable A
INNER JOIN
(
select MAX(date) as Date,ID
from yourtable
group by ID
) B
ON A.ID =B.ID and A.Date = B.Date
The other answers didn't work for me. I found the following code, which worked great for me:
SELECT * FROM TABLE WHERE DATE IN (SELECT MAX(DATE) FROM TABLE)
I am using SSMS 2014, SQLServer