Select column from another table based on matching condition - mysql

I have two tables that have time-series data in the following form. I want to select all of the columns of TABLE1 and an additional column Limit_At_Time which is the value of the Limit column of TABLE2 for the row which has the most recent Date (relative to TABLE1.Date)
TABLE1:
Customer_ID Date Amount
1 01/01/2019 5
2 02/05/2019 15
TABLE2:
Customer_ID Date Limit
1 12/05/2018 10
1 12/25/2018 20
2 01/05/2019 30
2 03/08/2019 50
Result:
Customer_ID Date Amount Limit_At_Time
1 01/01/2019 5 20
2 02/05/2019 15 30
The closest I have gotten is selecting a previous_date column with this query:
SELECT *,
(SELECT MAX(Date) FROM TABLE2 t2
WHERE t2.Date < t1.Date
AND t2.Customer_ID = t1.Customer_ID)
as previous_date
FROM TABLE1 AS t1
This gets me the date of the event from TABLE2 that I am interested in for each TABLE1 row, but I need to extract the Limit column value of the row that contains that previous_date.
How can I achieve the result that I want?

I would just use a correlated subquery:
select t1.*,
(select t2.limit
from table2 t2
where t2.date <= t1.date
order by t2.date desc
limit 1
) as Limit_At_Time
from table1 t1;
Usually in these types of problems, the comparison is <= rather than <, so I used that. Of course, the exact equivalent to your query is <.

You can use your subquery as a JOIN condition between table1 and table2 which will then allow you to get the Limit value from table2:
SELECT t1.Customer_ID, t1.Date, t1.Amount, t2.Limit
FROM table1 t1
JOIN table2 t2 ON t2.Customer_ID = t1.Customer_ID
AND t2.Date = (SELECT MAX(Date) FROM table2 t2b
WHERE t2b.Date < t1.Date
AND t2b.Customer_ID = t1.Customer_ID)
Output:
Customer_ID Date Amount Limit
1 2019-01-01 5 20
2 2019-02-05 15 30
Demo on dbfiddle

Related

How to get previous last row in MySQL

I have below mentioned two tables.
Table1
ID ref_id
O-1 rt-1-r
O-2 rx-2-e
Table2
ref_id seq value
rt-1-r 1 10
rt-1-r 2 15
rt-1-r 3 0
rt-1-r 4 18
rx-2-e 12 1
rx-2-e 13 13
rx-2-e 14 21
Required Output
ID Value
O-1 0
O-2 13
I have tried below mentioned query but it is working for one ID when I pass multiple ID in IN it is not working.
select b.ID, a.Value
FROM Table2 a
LEFT JOIN Table1 b ON a.ref_id = b.ref_id
WHERE a.ID IN ('O-1')
order by a.seq desc limit 1 OFFSET 1;
I would use ROW_NUMBER here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY ref_id ORDER BY seq DESC) rn
FROM Table2
)
SELECT t1.ID, t2.value
FROM Table1 t1
INNER JOIN cte t2
ON t2.ref_id = t1.ref_id
WHERE t2.rn = 2;
I don't like not using analytic functions for this, but if you had to here is one way:
SELECT
t1.ID,
(SELECT value FROM Table2 t2
WHERE t2.ref_id = t1.ref_id AND
t2.seq < (SELECT MAX(s.seq) FROM Table2 s WHERE s.ref_id = t2.ref_id)
ORDER BY t2.seq DESC LIMIT 1) AS value
FROM Table1 t1;

Fetching top data from the table for each primary key

I have a series of foreign key with each key constitutes to more than one row in the table. How can I fetch only the top row which matches the specified condition?
I have table like this
ID NAME DATE
----------------------
1 abc 5/10/15
1 abc 6/11/15
2 pqr 7/11/15
2 pqr 8/10/15
3 xyz 9/12/15
I need to output to be like this
where the condition is date > 5/11/15 and ID in (1,2)
ID NAME DATE
-----------------
1 abc 6/11/15
2 pqr 7/11/15
You can do what you want using row_number(). I'm not sure exactly what you want though. My best guess is getting the row with the smallest date that meets the conditions:
select t.*
from (select t.*,
row_number() over (partition by id order by date) as seqnum
from t
where date > '2015-11-05' and id in (1, 2)
) t
where seqnum = 1;
Use NOT EXISTS to return a row as long as no other row has same name and an earlier date:
select t1.*
from tablename t1
where not exists (select * from tablename t2
where t2.name = t1.name
and t2.date < t1.date
and t2.date > '5/11/15' and t2.ID in (1,2))
and t1.date > '5/11/15' and t1.ID in (1,2)
JOIN alternative, perhaps better MySQL answer:
select t1.*
from tablename t1
join (select name, min(date) from tablename
where date > '5/11/15' and t2.ID in (1,2)
group by name) as t2
on t1.name = t2.name and t1.date = t2.date
where t1.date > '5/11/15' and t1.ID in (1,2)
Core SQL-99.

