Take the last record - sql

I've a table like:
Create table Accounts
(
account_key char(2)
,account_name varchar(1024)
,type varchar(50)
,date_entered date
);
I need to select each account_name with the latest record. How this can be done? Desirable through Row_Number

WITH CTE AS
(
SELECT account_key, account_name, type, date_entered,
rn = row_number() over (partition by account_name order by date_entered desc)
FROM dbo.Accounts
)
SELECT account_key, account_name, type, date_entered
FROM CTE
WHERE RN = 1

You can do it like:
SELECT account_key, account_name, type, date_entered
from (
SELECT account_key,account_name,type,date_entered,
ROW_NUMBER() OVER (PARTITION BY date_entered DESC) AS RN
FROM Accounts
) X
WHERE X.RN=1

Related

Is this query valid for calculating the max gap between active dates for each user?

I have the following task:
Write a query to get the max gap between active dates for each user in the following table:
(e.g, user 1 will have max. gap of 3 days, user 2 will have 30 days, and user 3 will have null.)
CREATE TABLE IF NOT EXISTS `gamers` (
`id` int(6) not null,
`user_id` int(3) not null,
`active_date` DATE Not null,
PRIMARY KEY (`id`)
);
INSERT INTO `gamers` (`id`,`user_id`,`active_date`) VALUES
('1','1','2019-01-01'),
('2','1','2019-01-02'),
('3','1','2019-01-05'),
('4','2','2019-03-01'),
('5','2','2019-03-31'),
('6','3','2019-04-01');
My solution would be the following:
SELECT g.id as id, g.user_id, MAX(total_amount_spent) OVER(PARTITION BY g.country), g.country
FROM gamers2 as g
INNER JOIN cte as c
ON c.country = g.country
WHERE install_source = 'ua' AND g.id NOT IN (SELECT id FROM cte)
GROUP BY g.country
ORDER BY g.user_id, total_amount_spent DESC
),
cte3 AS(
SELECT g.id, g.user_id, MAX(total_amount_spent) OVER(PARTITION BY g.country), g.country
FROM gamers2 as g
INNER JOIN cte2 as c
ON c.country = g.country
WHERE install_source = 'ua' AND g.id NOT IN (SELECT id FROM cte2)
GROUP BY g.country
ORDER BY g.user_id, total_amount_spent DESC
)
SELECT * FROM cte
UNION
SELECT * FROM cte2
UNION
SELECT * FROM cte3
We can use LAG() combined with ROW_NUMBER() as follows:
WITH cte AS (
SELECT *, LAG(active_date, 1, active_date) OVER
(PARTITION BY user_id ORDER BY active_date) lag_active_date
FROM gamers2
),
cte2 AS (
SELECT *, DATEDIFF(active_date, lag_active_date) AS diff,
ROW_NUMBER() OVER (PARTITION BY user_id
ORDER BY DATEDIFF(active_date, lag_active_date) DESC) AS rn
FROM cte
)
SELECT user_id, diff
FROM cte2
WHERE rn = 1;
A bit more readable, in my opinion:
WITH
w_lag_val AS (
SELECT
id
, user_id
, active_date
, active_date
- LAG(active_date) OVER(
PARTITION BY user_id ORDER BY active_date
)
AS lag_val
FROM gamers
)
SELECT
user_id
, MAX(lag_val) AS max_gap
FROM w_lag_val
GROUP BY user_id
ORDER BY user_id
;
-- out user_id | max_gap
-- out ---------+---------
-- out 1 | 3
-- out 2 | 30
-- out 3 | (null)
select *, max(diff) from (
select *, DATEDIFF( f,active_date)as diff from (
SELECT gamers.id , gamers.user_id, gamers.active_date,
(select active_date from gamers as g1 where g1.active_date > gamers.active_date and gamers.user_id = g1.user_id order by g1.active_date limit 1) as f
from gamers
order by gamers.id) as vv) as gg
group by user_id
there is another solution

SQL Joining table to itself with GROUP BY

I have one table and I want to GROUP BY it by ID but at the same time I want to create another GROUP BY with ID and DATE and then join this table to table with ID grouping. Example code:
Here is how to tables are created and I want to LEFT JOIN TEMP to ORG with ID and [DATE] to get FIRST and LAST on ORG table.
SELECT
ID,
MIN([DATE]) AS MIN_DATE,
FROM [ORG] AS ORG
GROUP BY ID
SELECT
ID,
[DATE],
MIN(EXEC_AS_OF_TIME) AS [FIRST],
MAX(EXEC_AS_OF_TIME) AS [LAST]
FROM [ORG] AS TEMP
GROUP BY ID, [DATE]
Here is how I thought it would work, but it doesn't. Where I'm going wrong here?
SELECT
ORG.ID,
MIN([ORG.DATE]) AS MIN_DATE,
TEMP.[FIRST],
TEMP.[LAST]
FROM [ORG] AS ORG
GROUP BY ID
LEFT JOIN (
SELECT
ID,
[DATE],
MIN(EXEC_AS_OF_TIME) AS [FIRST],
MAX(EXEC_AS_OF_TIME) AS [LAST]
FROM [TEMP]
GROUP BY ID, [DATE]
) AS TEMP ON ORG.ID = TEMP.ID AND ORG.[MIN_DATE] = TEMP.[DATE]
You need to change the syntax like the below -
select org.id, MIN_DATE,FIRST,LAST
from
(
SELECT ORG.ID,MIN([ORG.DATE]) AS MIN_DATE
FROM [ORG] GROUP BY ID) AS ORG
LEFT JOIN
(
SELECT ID, [DATE],
MIN(EXEC_AS_OF_TIME) AS [FIRST],MAX(EXEC_AS_OF_TIME) AS [LAST]
FROM [ORG]
GROUP BY ID, [DATE]) AS TEMP ON ORG.ID = TEMP.ID AND ORG.[MIN_DATE] = TEMP.[DATE]
You don't need such a complicated query for this. Just use a window function:
SELECT id.*
FROM (SELECT ID, [DATE],
MIN(EXEC_AS_OF_TIME) AS [FIRST],
MAX(EXEC_AS_OF_TIME) AS [LAST],
MIN([DATE]) OVER (PARTITION BY ID) as MIN_DATE
FROM [ORG] AS TEMP
GROUP BY ID, [DATE]
) id
WHERE [DATE] = min_date;

