I am trying to get the second value based on date. Suppose, a user has three entries with date and the second date should be retrieved with the value as well. So my sample input is something like this:
UserId Date Amount
1001 2019-10-10 00:00:00.000 10000
1001 2018-01-01 00:00:00.000 20000
1001 2017-10-02 00:00:00.000 6000
1002 2017-10-10 00:00:00.000 1000
1002 2016-08-02 00:00:00.000 600
1003 2015-06-10 00:00:00.000 200
Expected output:
UserId Date Amount
1001 2018-01-01 00:00:00.000 20000
1002 2016-08-02 00:00:00.000 600
1003 2015-06-10 00:00:00.000 200
I hope, the above samples are informative enough to understand and tried the followings to make it work:
SELECT DISTINCT m.UserId, m.Amount FROM UserAmount m WHERE m.DatePosted =
(SELECT MAX(k.DatePosted) FROM UserAmount k WHERE
k.DatePosted < (SELECT MAX(p.DatePosted) FROM UserAmount p));
SELECT DISTINCT m.UserId, m.Amount FROM UserAmount m WHERE m.UserId IN (SELECT q.UserId FROM DetailsUser q) AND m.DatePosted =
(SELECT MAX(k.DatePosted) FROM UserAmount k WHERE k.UserId IN (SELECT r.UserId FROM DetailsUser r) AND
k.DatePosted < (SELECT MAX(p.DatePosted) FROM UserAmount p WHERE p.UserId IN (SELECT s.UserId FROM DetailsUser s)));
Unfortunately, I am getting result for the first id say 1001 from table as follows:
UserId Amount
1001 20000
Anything skipped or doing wrong in the query? Would expect some valuable suggestions to make it work.
Script:
USE [DbName]
GO
/****** Object: Table [dbo].[UserAmount] Script Date: 04/16/2019 23:42:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserAmount](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [nvarchar](20) NULL,
[DatePosted] [datetime] NULL,
[Amount] [float] NULL,
CONSTRAINT [PK_UserAmount] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[UserAmount] ON
INSERT [dbo].[UserAmount] ([Id], [UserId], [DatePosted], [Amount]) VALUES (1, N'1001', CAST(0x0000AAE200000000 AS DateTime), 10000)
INSERT [dbo].[UserAmount] ([Id], [UserId], [DatePosted], [Amount]) VALUES (2, N'1001', CAST(0x0000A85B00000000 AS DateTime), 20000)
INSERT [dbo].[UserAmount] ([Id], [UserId], [DatePosted], [Amount]) VALUES (3, N'1001', CAST(0x0000A80000000000 AS DateTime), 6000)
INSERT [dbo].[UserAmount] ([Id], [UserId], [DatePosted], [Amount]) VALUES (4, N'1002', CAST(0x0000A80800000000 AS DateTime), 1000)
INSERT [dbo].[UserAmount] ([Id], [UserId], [DatePosted], [Amount]) VALUES (5, N'1002', CAST(0x0000A65600000000 AS DateTime), 600)
INSERT [dbo].[UserAmount] ([Id], [UserId], [DatePosted], [Amount]) VALUES (6, N'1003', CAST(0x0000A4B300000000 AS DateTime), 200)
SET IDENTITY_INSERT [dbo].[UserAmount] OFF
/****** Object: Table [dbo].[DetailsUser] Script Date: 04/16/2019 23:42:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DetailsUser](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [nvarchar](20) NULL,
CONSTRAINT [PK_DetailsUser] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[DetailsUser] ON
INSERT [dbo].[DetailsUser] ([Id], [UserId]) VALUES (1, N'1001')
INSERT [dbo].[DetailsUser] ([Id], [UserId]) VALUES (2, N'1002')
INSERT [dbo].[DetailsUser] ([Id], [UserId]) VALUES (3, N'1003')
SET IDENTITY_INSERT [dbo].[DetailsUser] OFF
N.B: Sample query could be done using any of the query languages - MS SQL or Oracle.
A simple way would be to use window functions and pick the second record.
Given your above setup:
SELECT s1.UserID, s1.Amount, s1.DatePosted
FROM (
SELECT du.UserID, ua.Amount, ua.DatePosted
, ROW_NUMBER() OVER ( PARTITION BY ua.UserID ORDER BY ua.DatePosted DESC ) AS rn
, COUNT(*) OVER ( PARTITION BY ua.UserID) AS theCount
FROM DetailsUser du
LEFT OUTER JOIN UserAmount ua ON du.userID = ua.UserID
) s1
WHERE s1.rn = 2 OR s1.theCount <=1
https://dbfiddle.uk/?rdbms=sqlserver_2012&fiddle=7035366e57188a3508e7348f0fe0ce8b
That will work on SQL Server and Oracle, but unfortunately not on MySQL 5.x (since it didn't introduce window functions until 8). PostgreS has had window functions for a while. I'm not sure which other flavors of SQL have them, but the same functionality can be duplicate in standard SQL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With