How to retrieve Closest date from another table dynamically MySQL - mysql

I have two tables:
INFO table
ID LockDate Investor
157 10/15/2018 TEST1
VF1 09/02/2018 TEST2
LO2 05/01/2018 TEST3
09K 03/03/2012 TEST4
098 05/01/2012 TEST5
099 09/09/2012 TEST6
2YT 08/25/2012 TEST7
NUMBERS table
Dates Amount
10/10/2018 25.10
08/31/2018 200.15
05/10/2018 15.251
03/03/2012 10.10
05/10/2012 15.251
08/31/2012 548.0
I want the query to select all the values in the INFO table and find the closest or equal date in the Numbers table and give me the Amount. So my results would be:
ID LockDate Investor Amount
157 10/15/2018 TEST1 25.10
VF1 09/02/2018 TEST2 200.15
LO2 05/01/2018 TEST3 15.251
09K 03/03/2012 TEST4 10.10
098 05/01/2012 TEST5 15.251
099 09/09/2012 TEST6 548.0
2YT 08/25/2012 TEST7 548.0
By closest I mean equal or closest one whether it is lesser or greater than lock date.
This is the query I'm using but it is just retrieving the greater or equal one which doesn't work at all for me since I have to do it dynamically...
SELECT I.* ,
N.Amount FROM
(
SELECT A.*, MIN(NUM.Dates) AS XDATE
FROM INFO A
INNER JOIN NUMBERS AS NUM
ON NUM.Dates >= A.LockDate
GROUP BY A.ID
)AS RES
INNER JOIN NUMBERS AS N
ON N.Dates = I.XDATE
I will appreciate any help.

You just need to find the absolute minimum value for LockDate minus Dates. This will give you the closest date; lesser or greater. Rest is easy.
SELECT info.*, numbers.*
FROM info
INNER JOIN (
SELECT ID, MIN(DATEDIFF(GREATEST(LockDate, Dates), LEAST(LockDate, Dates))) Delta
FROM info
CROSS JOIN numbers
GROUP BY ID
) g ON info.ID = g.ID
INNER JOIN numbers ON DATEDIFF(GREATEST(LockDate, Dates), LEAST(LockDate, Dates)) = g.Delta
SQL Fiddle

Not sure what is your definition of "closest".
Here is my approach to get dates<=LockDate
http://sqlfiddle.com/#!9/8eea46/8
SELECT i.*, n.amount
FROM info i
LEFT JOIN numbers n
ON i.LockDate >= n.dates
LEFT JOIN numbers n_all
ON i.LockDate >= n_all.dates
AND n_all.dates > n.dates
WHERE n_all.dates IS NULL
Note: expected result is different since the definition of "closest" kind changed.
PS
Q: Why do I think that is a good approach?
A: Because whenever we deal with the data related to the timeline usually we expect data to know what (state, events, results) was before the moment we have on the timeline but not what will happen in future. That mean 31/12/2017 line/record can have/collect data from any table/records before 31/12/2017 but none from 2018. This strategy helps to keep reports consistent. They less dependent on the date when we generate the report. if we generate report about Dec 2017 at 1st Jan 2018 it will output same result as if we generate same report on same period Dec 2017 but week or month later 10th Jan 2018 or 1st of Feb.

Related

How can I do a table join where the composite key is an access number and a date +/- 1 day

I am trying to do a table join where the composite key is an access number and a snapshot date, and the data of interest is Status. Here's what the simple join looks like:
SELECT A.Access_Num, B.Access_Num, A.SNAPSHOT_DATE, B.SNAPSHOT_DATE, B.Status
FROM A
INNER JOIN B
ON A.Access_Num = B.Access_Numb AND A.SNAPSHOT_DATE = B.SNAPSHOT_DATE
My obstacle is that the data of interest Status is not populated on the exact match for SNAPSHOT_DATE (20% of the time). Sometimes it varies by +/- 1 from the SNAPSHOT_DATE in table A. There's still a record match, but table B will just return NA.
I am trying to write a join case that examines if Status returns as NA, to look at a composite key from the previous day for Table_B, and a composite key from the next day to see if there's a valid value available (i.e., not NA).
In the table below, I would want the query to recognize that row 3 returns an NA, so then it looks at the previous or next day to find a valid value. It should pick up that row 4 has a non-NA value, and return that one.
Row A.Access_Num B.Access_Num A.SNAPSHOT_DATE B.SNAPSHOT_DATE B.STATUS
1 11 11 12-12-2018 12-12-2018 Y
2 11 11 12-13-2018 12-13-2018 Y
3 13 13 12-05-2018 12-05-2018 NA
4 13 13 12-06-2018 Y
You can use inequalities in the ON clause:
SELECT A.Access_Num, B.Access_Num, A.SNAPSHOT_DATE, B.SNAPSHOT_DATE, B.Status
FROM A INNER JOIN
B
ON A.Access_Num = B.Access_Numb AND
A.SNAPSHOT_DATE >= B.SNAPSHOT_DATE - INTERVAL 1 DAY AND
A.SNAPSHOT_DATE <= B.SNAPSHOT_DATE + INTERVAL 1 DAY ;

how to fetch all the houskeepers name & the sum of 1bed,2 bed & total_work_time at once from the selected date?