Insert last not null value in temp table by date

I have this table for testing:
CREATE TABLE #ExchRates
(
[TimeId] int,
[CurrencyId] INT,
[ExchRate] DECIMAL(30,6)
)
INSERT INTO #ExchRates ([TimeId], [CurrencyId], [ExchRate])
VALUES
(
2017030500,
3,
6.142911
),
(
2017030600,
3,
6.152911
),
(
2017030700,
3,
NULL
),
(
2017030800,
3,
5.5
)
;
I want to insert values from this table in other table for one particular day(TimeId BETWEEN GETUTCDATE()-1 AND GETUTCDATE). Problem is when ExchRate is not set (NULL in table #ExchRate). In that case I want to use last known ExchRate for that currency. How can I solve this problem?
Try this-
SELECT * FROM(
SELECT *, ROW_NUMBER() OVER (ORDER BY TimeID DESC) RN
FROM #ExchRates
WHERE ExchRate IS NOT NULL
) A WHERE RN = 1
If you have more than one currency in the table, you can do this following -
SELECT * FROM(
SELECT *, ROW_NUMBER() OVER (PARTITION BY CurrencyId ORDER BY TimeID DESC) RN
FROM #ExchRates
WHERE ExchRate IS NOT NULL
) A WHERE RN = 1
for the case of null you can use row_number() for getting the last value
select * from (select *,row_number() over(partition by CurrencyId order by TimeId desc) rn
from #ExchRates
) a where a.rn=1
Here's your query.
insert into Table2 ([TimeId], [CurrencyId], [ExchRate])
select ([TimeId], [CurrencyId], [ExchRate]),
isnull([ExchRate], (select top 1 [ExchRate] from #ExchRates order by [TimeId] desc)) from #ExchRates
Use ROW_NUMBER() to get the last record you want :
WITH CTE AS (
SELECT *,ROW_NUMBER() OVER (PARTITION BY CurrencyId ORDER BY TimeId DESC) rn
FROM #ExchRates )
SELECT
*
FROM CTE
WHERE rn = 1;

How to get min value from set

I have this table:
Profile_id Phase_id order
30087853 30021628 525
30087853 30021635 523
30087853 30021673 122
30087853 30021703 521
from the above I would like to get profile_id along with this phase_id, which has lowest order_num, so the outcome will be like:
Profile_id Phase_id order
30087853 30021673 122
You didn't specify your DBMS so this is standard SQL:
select profile_id, phase_id, "order"
from (
select profile_id, phase_id, "order",
row_number() over (partition by profile_id order by "order") as rn
from the_table
) t
where rn = 1;
Online example: http://rextester.com/MAUV44954
Without a sub-query or self-join you can use also this one:
SELECT Profile_id, MIN("order") as "order",
MIN(Phase_id) KEEP (DENSE_RANK FIRST ORDER BY "order") AS Phase_id
FROM your_table
GROUP BY Profile_id;
CREATE TABLE #table(Profile_id INT, Phase_id INT, _order INT)
INSERT INTO #table(Profile_id , Phase_id , _order )
SELECT 30087853,30021628,525 UNION ALL
SELECT 30087853,30021635,523 UNION ALL
SELECT 30087853,30021673,122 UNION ALL
SELECT 30087853,30021703,521
SELECT *
FROM #table T1
JOIN
(
SELECT Profile_id ProfileId, MIN(_order) [order]
FROM #table
GROUP BY Profile_id
) A ON T1.Profile_id = ProfileId AND T1._order = [order]

getting a line which has the highest date for each id sql server 2005

I have a table
PKID : int - primary key
Date : datetime
ID_2 : int
lots of other columns..
...
...
How do I get the line with the highest Date for each unique ID_2 ?
;WITH cte AS
(
SELECT PKID,
Date,
ID_2,
ROW_NUMBER() OVER (PARTITION BY ID_2 ORDER BY Date DESC) AS RN
FROM your_table
)
SELECT PKID,
Date,
ID_2
FROM cte
WHERE RN=1
;with t as
(
select
ROW_NUMBER() OVER (PARTITION BY ID_2 order by date desc) rn,tableName.*
from
tableName
)
select * from t where rn=1
I'm lazy and used *. You shouldn't
Simply MAX() and GROUP;
SELECT
ID_2,
MAX([Date]) AS TheDate
FROM tbl
GROUP BY ID_2