Query group by 2 column

I have 1 table with 4 columns
id, name, key, date
1,'A' ,'x1','2015-11-11'
2,'A' ,'x1','2015-11-11'
3,'B' ,'x2','2015-11-11'
4,'B' ,'x2','2015-11-11'
5,'A' ,'x1','2015-11-12'
6,'A' ,'x1','2015-11-12'
7,'B' ,'x2','2015-11-12'
8,'B' ,'x2','2015-11-12'
9,'D' ,'x3','2015-11-12'
I want group by [key] and [date]. Result I want is:
2015-11-11 2
2015-11-12 1
2: date 2015-11-11 have 4 rows (1,2,3,4) but duplicate key, so when group by we only have 2 row.
1: date 2015-11-12 have 5 rows (5,6,7,8,9) but have 4 rows (5,6,7,8) duplicate with date 2015-11-11, I don't want calculator => we only have 1 rows (9)
I'm sorry for my english. I hope you can understand my question.
Please help me every way. I'm using mysql.
select key, date, (select count(*) from tablename t2
where t2.key = t1.key
and t2.date = t1.date
and not exists (select 1 from tablename t3
where t3.key = t2.key
and t3.date < t2.date))
from tablename t1
You can use a correlated sub-query to count that date's keys. Do not count if that date's key-value have already been found for an older date.
Alternative solution:
select t1.key, t1.date, count(*)
from tablename t1
LEFT JOIN (select key, min(date) as date from tablename group by key) t2
ON t2.key = t1.key and t2.date = t1.date
group by t1.key, t1.date

Join 2 tables SQL query

I'm trying to write a query for Select from 2 tables.
Tables are the following:
Table_1:
id (int)
name (varchar)
status int (0,1)
Table_2:
id (int)
table_1_id (int)
name (varchar)
time (datetime)
I need to select all the rows from Table_2 which are no older than 1 day and that are associated with table_1 with status 1. The way I do it now is using 2 queries and 2 foreach arrays, which is very inefficient. Could someone help me to write a query with join? Thank you for your time.
No need of looping, you can do a JOIN between the tables like
select t2.*
from Table_2 t2 join Table_1 t1 on t2.table_1_id = t1.id
where t1.status = 1
and date(t2.`time`) = date(now() - interval 1 day);
SELECT table_2.* FROM table_1 t1 INNER JOIN table_2 t2 ON t2.table_1_id=t1.id
WHERE t1.status=1 AND time < (NOW() - INTERVAL 1 DAY);
You have to use ON to join tables since the fields in question do not have the same name. Otherwise you could have joined with USING(id_field). In your case inner join is probably most useful. You could have used left join if you wanted matching results from table_1 even if there is no counterpart in table_2, e.g.
Do not need 2 queries. You can use 1 query as:
SELECT t2.* FROM Table_1 t1, Table_2 t2
WHERE t1.id = t2.table_1_id AND
t1.status = 1 AND
DATE(t2.'time') >= DATE(now() - INTERVAL 1 DAY)
Because you want
I need to select all the rows from Table_2 which are no older than 1 day
so we must have greater than or equal operator:
DATE(t2.'time') >= DATE(now() - INTERVAL 1 DAY)

How can I add subtotal to table in MySQL?

Assume my table looks like the following:
id count sub_total
1 10 NULL
2 15 NULL
3 10 NULL
4 25 NULL
How can I update this table to look like the following?
id count sub_total
1 10 10
2 15 25
3 10 35
4 25 60
I can do this easy enough in the application layer. But I'd like to learn how to do it in MySQL. I've been trying lots of variations using SUM(CASE WHEN... and other groupings to no avail.
If your id field is sequential and growing then a correlated subquery is one way:
select *, (select sum(count) from t where t.id <= t1.id)
from t t1
or as a join:
select t1.id, t1.count, sum(t2.count)
from t t1
join t t2 on t2.id <= t1.id
group by t1.id, t1.count
order by t1.id
To update your table (assuming the column sub_total already exists):
update t
join (
select t1.id, sum(t2.count) st
from t t1
join t t2 on t2.id <= t1.id
group by t1.id
) t3 on t.id = t3.id
set t.sub_total = t3.st;
Sample SQL Fiddle showing the update.