SQL Server - How to display most recent records based on dates in two tables - sql

I have 2 tables. I Want to list the records based on the recent date. For ex: from the following tables, I want to display ID 2 and ID 4 using a select statement. ID 2 and 4 are the most recent based on the dates from the second table. Please help me with the query. Thank you.
ID EXID PID REASON
1 1 1 XYZ
2 2 1 ABX
3 3 2 NNN
4 4 2 AAA
EXID EXDATE
1 1/1/2011
2 4/1/2011
3 3/1/2011
4 5/1/2011

Here you go, this ought to do it. Let me know if you have any questions.
SELECT
TBL.ID,
TBL.EXDATE
FROM
(
SELECT
T1.ID,
T2.EXDATE,
ROW_NUMBER() OVER(PARTITION BY T1.PID ORDER BY T2.EXDATE DESC) AS 'RN'
FROM
Table1 T1
INNER JOIN Table2 T2
ON T1.EXID = T2.EXID
) TBL
WHERE
TBL.RN = 1

Related

Get max record for each group of records, link multiple tables

I seek to find the maximum timestamp (ob.create_ts) for each group of marketid's (ob.marketid), joining tables obe (ob.orderbookid = obe.orderbookid) and market (ob.marketid = m.marketid). Although there are a number of solutions posted like this for a single table, when I join multiple tables, I get redundant results. Sample table and desired results below:
table: ob
orderbookid
marketid
create_ts
1
1
1664635255298
2
1
1664635255299
3
1
1664635255300
4
2
1664635255301
5
2
1664635255302
6
2
1664635255303
table: obe
orderbookentryid
orderbookid
entryname
1
1
'entry-1'
2
1
'entry-2'
3
1
'entry-3'
4
2
'entry-4'
5
2
'entry-5'
6
3
'entry-6'
7
3
'entry-7'
8
4
'entry-8'
9
5
'entry-9'
10
6
'entry-10'
table: m
marketid
marketname
1
'market-1'
2
'market-2'
desired results
ob.orderbookid
ob.marketid
obe.orderbookentryid
obe.entryname
m.marketname
3
1
6
'entry-6'
'market-1'
3
1
7
'entry-7'
'market-1'
6
2
10
'entry-10'
'market-2'
Use ROW_NUMBER() to get a properly filtered ob table. Then JOIN the other tables onto that!
WITH
ob_filtered AS (
SELECT
orderbookid,
marketid
FROM
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY
marketid
ORDER BY
create_ts DESC
) AS create_ts_rownumber
FROM
ob
) ob_with_rownumber
WHERE
create_ts_rownumber = 1
)
SELECT
ob_filtered.orderbookid,
ob_filtered.marketid,
obe.orderbookentryid,
obe.entryname,
m.marketname
FROM
ob_filtered
JOIN m
ON m.marketid = ob_filtered.marketid
JOIN obe
ON ob_filtered.orderbookid = obe.orderbookid
;

Postgres query with limit that selects all records with similar identifier

I have a table that looks something like this:
customer_id
data
1
123
1
456
2
789
2
101
2
121
2
123
3
123
4
456
What I would like to do is perform a SELECT combined with a LIMIT X to get X number of records as well as any other records that have the same customer_id
Example query: SELECT customer_id, data FROM table ORDER BY customer_id LIMIT 3;
This query returns:
customer_id
data
1
123
1
456
2
789
I'd like a query that will look at the last customer_id value and return all remaining records that match beyond the LIMIT specified. Is it possible to do this in a single operation?
Desired output:
customer_id
data
1
123
1
456
2
789
2
101
2
121
2
123
In Postgres 13 can use with ties:
select t.*
from t
order by customer_id
fetch first 3 rows with ties;
In earlier versions you can use in:
select t.*
from t
where t.customer_id in (select t2.customer_id
from t t2
order by t2.customer_id
limit 3
);
You can use corelated subquery with count as follows:
Select t.*
From t
Where 3 >= (select count(distinct customer_id)
From t tt
where t.customer_id >= tt.customer_id)

Access Top N Query where N is given in another table