there are 2 table tbl_hk and tbl_hk_work:
tbl_hk:hk_id(pk), hk_name
tbl_hk_work:hk_work_id, hk_id(fk), hk_work_date, hk_work_1bed, hk_work_2bed, hk_work_time
Now the problem is I want to fetch all housekeepers name, the sum of 1bed, 2 bed and total work hours from the date that provided from the user
Right now I have the one query which is working great but it only fetches only 1 housekeeper data at a time.
select t2.hk_name, sum(hk_work_1bed), sum(hk_work_2bed), sum(hk_work_time_decimal)
from tbl_hk_work t1 inner join
tbl_hk t2
on t2.hk_id = t1.hk_id
where hk_work_date between '2019-10-01' and '2019-10-30' and t2.hk_id='1'
group by t2.hk_name"
This is the Data I'm getting it right now:
hk_name sum(hk_work_1bed) sum(hk_work_2bed) sum(hk_work_time_decimal)
Veronica 12 25 28.86
This is the Data what is what I expect:
hk_name sum(hk_work_1bed) sum(hk_work_2bed) sum(hk_work_time_decimal)
Veronica 12 25 28.86
Carmen 10 16 27.31
Sofia 08 11 20.46
Amanda 05 09 17.19
I think you just need to remove the extra filter in the where clause:
select t2.hk_name, sum(hk_work_1bed), sum(hk_work_2bed), sum(hk_work_time_decimal)
from tbl_hk_work t1 inner join
tbl_hk t2
on t2.hk_id = t1.hk_id
where hk_work_date between '2019-10-01' and '2019-10-30'
group by t2.hk_name;
That is, remove t2.hk_id = '1'.
I think the only issue is the "and t2.hk_id='1'" in the where clause.

Calculate running day difference in MySQL

I'd like tot calculate the difference in days from the current row, compared to the previous row. What I have now:
Here is my column is day difference
**Day_Diff**
351
363
363
But what I actually want:
**Day_Diff**
351
12
12
What query would I need to accomplish this?
This should do the work (if what you want is minimum in first row and then difference to the minimum, with table being the name of your table and day_diff the name of the column you named Day_diff):
See sqlfiddle :
SELECT
CASE WHEN t1.day_diff = t2.min_day_diff
THEN t1.day_diff
ELSE t1.day_diff - t2.min_day_diff
END
FROM mytable t1
LEFT JOIN (SELECT MIN(day_diff) AS min_day_diff FROM mytable) t2
ON True;

Mysql single column result to multiple column result

I have a problem with a MySQL query, the problem is I have the following table:
id, rep, val dates
1 rep1 200 06/01/2014
2 rep2 300 06/01/2014
3 rep3 400 06/01/2014
4 rep4 500 06/01/2014
5 rep5 100 06/01/2014
6 rep1 200 02/06/2014
7 rep2 300 02/06/2014
8 rep3 900 02/06/2014
9 rep4 700 02/06/2014
10 rep5 600 02/06/2014
and I want a result like this:
rep 01/06/2014 02/06/2014
rep1 200 200
rep2 300 300
rep3 400 900
rep4 500 700
rep5 100 600
thank you very much!
You seem to want the most recent row for each rep. Here is an approach that often performs well:
select t.*
from table t
where not exists (select 1
from table t2
where t2.repid = t.repid and
t2.id > t.id
);
This transforms the problem to: "Get me the rows in table t where there is no other row with the same repid and a larger id." That is the same logic as getting the last one, just convoluted a bit to help the database know what to do.
For performance reasons, an index on t(repid, id) is helpful.
You seem to want the val for each of the dates.
Assuming the dates you are interested in are fixed then you can do that as follows. For output date column you check of the row matches the date for that column. If so you use the value of val , if not you just use 0. Then you sum all the resulting values, grouping by rep. I have assumed a fixed format of date.
SELECT rep, SUM(IF(dates='2014/06/01'), val, 0) AS '2014/06/01', SUM(IF(dates='2014/06/02'), val, 0) AS '2014/06/02'
FROM sometable
GROUP BY rep
Or if you just wanted the highest val for each day
SELECT rep, MAX(IF(dates='2014/06/01'), val, 0) AS '2014/06/01', MAX(IF(dates='2014/06/02'), val, 0) AS '2014/06/02'
FROM sometable
GROUP BY rep
If the number of dates is variable then not really a direct way to do it (as the number of resulting columns would vary). It would be easiest to do this manly in your calling script based on the following, giving you one row per rep / possible date with a sum of the values of val for that rep / date combination:-
SELECT rep, sub0.dates, SUM(IF(sometable.dates=sub0.dates), val, 0)
FROM sometable
CROSS JOIN
(
SELECT DISTINCT dates
FROM sometable
) sub0
GROUP BY rep, sub0.dates

Finding Records with Specific dateTime Difference in MySQL

I have an audit Trail table where I store the records with time taken for each transaction
Ex:
DateTime ReferenceID Status
2012-08-29 18:54:22 abc
2012-08-29 18:54:28 abc Success
2012-08-29 18:54:32 abcd
2012-08-29 18:54:48 abcd Success
I want to find out all the records that took more than say 10 seconds.
My output should look like
ReferenceID TimeTaken
abcd 16
Thanks
Soni
You can do a self join on the table from the records with blank Status to the corresponding Success record and calculate the difference between them. This query is assuming you only have the two records for each ReferenceID, if there may be more you will have to do some further filtering.
select d1.ReferenceID,
TimeStampDiff(SECOND, d1.Dttm, d2.Dttm) TimeTaken
from data d1
left join data d2 on d2.ReferenceID = d1.ReferenceID
and d2.Status = 'Success'
where d1.Status = ''
and TimeStampDiff(SECOND, d1.Dttm, d2.Dttm) > 10
SQL Fiddle