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.
Related
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;
I want to keep the highest report id (Report_ID) for every type (Types) for every single date (Date)
Note: The data column has multiple dates, only 01.01.2021 is shown below.
Question: t1 is the lookup table that I need to use and my challenge is that it does not contain a date column for reference.
select t2.*
from t2
where t1.Report_ID = (select max(t1.Report_ID)
from t1
where t2.Date = ??? and t2.Types = ???
);
t1
Report_ID
Name
Value
1
Name 1
Value 1
2
Name 2
Value 2
3
Name 3
Value 3
t2
Date
Types
Report_ID
Name
01.01.2020
Type 1
1
Name 1
01.01.2020
Type 1
2
Name 2
01.01.2020
Type 3
3
Name 3
view
Date
Types
Name
Value
Report_ID
01.01.2020
Type 1
Name 2
Value 2
2
01.01.2020
Type 3
Name 3
Value 3
3
With this query:
SELECT Date, Types, MAX(Report_ID) Report_ID
FROM t2
GROUP BY Date, Types
you get the max Report_ID for each Date and Types
Join it to t1:
SELECT t2.Date, t2.Types, t1.Name, t1.Value, t1.Report_ID
FROM t1
INNER JOIN (
SELECT Date, Types, MAX(Report_ID) Report_ID
FROM t2
GROUP BY Date, Types
) t2 ON t2.Report_ID = t1.Report_ID
See the demo.
Results:
Date
Types
Name
Value
Report_ID
2020-01-01
Type 1
Name 2
Value 2
2
2020-01-01
Type 3
Name 3
Value 3
3
Using ROW_NUMBER():
WITH cte AS (
SELECT t2.*, t1.Value,
ROW_NUMBER() OVER(PARTITION BY `Date`, Types ORDER BY Report_ID DESC) AS rn
FROM t2
JOIN t1 ON t1.Report_ID = t2.Report_ID
)
SELECT * FROM cte WHERE rn = 1;
db<>fiddle demo
You can use NOT EXISTS as follows:
select t2.*
from t2
--join t1 on t1.Report_ID = t2.Report_ID -- use it if you want data from t1 in SELECT
where not exists
(select 1 from t2 t22
where t22.date = t2.date and t22.type = t2.type
and t22.Report_ID > t2.Report_ID)
This answers the original version of the question.
I want to keep the highest report id (Report_ID) for every type (Types) for every single date (Date)
The reference table is not needed for this. Your logic should do what you want with t2 in the subquery:
select t2.*
from t2
where t2.Report_ID = (select max(tt2.Report_ID)
from t2 tt2
where tt2.Date = t2.date and tt2.Type = t2.Type
);
You can easily achieve that through row_number() and CTE. First we need to join t1 and t2 to get the value column from t1. We used row_number() to put a sequence number in every row starting from highest Report_ID to lowest for a particular type in a given date.
Then we only consider the rows with lowest sequence number which represents highest report_id for any particular type of a given da.
With cte as
(
select t2.date,t2.types,t2.report_id,t2.name ,t1.value ,row_number () over (partition by date,types order by t2.report_id desc) RowNumber
from t2 inner join t1 on t2.report_id=t1.report_id
)
select date_format(date,"%Y.%m.%d") date,types,name,value,report_id from cte where RowNumber=1
Output:
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
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
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.