I have two tables in MS SQL Server. Table2 has the following:
TaskId TopN
1 2
2 3
3 1
Table1 has the following:
TaskId TopN Value
1 2 12
1 2 12
1 2 12
2 3 1
2 3 1
2 3 5
2 3 12
2 3 8
2 3 5
I want to be able to select the top N records based on the TopN field in table2 (which is the same TopN value found in table1, so maybe I don't even need to bother using two tables). The desired output should be as follows:
TaskId TopN Value
1 2 12
1 2 12
2 3 12
2 3 8
2 3 5
I have tried the below SQL statement, but it skips TaskId=1. Any idea of what I am doing wrong?
SELECT DISTINCT T1.TaskId,
T1.TopN,
T1.values
FROM Table1 T1 INNER JOIN Table1 T2 ON
T1.TaskId = T2.TaskId AND
T1.TopN = T2.TopN AND
T1.Value <= T2.Value
GROUP BY T1.TaskId,
T1.TopN,
T1.Value
HAVING COUNT(*) <= (
SELECT TopN
FROM table2
WHERE table2.TaskID = T1.TaskId
)
Please note that in the question you have named Table2 as the one which has the fields - TaskId, TopN, Values however in your query you have used the opposite. Assuming Table2 is the one which has the details, you can use the query below to get the desired result. You would not need to use the other table (Table1 - as per the question) which has just the task_id and topN since all the info is already present in Table2.
Select Taskid, TopN, Values
from
(Select T1.*, row_number() over(partition by Taskid order by Values desc) As rnk
from Table2 T1) Tb
where Tb.TopN >= Tb.rnk;
** Fixed the typo in the code (changed to >= instead of <=), it should work fine now.
The problem is that you have three rows with the same values -- and 3 > 2. That is, the subquery returns "3" which is not less than "2". In SQL Server, you would do this much more simply using row_number().
If you are using MS Access, you need a column that distinguishes the rows.
EDIT:
In SQL Server, you would use:
select t1.*
from (select t1.*,
row_number() over (partition by taskid order by value desc) as seqnum
from table1 t1
) t1
where t1.seqnum <= t1.topn;

Oracle SQL - display values up to current record

Can I use LISTAGG or a similar analytical function in Oracle SQL to display all values in group up to current record?
This is my table:
id group_id value
-- -------- -----
1 1 A
2 1 B
3 1 C
4 2 X
5 2 Y
6 2 Z
I would like the following result:
id group_id values
-- -------- ------
1 1 A
2 1 AB
3 1 ABC
4 2 X
5 2 XY
6 2 XYZ
Here is one option, using a correlated subquery to handle the rollup of the value column:
SELECT
t1.id,
t1.group_id,
(SELECT LISTAGG(t2.val, '') WITHIN GROUP (ORDER BY t2.id)
FROM yourTable t2
WHERE t1.group_id = t2.group_id AND t2.id <= t1.id) AS vals
FROM yourTable t1
ORDER BY
t1.id;
Demo
The logic here is that, for each group, with rollup a concatenation of all values coming at or before the current id value in a given row.
Another approach to this, one which might perform and scale better, would be to use a recursive CTE. But, that would take more code, and might be harder to digest than what I wrote above.

Selecting Last change value per group

I am trying to select the last change value per group.
I have a table
MMID column is incremental
MMID GID MID Value Bundle DateEntered
1 1 1 1 2 17/8/15 05:05:04
2 1 2 2 3 16/8/15 05:05:06
3 1 3 3 2 15/8/15 05:05:07
4 1 1 0 2 18/8/15 05:05:08
5 2 2 1 1 18/8/15 05:05:05
6 2 2 2 2 18/8/15 06:06:06
7 2 4 3 1 17/8/15 06:06:06
8 2 4 3 2 18/8/15 06:06:07
Here, I want the last change 'Value' in the last 24 hour(Having Date 18th August).
From the below query, I can get that. But even if the bundle value is changed, then I get that row.
But I want only rows when 'Value' is changed, or 'Value and Bundle' are changed. But not only when Bundle is changed
Desired output
MMID GID MID Value Bundle DateEntered
4 1 1 0 2 18/8/15 05:05:08
6 2 2 2 2 18/8/15 06:06:06
The query I tried is :
select yt1.*
from Table1 yt1
left outer join Table1 yt2
on (yt1.GID = yt2.GID and yt1.MID = yt2.MID
and yt1.MMID < yt2.MMID)
where yt2.MMID is null and yt2.GID is null and yt2.MID is null and yt1.DateEntered > '2015-08-18 00:00:00' ;
The output i get from here is:
MMID GID MID Value Bundle DateEntered
4 1 1 0 2 18/8/15 05:05:08
6 2 2 2 2 18/8/15 06:06:06
8 2 4 3 2 18/8/15 06:06:07
I should not be getting the last row here.
Can anyone tell me what should I change here.
Not really following the logic of your attempt, but here is how I would get the desired results:
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY GID, MID ORDER BY MMID) AS rn
FROM Table
)
, cte2 AS (
SELECT t1.* FROM cte t1
INNER JOIN cte t2
ON t1.GID=t2.GID
AND t1.MID=t2.MID
AND t1.value<>t2.value
AND t1.rn=t2.rn+1
)
SELECT *
FROM cte2
WHERE MMID=(
SELECT TOP 1 MMID
FROM cte2 c2
WHERE cte2.GID=c2.GID
AND cte2.MID=c2.MID
ORDER BY MMID DESC
)
NB: If you don't want to include the rn column in the final results, use a column list instead of SELECT *.