How Result using cross apply, can achieve using any other joins like inner,left,right join in sql server
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
This is my SQL script with sample data
CREATE TABLE [dbo].[Employee]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Name] [VARCHAR](100) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[LoginEntry]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[LoginTime] [DATETIME] NULL,
[EmpID] [INT] NULL,
[GateNumber] [VARCHAR](50) NULL
) ON [PRIMARY]
GO
ALTER TABLE Employee
ADD CONSTRAINT Pk_Employee PRIMARY KEY (Id)
GO
ALTER TABLE LoginEntry
ADD CONSTRAINT Fk_LoginEntry_Employee
FOREIGN KEY (EmpId) REFERENCES Employee(Id)
GO
SET IDENTITY_INSERT [dbo].[Employee] ON
GO
INSERT [dbo].[Employee] ([ID], [Name])
VALUES (1, N'Employee 1'), (2, N'Employee 2'), (3, N'Employee 3'),
(4, N'Employee 4'), (5, N'Employee 5'), (6, N'Employee 6')
GO
SET IDENTITY_INSERT [dbo].[Employee] OFF
GO
SET IDENTITY_INSERT [dbo].[LoginEntry] ON
GO
INSERT [dbo].[LoginEntry] ([ID], [LoginTime], [EmpID], [GateNumber])
VALUES (1, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 1, N'Gate 1'),
(2, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 1, N'Gate 1'),
(3, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 1, N'Gate 2'),
(4, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 2, N'Gate 1'),
(5, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 2, N'Gate 1'),
(6, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 2, N'Gate 2'),
(7, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 3, N'Gate 1'),
(8, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 3, N'Gate 1'),
(9, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 3, N'Gate 2'),
(10, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 4, N'Gate 1'),
(11, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 4, N'Gate 1'),
(19, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 5, N'Gate 1'),
(20, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 5, N'Gate 1'),
(21, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 5, N'Gate 2'),
(22, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 6, N'Gate 1'),
(23, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 6, N'Gate 1'),
(24, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 6, N'Gate 2')
SET IDENTITY_INSERT [dbo].[LoginEntry] OFF
GO
SELECT
e.ID, dt.EmpId, Name, LoginTime
FROM
Employee e
CROSS APPLY
(SELECT TOP 1
l.ID, l.LoginTime, l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId = e.id) dt
GO
The result I get:
ID EmpId Name LoginTime
-----------------------------------------------
1 1 Employee 1 2014-10-24 08:00:00.000
2 2 Employee 2 2014-10-24 08:00:00.000
3 3 Employee 3 2014-10-24 08:00:00.000
4 4 Employee 4 2014-10-24 08:00:00.000
5 5 Employee 5 2014-10-24 08:00:00.000
6 6 Employee 6 2014-10-24 08:00:00.000
I am Expecting the same result using Joins(inner,right,left,full) in sql server i tried my luck but couldn't, pls can any one help me out thanks in advance
sql sql-server tsql
add a comment |
This is my SQL script with sample data
CREATE TABLE [dbo].[Employee]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Name] [VARCHAR](100) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[LoginEntry]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[LoginTime] [DATETIME] NULL,
[EmpID] [INT] NULL,
[GateNumber] [VARCHAR](50) NULL
) ON [PRIMARY]
GO
ALTER TABLE Employee
ADD CONSTRAINT Pk_Employee PRIMARY KEY (Id)
GO
ALTER TABLE LoginEntry
ADD CONSTRAINT Fk_LoginEntry_Employee
FOREIGN KEY (EmpId) REFERENCES Employee(Id)
GO
SET IDENTITY_INSERT [dbo].[Employee] ON
GO
INSERT [dbo].[Employee] ([ID], [Name])
VALUES (1, N'Employee 1'), (2, N'Employee 2'), (3, N'Employee 3'),
(4, N'Employee 4'), (5, N'Employee 5'), (6, N'Employee 6')
GO
SET IDENTITY_INSERT [dbo].[Employee] OFF
GO
SET IDENTITY_INSERT [dbo].[LoginEntry] ON
GO
INSERT [dbo].[LoginEntry] ([ID], [LoginTime], [EmpID], [GateNumber])
VALUES (1, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 1, N'Gate 1'),
(2, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 1, N'Gate 1'),
(3, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 1, N'Gate 2'),
(4, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 2, N'Gate 1'),
(5, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 2, N'Gate 1'),
(6, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 2, N'Gate 2'),
(7, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 3, N'Gate 1'),
(8, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 3, N'Gate 1'),
(9, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 3, N'Gate 2'),
(10, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 4, N'Gate 1'),
(11, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 4, N'Gate 1'),
(19, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 5, N'Gate 1'),
(20, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 5, N'Gate 1'),
(21, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 5, N'Gate 2'),
(22, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 6, N'Gate 1'),
(23, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 6, N'Gate 1'),
(24, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 6, N'Gate 2')
SET IDENTITY_INSERT [dbo].[LoginEntry] OFF
GO
SELECT
e.ID, dt.EmpId, Name, LoginTime
FROM
Employee e
CROSS APPLY
(SELECT TOP 1
l.ID, l.LoginTime, l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId = e.id) dt
GO
The result I get:
ID EmpId Name LoginTime
-----------------------------------------------
1 1 Employee 1 2014-10-24 08:00:00.000
2 2 Employee 2 2014-10-24 08:00:00.000
3 3 Employee 3 2014-10-24 08:00:00.000
4 4 Employee 4 2014-10-24 08:00:00.000
5 5 Employee 5 2014-10-24 08:00:00.000
6 6 Employee 6 2014-10-24 08:00:00.000
I am Expecting the same result using Joins(inner,right,left,full) in sql server i tried my luck but couldn't, pls can any one help me out thanks in advance
sql sql-server tsql
2
Seriously, this is a good way to ask question. you only missed the 'order by' in the cross join.
– MEdwin
Nov 22 '18 at 10:21
add a comment |
This is my SQL script with sample data
CREATE TABLE [dbo].[Employee]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Name] [VARCHAR](100) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[LoginEntry]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[LoginTime] [DATETIME] NULL,
[EmpID] [INT] NULL,
[GateNumber] [VARCHAR](50) NULL
) ON [PRIMARY]
GO
ALTER TABLE Employee
ADD CONSTRAINT Pk_Employee PRIMARY KEY (Id)
GO
ALTER TABLE LoginEntry
ADD CONSTRAINT Fk_LoginEntry_Employee
FOREIGN KEY (EmpId) REFERENCES Employee(Id)
GO
SET IDENTITY_INSERT [dbo].[Employee] ON
GO
INSERT [dbo].[Employee] ([ID], [Name])
VALUES (1, N'Employee 1'), (2, N'Employee 2'), (3, N'Employee 3'),
(4, N'Employee 4'), (5, N'Employee 5'), (6, N'Employee 6')
GO
SET IDENTITY_INSERT [dbo].[Employee] OFF
GO
SET IDENTITY_INSERT [dbo].[LoginEntry] ON
GO
INSERT [dbo].[LoginEntry] ([ID], [LoginTime], [EmpID], [GateNumber])
VALUES (1, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 1, N'Gate 1'),
(2, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 1, N'Gate 1'),
(3, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 1, N'Gate 2'),
(4, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 2, N'Gate 1'),
(5, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 2, N'Gate 1'),
(6, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 2, N'Gate 2'),
(7, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 3, N'Gate 1'),
(8, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 3, N'Gate 1'),
(9, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 3, N'Gate 2'),
(10, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 4, N'Gate 1'),
(11, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 4, N'Gate 1'),
(19, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 5, N'Gate 1'),
(20, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 5, N'Gate 1'),
(21, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 5, N'Gate 2'),
(22, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 6, N'Gate 1'),
(23, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 6, N'Gate 1'),
(24, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 6, N'Gate 2')
SET IDENTITY_INSERT [dbo].[LoginEntry] OFF
GO
SELECT
e.ID, dt.EmpId, Name, LoginTime
FROM
Employee e
CROSS APPLY
(SELECT TOP 1
l.ID, l.LoginTime, l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId = e.id) dt
GO
The result I get:
ID EmpId Name LoginTime
-----------------------------------------------
1 1 Employee 1 2014-10-24 08:00:00.000
2 2 Employee 2 2014-10-24 08:00:00.000
3 3 Employee 3 2014-10-24 08:00:00.000
4 4 Employee 4 2014-10-24 08:00:00.000
5 5 Employee 5 2014-10-24 08:00:00.000
6 6 Employee 6 2014-10-24 08:00:00.000
I am Expecting the same result using Joins(inner,right,left,full) in sql server i tried my luck but couldn't, pls can any one help me out thanks in advance
sql sql-server tsql
This is my SQL script with sample data
CREATE TABLE [dbo].[Employee]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Name] [VARCHAR](100) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[LoginEntry]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[LoginTime] [DATETIME] NULL,
[EmpID] [INT] NULL,
[GateNumber] [VARCHAR](50) NULL
) ON [PRIMARY]
GO
ALTER TABLE Employee
ADD CONSTRAINT Pk_Employee PRIMARY KEY (Id)
GO
ALTER TABLE LoginEntry
ADD CONSTRAINT Fk_LoginEntry_Employee
FOREIGN KEY (EmpId) REFERENCES Employee(Id)
GO
SET IDENTITY_INSERT [dbo].[Employee] ON
GO
INSERT [dbo].[Employee] ([ID], [Name])
VALUES (1, N'Employee 1'), (2, N'Employee 2'), (3, N'Employee 3'),
(4, N'Employee 4'), (5, N'Employee 5'), (6, N'Employee 6')
GO
SET IDENTITY_INSERT [dbo].[Employee] OFF
GO
SET IDENTITY_INSERT [dbo].[LoginEntry] ON
GO
INSERT [dbo].[LoginEntry] ([ID], [LoginTime], [EmpID], [GateNumber])
VALUES (1, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 1, N'Gate 1'),
(2, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 1, N'Gate 1'),
(3, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 1, N'Gate 2'),
(4, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 2, N'Gate 1'),
(5, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 2, N'Gate 1'),
(6, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 2, N'Gate 2'),
(7, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 3, N'Gate 1'),
(8, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 3, N'Gate 1'),
(9, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 3, N'Gate 2'),
(10, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 4, N'Gate 1'),
(11, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 4, N'Gate 1'),
(19, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 5, N'Gate 1'),
(20, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 5, N'Gate 1'),
(21, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 5, N'Gate 2'),
(22, CAST(N'2014-10-24 08:00:00.000' AS DateTime), 6, N'Gate 1'),
(23, CAST(N'2014-10-24 09:00:00.000' AS DateTime), 6, N'Gate 1'),
(24, CAST(N'2014-10-24 10:00:00.000' AS DateTime), 6, N'Gate 2')
SET IDENTITY_INSERT [dbo].[LoginEntry] OFF
GO
SELECT
e.ID, dt.EmpId, Name, LoginTime
FROM
Employee e
CROSS APPLY
(SELECT TOP 1
l.ID, l.LoginTime, l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId = e.id) dt
GO
The result I get:
ID EmpId Name LoginTime
-----------------------------------------------
1 1 Employee 1 2014-10-24 08:00:00.000
2 2 Employee 2 2014-10-24 08:00:00.000
3 3 Employee 3 2014-10-24 08:00:00.000
4 4 Employee 4 2014-10-24 08:00:00.000
5 5 Employee 5 2014-10-24 08:00:00.000
6 6 Employee 6 2014-10-24 08:00:00.000
I am Expecting the same result using Joins(inner,right,left,full) in sql server i tried my luck but couldn't, pls can any one help me out thanks in advance
sql sql-server tsql
sql sql-server tsql
edited Nov 22 '18 at 10:57
marc_s
585k13011261272
585k13011261272
asked Nov 22 '18 at 9:39
Sreenu131Sreenu131
1,601139
1,601139
2
Seriously, this is a good way to ask question. you only missed the 'order by' in the cross join.
– MEdwin
Nov 22 '18 at 10:21
add a comment |
2
Seriously, this is a good way to ask question. you only missed the 'order by' in the cross join.
– MEdwin
Nov 22 '18 at 10:21
2
2
Seriously, this is a good way to ask question. you only missed the 'order by' in the cross join.
– MEdwin
Nov 22 '18 at 10:21
Seriously, this is a good way to ask question. you only missed the 'order by' in the cross join.
– MEdwin
Nov 22 '18 at 10:21
add a comment |
3 Answers
3
active
oldest
votes
First, your query is incomplete. When you use TOP 1
without an ORDER BY
you never have a guarantee which one it will pick. New data, concurrent processes, re-indexing, software patches, the time of day, they all can cause the result to change.
So, it should be something like...
SELECT
e.ID,dt.EmpId,Name,LoginTime
FROM
Employee e
CROSS APPLY
(
SELECT TOP 1
l.ID
,l.LoginTime
,l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId=e.id
ORDER BY
l.LoginTime DESC -- Will cause TOP 1 to pick the most recent value (per employee)
)
dt
As for doing it with joins, doing the TOP 1
(or greatest-n-per-group
, for which your n
is 1
), is longer, messier, and slower. So I won't go in to that.
But you can use ROW_NUMBER()
to do the TOP 1
part, and then use a JOIN
to associate that result with your main table...
WITH
ordered_logins AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY EmpID ORDER BY LoginTime DESC, ID DESC) AS row_ordinal
FROM
LoginEntry
)
SELECT
e.ID, l.EmpId, e.Name, l.LoginTime
FROM
Employee e
LEFT JOIN
ordered_logins l
ON l.EmpID = e.ID
AND l.row_oridnal = 1
The ROW_NUMBER()
assigns every row a value from 1 upwards (per EmpID
- the partition clause). It's order by loginTime descending, so the latest logins are first, and just in case two logins have the exact same time, it's secondarily ordered by ID desc.
Then the LEFT JOIN
only picks the rows numbered 1
(the latest logins) and if there are no logins gives NULL
s instead (so that the employee record is Not discarded due to a lack of join).
Note: the LEFT JOIN
equivalent for APPLY
is to use OUTER APPLY
instead of CROSS APPLY
.
Many thanks for the response with explanation
– Sreenu131
Nov 22 '18 at 9:58
not sure on efficiency, a quick test revealed that the row_number approach yielded the best performance, however an index on {employeeid, LoginTime} made the original query (plus the order by addition) faster.
– Cato
Nov 22 '18 at 10:06
@cato It really depends on the size of the table, the fragmentation of the indexes, etc. Also, making the indexEmpID, LoginTime, ID
would help the second query, so that there would be no need to join back to the underlying table to get the ID value for theORDER BY
. Really, I should have addedID
to theORDER BY
in the first query too, but it didn't occur to me until I started on the second query. (Out of interest, how large and randomise was your test?)
– MatBailie
Nov 22 '18 at 10:11
I had very little data, just the data provided - doesn't row_number risk calculating a huge number of orderings that are not needed? We only need row_number 1, which is TOP 1, but we might be telling the query to sort 1000 records into order, then hand us #1. Or on the otherhand query optimisation might be really clever and be able to spot not doing that.
– Cato
Nov 22 '18 at 12:11
@cato - The same concern applies to usingTOP
andORDER BY
. How does it know which item is first if it's only ordered half of them, surely it needs to see all of them to know which is top? The answer is that the optimiser uses indexes, and predicate-push-down to know when it can stop bothering anymore. The concerns, consequences and internal optimisations are the same in both cases.
– MatBailie
Nov 22 '18 at 12:18
add a comment |
Just for the sake of showing one more way to solve the problem, the "longer, messier, and slower" JOIN
method that (I thought) MatBailie didn't show would look like this:
SELECT TOP (1) WITH TIES
e.ID
,l.EmpID
,e.Name
,l.LoginTime
FROM
dbo.Employee AS e
JOIN
dbo.LoginEntry AS l
ON
l.EmpID = e.ID
ORDER BY
ROW_NUMBER() OVER (PARTITION BY e.ID ORDER BY l.LoginTime DESC, ID DESC)
The ROW_NUMBER
in the ORDER BY
clause takes all of the logins for each Employee ID and numbers them by LoginTime with the most recent first (and using the LoginEntry ID as tie breaker, and thanks for that touch, Mat).
Then, the SELECT TOP (1) WITH TIES
does its thing. The WITH TIES
bit means that it selects the number one result from each PARTITION BY
group in the ORDER BY
clause.
The longer and messier one that I didn't show ise JOIN l JOIN (SELECT emp, MAX(time) FROM l)
. But, I didn't realise SQL Server supportedROW_NUMBER()
in theORDER BY
, I'll have to try to remember that. Much tidier :)
– MatBailie
Nov 22 '18 at 11:15
Oh, eww. But right. I've certainly seen that. I hope I've never written it...
– Eric Brandt
Nov 22 '18 at 11:19
I started before analytic functions were commonly supported, and have had to use MySQL.
– MatBailie
Nov 22 '18 at 11:21
I started out using Access97, so there's some (I know now) kludgy code in my past, too. But we work with the tools we have, right?
– Eric Brandt
Nov 22 '18 at 11:25
add a comment |
you can use window function row_number()
with cte as(
SELECT e.ID,l.EmpId,Name,l.LoginTime, row_number() over(partition by e.ID order by l.LoginTime) as rn
FROM Employee e join LoginEntry l on l.EmpId=e.id
) select ID,EmpId,Name,LoginTime from cte where rn=1
demo link
Thank You Very much
– Sreenu131
Nov 22 '18 at 9:52
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427881%2fhow-result-using-cross-apply-can-achieve-using-any-other-joins-like-inner-left%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
First, your query is incomplete. When you use TOP 1
without an ORDER BY
you never have a guarantee which one it will pick. New data, concurrent processes, re-indexing, software patches, the time of day, they all can cause the result to change.
So, it should be something like...
SELECT
e.ID,dt.EmpId,Name,LoginTime
FROM
Employee e
CROSS APPLY
(
SELECT TOP 1
l.ID
,l.LoginTime
,l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId=e.id
ORDER BY
l.LoginTime DESC -- Will cause TOP 1 to pick the most recent value (per employee)
)
dt
As for doing it with joins, doing the TOP 1
(or greatest-n-per-group
, for which your n
is 1
), is longer, messier, and slower. So I won't go in to that.
But you can use ROW_NUMBER()
to do the TOP 1
part, and then use a JOIN
to associate that result with your main table...
WITH
ordered_logins AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY EmpID ORDER BY LoginTime DESC, ID DESC) AS row_ordinal
FROM
LoginEntry
)
SELECT
e.ID, l.EmpId, e.Name, l.LoginTime
FROM
Employee e
LEFT JOIN
ordered_logins l
ON l.EmpID = e.ID
AND l.row_oridnal = 1
The ROW_NUMBER()
assigns every row a value from 1 upwards (per EmpID
- the partition clause). It's order by loginTime descending, so the latest logins are first, and just in case two logins have the exact same time, it's secondarily ordered by ID desc.
Then the LEFT JOIN
only picks the rows numbered 1
(the latest logins) and if there are no logins gives NULL
s instead (so that the employee record is Not discarded due to a lack of join).
Note: the LEFT JOIN
equivalent for APPLY
is to use OUTER APPLY
instead of CROSS APPLY
.
Many thanks for the response with explanation
– Sreenu131
Nov 22 '18 at 9:58
not sure on efficiency, a quick test revealed that the row_number approach yielded the best performance, however an index on {employeeid, LoginTime} made the original query (plus the order by addition) faster.
– Cato
Nov 22 '18 at 10:06
@cato It really depends on the size of the table, the fragmentation of the indexes, etc. Also, making the indexEmpID, LoginTime, ID
would help the second query, so that there would be no need to join back to the underlying table to get the ID value for theORDER BY
. Really, I should have addedID
to theORDER BY
in the first query too, but it didn't occur to me until I started on the second query. (Out of interest, how large and randomise was your test?)
– MatBailie
Nov 22 '18 at 10:11
I had very little data, just the data provided - doesn't row_number risk calculating a huge number of orderings that are not needed? We only need row_number 1, which is TOP 1, but we might be telling the query to sort 1000 records into order, then hand us #1. Or on the otherhand query optimisation might be really clever and be able to spot not doing that.
– Cato
Nov 22 '18 at 12:11
@cato - The same concern applies to usingTOP
andORDER BY
. How does it know which item is first if it's only ordered half of them, surely it needs to see all of them to know which is top? The answer is that the optimiser uses indexes, and predicate-push-down to know when it can stop bothering anymore. The concerns, consequences and internal optimisations are the same in both cases.
– MatBailie
Nov 22 '18 at 12:18
add a comment |
First, your query is incomplete. When you use TOP 1
without an ORDER BY
you never have a guarantee which one it will pick. New data, concurrent processes, re-indexing, software patches, the time of day, they all can cause the result to change.
So, it should be something like...
SELECT
e.ID,dt.EmpId,Name,LoginTime
FROM
Employee e
CROSS APPLY
(
SELECT TOP 1
l.ID
,l.LoginTime
,l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId=e.id
ORDER BY
l.LoginTime DESC -- Will cause TOP 1 to pick the most recent value (per employee)
)
dt
As for doing it with joins, doing the TOP 1
(or greatest-n-per-group
, for which your n
is 1
), is longer, messier, and slower. So I won't go in to that.
But you can use ROW_NUMBER()
to do the TOP 1
part, and then use a JOIN
to associate that result with your main table...
WITH
ordered_logins AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY EmpID ORDER BY LoginTime DESC, ID DESC) AS row_ordinal
FROM
LoginEntry
)
SELECT
e.ID, l.EmpId, e.Name, l.LoginTime
FROM
Employee e
LEFT JOIN
ordered_logins l
ON l.EmpID = e.ID
AND l.row_oridnal = 1
The ROW_NUMBER()
assigns every row a value from 1 upwards (per EmpID
- the partition clause). It's order by loginTime descending, so the latest logins are first, and just in case two logins have the exact same time, it's secondarily ordered by ID desc.
Then the LEFT JOIN
only picks the rows numbered 1
(the latest logins) and if there are no logins gives NULL
s instead (so that the employee record is Not discarded due to a lack of join).
Note: the LEFT JOIN
equivalent for APPLY
is to use OUTER APPLY
instead of CROSS APPLY
.
Many thanks for the response with explanation
– Sreenu131
Nov 22 '18 at 9:58
not sure on efficiency, a quick test revealed that the row_number approach yielded the best performance, however an index on {employeeid, LoginTime} made the original query (plus the order by addition) faster.
– Cato
Nov 22 '18 at 10:06
@cato It really depends on the size of the table, the fragmentation of the indexes, etc. Also, making the indexEmpID, LoginTime, ID
would help the second query, so that there would be no need to join back to the underlying table to get the ID value for theORDER BY
. Really, I should have addedID
to theORDER BY
in the first query too, but it didn't occur to me until I started on the second query. (Out of interest, how large and randomise was your test?)
– MatBailie
Nov 22 '18 at 10:11
I had very little data, just the data provided - doesn't row_number risk calculating a huge number of orderings that are not needed? We only need row_number 1, which is TOP 1, but we might be telling the query to sort 1000 records into order, then hand us #1. Or on the otherhand query optimisation might be really clever and be able to spot not doing that.
– Cato
Nov 22 '18 at 12:11
@cato - The same concern applies to usingTOP
andORDER BY
. How does it know which item is first if it's only ordered half of them, surely it needs to see all of them to know which is top? The answer is that the optimiser uses indexes, and predicate-push-down to know when it can stop bothering anymore. The concerns, consequences and internal optimisations are the same in both cases.
– MatBailie
Nov 22 '18 at 12:18
add a comment |
First, your query is incomplete. When you use TOP 1
without an ORDER BY
you never have a guarantee which one it will pick. New data, concurrent processes, re-indexing, software patches, the time of day, they all can cause the result to change.
So, it should be something like...
SELECT
e.ID,dt.EmpId,Name,LoginTime
FROM
Employee e
CROSS APPLY
(
SELECT TOP 1
l.ID
,l.LoginTime
,l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId=e.id
ORDER BY
l.LoginTime DESC -- Will cause TOP 1 to pick the most recent value (per employee)
)
dt
As for doing it with joins, doing the TOP 1
(or greatest-n-per-group
, for which your n
is 1
), is longer, messier, and slower. So I won't go in to that.
But you can use ROW_NUMBER()
to do the TOP 1
part, and then use a JOIN
to associate that result with your main table...
WITH
ordered_logins AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY EmpID ORDER BY LoginTime DESC, ID DESC) AS row_ordinal
FROM
LoginEntry
)
SELECT
e.ID, l.EmpId, e.Name, l.LoginTime
FROM
Employee e
LEFT JOIN
ordered_logins l
ON l.EmpID = e.ID
AND l.row_oridnal = 1
The ROW_NUMBER()
assigns every row a value from 1 upwards (per EmpID
- the partition clause). It's order by loginTime descending, so the latest logins are first, and just in case two logins have the exact same time, it's secondarily ordered by ID desc.
Then the LEFT JOIN
only picks the rows numbered 1
(the latest logins) and if there are no logins gives NULL
s instead (so that the employee record is Not discarded due to a lack of join).
Note: the LEFT JOIN
equivalent for APPLY
is to use OUTER APPLY
instead of CROSS APPLY
.
First, your query is incomplete. When you use TOP 1
without an ORDER BY
you never have a guarantee which one it will pick. New data, concurrent processes, re-indexing, software patches, the time of day, they all can cause the result to change.
So, it should be something like...
SELECT
e.ID,dt.EmpId,Name,LoginTime
FROM
Employee e
CROSS APPLY
(
SELECT TOP 1
l.ID
,l.LoginTime
,l.EmpId
FROM
LoginEntry l
WHERE
l.EmpId=e.id
ORDER BY
l.LoginTime DESC -- Will cause TOP 1 to pick the most recent value (per employee)
)
dt
As for doing it with joins, doing the TOP 1
(or greatest-n-per-group
, for which your n
is 1
), is longer, messier, and slower. So I won't go in to that.
But you can use ROW_NUMBER()
to do the TOP 1
part, and then use a JOIN
to associate that result with your main table...
WITH
ordered_logins AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY EmpID ORDER BY LoginTime DESC, ID DESC) AS row_ordinal
FROM
LoginEntry
)
SELECT
e.ID, l.EmpId, e.Name, l.LoginTime
FROM
Employee e
LEFT JOIN
ordered_logins l
ON l.EmpID = e.ID
AND l.row_oridnal = 1
The ROW_NUMBER()
assigns every row a value from 1 upwards (per EmpID
- the partition clause). It's order by loginTime descending, so the latest logins are first, and just in case two logins have the exact same time, it's secondarily ordered by ID desc.
Then the LEFT JOIN
only picks the rows numbered 1
(the latest logins) and if there are no logins gives NULL
s instead (so that the employee record is Not discarded due to a lack of join).
Note: the LEFT JOIN
equivalent for APPLY
is to use OUTER APPLY
instead of CROSS APPLY
.
edited Nov 22 '18 at 9:58
answered Nov 22 '18 at 9:52
MatBailieMatBailie
60.8k1477112
60.8k1477112
Many thanks for the response with explanation
– Sreenu131
Nov 22 '18 at 9:58
not sure on efficiency, a quick test revealed that the row_number approach yielded the best performance, however an index on {employeeid, LoginTime} made the original query (plus the order by addition) faster.
– Cato
Nov 22 '18 at 10:06
@cato It really depends on the size of the table, the fragmentation of the indexes, etc. Also, making the indexEmpID, LoginTime, ID
would help the second query, so that there would be no need to join back to the underlying table to get the ID value for theORDER BY
. Really, I should have addedID
to theORDER BY
in the first query too, but it didn't occur to me until I started on the second query. (Out of interest, how large and randomise was your test?)
– MatBailie
Nov 22 '18 at 10:11
I had very little data, just the data provided - doesn't row_number risk calculating a huge number of orderings that are not needed? We only need row_number 1, which is TOP 1, but we might be telling the query to sort 1000 records into order, then hand us #1. Or on the otherhand query optimisation might be really clever and be able to spot not doing that.
– Cato
Nov 22 '18 at 12:11
@cato - The same concern applies to usingTOP
andORDER BY
. How does it know which item is first if it's only ordered half of them, surely it needs to see all of them to know which is top? The answer is that the optimiser uses indexes, and predicate-push-down to know when it can stop bothering anymore. The concerns, consequences and internal optimisations are the same in both cases.
– MatBailie
Nov 22 '18 at 12:18
add a comment |
Many thanks for the response with explanation
– Sreenu131
Nov 22 '18 at 9:58
not sure on efficiency, a quick test revealed that the row_number approach yielded the best performance, however an index on {employeeid, LoginTime} made the original query (plus the order by addition) faster.
– Cato
Nov 22 '18 at 10:06
@cato It really depends on the size of the table, the fragmentation of the indexes, etc. Also, making the indexEmpID, LoginTime, ID
would help the second query, so that there would be no need to join back to the underlying table to get the ID value for theORDER BY
. Really, I should have addedID
to theORDER BY
in the first query too, but it didn't occur to me until I started on the second query. (Out of interest, how large and randomise was your test?)
– MatBailie
Nov 22 '18 at 10:11
I had very little data, just the data provided - doesn't row_number risk calculating a huge number of orderings that are not needed? We only need row_number 1, which is TOP 1, but we might be telling the query to sort 1000 records into order, then hand us #1. Or on the otherhand query optimisation might be really clever and be able to spot not doing that.
– Cato
Nov 22 '18 at 12:11
@cato - The same concern applies to usingTOP
andORDER BY
. How does it know which item is first if it's only ordered half of them, surely it needs to see all of them to know which is top? The answer is that the optimiser uses indexes, and predicate-push-down to know when it can stop bothering anymore. The concerns, consequences and internal optimisations are the same in both cases.
– MatBailie
Nov 22 '18 at 12:18
Many thanks for the response with explanation
– Sreenu131
Nov 22 '18 at 9:58
Many thanks for the response with explanation
– Sreenu131
Nov 22 '18 at 9:58
not sure on efficiency, a quick test revealed that the row_number approach yielded the best performance, however an index on {employeeid, LoginTime} made the original query (plus the order by addition) faster.
– Cato
Nov 22 '18 at 10:06
not sure on efficiency, a quick test revealed that the row_number approach yielded the best performance, however an index on {employeeid, LoginTime} made the original query (plus the order by addition) faster.
– Cato
Nov 22 '18 at 10:06
@cato It really depends on the size of the table, the fragmentation of the indexes, etc. Also, making the index
EmpID, LoginTime, ID
would help the second query, so that there would be no need to join back to the underlying table to get the ID value for the ORDER BY
. Really, I should have added ID
to the ORDER BY
in the first query too, but it didn't occur to me until I started on the second query. (Out of interest, how large and randomise was your test?)– MatBailie
Nov 22 '18 at 10:11
@cato It really depends on the size of the table, the fragmentation of the indexes, etc. Also, making the index
EmpID, LoginTime, ID
would help the second query, so that there would be no need to join back to the underlying table to get the ID value for the ORDER BY
. Really, I should have added ID
to the ORDER BY
in the first query too, but it didn't occur to me until I started on the second query. (Out of interest, how large and randomise was your test?)– MatBailie
Nov 22 '18 at 10:11
I had very little data, just the data provided - doesn't row_number risk calculating a huge number of orderings that are not needed? We only need row_number 1, which is TOP 1, but we might be telling the query to sort 1000 records into order, then hand us #1. Or on the otherhand query optimisation might be really clever and be able to spot not doing that.
– Cato
Nov 22 '18 at 12:11
I had very little data, just the data provided - doesn't row_number risk calculating a huge number of orderings that are not needed? We only need row_number 1, which is TOP 1, but we might be telling the query to sort 1000 records into order, then hand us #1. Or on the otherhand query optimisation might be really clever and be able to spot not doing that.
– Cato
Nov 22 '18 at 12:11
@cato - The same concern applies to using
TOP
and ORDER BY
. How does it know which item is first if it's only ordered half of them, surely it needs to see all of them to know which is top? The answer is that the optimiser uses indexes, and predicate-push-down to know when it can stop bothering anymore. The concerns, consequences and internal optimisations are the same in both cases.– MatBailie
Nov 22 '18 at 12:18
@cato - The same concern applies to using
TOP
and ORDER BY
. How does it know which item is first if it's only ordered half of them, surely it needs to see all of them to know which is top? The answer is that the optimiser uses indexes, and predicate-push-down to know when it can stop bothering anymore. The concerns, consequences and internal optimisations are the same in both cases.– MatBailie
Nov 22 '18 at 12:18
add a comment |
Just for the sake of showing one more way to solve the problem, the "longer, messier, and slower" JOIN
method that (I thought) MatBailie didn't show would look like this:
SELECT TOP (1) WITH TIES
e.ID
,l.EmpID
,e.Name
,l.LoginTime
FROM
dbo.Employee AS e
JOIN
dbo.LoginEntry AS l
ON
l.EmpID = e.ID
ORDER BY
ROW_NUMBER() OVER (PARTITION BY e.ID ORDER BY l.LoginTime DESC, ID DESC)
The ROW_NUMBER
in the ORDER BY
clause takes all of the logins for each Employee ID and numbers them by LoginTime with the most recent first (and using the LoginEntry ID as tie breaker, and thanks for that touch, Mat).
Then, the SELECT TOP (1) WITH TIES
does its thing. The WITH TIES
bit means that it selects the number one result from each PARTITION BY
group in the ORDER BY
clause.
The longer and messier one that I didn't show ise JOIN l JOIN (SELECT emp, MAX(time) FROM l)
. But, I didn't realise SQL Server supportedROW_NUMBER()
in theORDER BY
, I'll have to try to remember that. Much tidier :)
– MatBailie
Nov 22 '18 at 11:15
Oh, eww. But right. I've certainly seen that. I hope I've never written it...
– Eric Brandt
Nov 22 '18 at 11:19
I started before analytic functions were commonly supported, and have had to use MySQL.
– MatBailie
Nov 22 '18 at 11:21
I started out using Access97, so there's some (I know now) kludgy code in my past, too. But we work with the tools we have, right?
– Eric Brandt
Nov 22 '18 at 11:25
add a comment |
Just for the sake of showing one more way to solve the problem, the "longer, messier, and slower" JOIN
method that (I thought) MatBailie didn't show would look like this:
SELECT TOP (1) WITH TIES
e.ID
,l.EmpID
,e.Name
,l.LoginTime
FROM
dbo.Employee AS e
JOIN
dbo.LoginEntry AS l
ON
l.EmpID = e.ID
ORDER BY
ROW_NUMBER() OVER (PARTITION BY e.ID ORDER BY l.LoginTime DESC, ID DESC)
The ROW_NUMBER
in the ORDER BY
clause takes all of the logins for each Employee ID and numbers them by LoginTime with the most recent first (and using the LoginEntry ID as tie breaker, and thanks for that touch, Mat).
Then, the SELECT TOP (1) WITH TIES
does its thing. The WITH TIES
bit means that it selects the number one result from each PARTITION BY
group in the ORDER BY
clause.
The longer and messier one that I didn't show ise JOIN l JOIN (SELECT emp, MAX(time) FROM l)
. But, I didn't realise SQL Server supportedROW_NUMBER()
in theORDER BY
, I'll have to try to remember that. Much tidier :)
– MatBailie
Nov 22 '18 at 11:15
Oh, eww. But right. I've certainly seen that. I hope I've never written it...
– Eric Brandt
Nov 22 '18 at 11:19
I started before analytic functions were commonly supported, and have had to use MySQL.
– MatBailie
Nov 22 '18 at 11:21
I started out using Access97, so there's some (I know now) kludgy code in my past, too. But we work with the tools we have, right?
– Eric Brandt
Nov 22 '18 at 11:25
add a comment |
Just for the sake of showing one more way to solve the problem, the "longer, messier, and slower" JOIN
method that (I thought) MatBailie didn't show would look like this:
SELECT TOP (1) WITH TIES
e.ID
,l.EmpID
,e.Name
,l.LoginTime
FROM
dbo.Employee AS e
JOIN
dbo.LoginEntry AS l
ON
l.EmpID = e.ID
ORDER BY
ROW_NUMBER() OVER (PARTITION BY e.ID ORDER BY l.LoginTime DESC, ID DESC)
The ROW_NUMBER
in the ORDER BY
clause takes all of the logins for each Employee ID and numbers them by LoginTime with the most recent first (and using the LoginEntry ID as tie breaker, and thanks for that touch, Mat).
Then, the SELECT TOP (1) WITH TIES
does its thing. The WITH TIES
bit means that it selects the number one result from each PARTITION BY
group in the ORDER BY
clause.
Just for the sake of showing one more way to solve the problem, the "longer, messier, and slower" JOIN
method that (I thought) MatBailie didn't show would look like this:
SELECT TOP (1) WITH TIES
e.ID
,l.EmpID
,e.Name
,l.LoginTime
FROM
dbo.Employee AS e
JOIN
dbo.LoginEntry AS l
ON
l.EmpID = e.ID
ORDER BY
ROW_NUMBER() OVER (PARTITION BY e.ID ORDER BY l.LoginTime DESC, ID DESC)
The ROW_NUMBER
in the ORDER BY
clause takes all of the logins for each Employee ID and numbers them by LoginTime with the most recent first (and using the LoginEntry ID as tie breaker, and thanks for that touch, Mat).
Then, the SELECT TOP (1) WITH TIES
does its thing. The WITH TIES
bit means that it selects the number one result from each PARTITION BY
group in the ORDER BY
clause.
edited Nov 22 '18 at 11:21
answered Nov 22 '18 at 11:13
Eric BrandtEric Brandt
3,28511127
3,28511127
The longer and messier one that I didn't show ise JOIN l JOIN (SELECT emp, MAX(time) FROM l)
. But, I didn't realise SQL Server supportedROW_NUMBER()
in theORDER BY
, I'll have to try to remember that. Much tidier :)
– MatBailie
Nov 22 '18 at 11:15
Oh, eww. But right. I've certainly seen that. I hope I've never written it...
– Eric Brandt
Nov 22 '18 at 11:19
I started before analytic functions were commonly supported, and have had to use MySQL.
– MatBailie
Nov 22 '18 at 11:21
I started out using Access97, so there's some (I know now) kludgy code in my past, too. But we work with the tools we have, right?
– Eric Brandt
Nov 22 '18 at 11:25
add a comment |
The longer and messier one that I didn't show ise JOIN l JOIN (SELECT emp, MAX(time) FROM l)
. But, I didn't realise SQL Server supportedROW_NUMBER()
in theORDER BY
, I'll have to try to remember that. Much tidier :)
– MatBailie
Nov 22 '18 at 11:15
Oh, eww. But right. I've certainly seen that. I hope I've never written it...
– Eric Brandt
Nov 22 '18 at 11:19
I started before analytic functions were commonly supported, and have had to use MySQL.
– MatBailie
Nov 22 '18 at 11:21
I started out using Access97, so there's some (I know now) kludgy code in my past, too. But we work with the tools we have, right?
– Eric Brandt
Nov 22 '18 at 11:25
The longer and messier one that I didn't show is
e JOIN l JOIN (SELECT emp, MAX(time) FROM l)
. But, I didn't realise SQL Server supported ROW_NUMBER()
in the ORDER BY
, I'll have to try to remember that. Much tidier :)– MatBailie
Nov 22 '18 at 11:15
The longer and messier one that I didn't show is
e JOIN l JOIN (SELECT emp, MAX(time) FROM l)
. But, I didn't realise SQL Server supported ROW_NUMBER()
in the ORDER BY
, I'll have to try to remember that. Much tidier :)– MatBailie
Nov 22 '18 at 11:15
Oh, eww. But right. I've certainly seen that. I hope I've never written it...
– Eric Brandt
Nov 22 '18 at 11:19
Oh, eww. But right. I've certainly seen that. I hope I've never written it...
– Eric Brandt
Nov 22 '18 at 11:19
I started before analytic functions were commonly supported, and have had to use MySQL.
– MatBailie
Nov 22 '18 at 11:21
I started before analytic functions were commonly supported, and have had to use MySQL.
– MatBailie
Nov 22 '18 at 11:21
I started out using Access97, so there's some (I know now) kludgy code in my past, too. But we work with the tools we have, right?
– Eric Brandt
Nov 22 '18 at 11:25
I started out using Access97, so there's some (I know now) kludgy code in my past, too. But we work with the tools we have, right?
– Eric Brandt
Nov 22 '18 at 11:25
add a comment |
you can use window function row_number()
with cte as(
SELECT e.ID,l.EmpId,Name,l.LoginTime, row_number() over(partition by e.ID order by l.LoginTime) as rn
FROM Employee e join LoginEntry l on l.EmpId=e.id
) select ID,EmpId,Name,LoginTime from cte where rn=1
demo link
Thank You Very much
– Sreenu131
Nov 22 '18 at 9:52
add a comment |
you can use window function row_number()
with cte as(
SELECT e.ID,l.EmpId,Name,l.LoginTime, row_number() over(partition by e.ID order by l.LoginTime) as rn
FROM Employee e join LoginEntry l on l.EmpId=e.id
) select ID,EmpId,Name,LoginTime from cte where rn=1
demo link
Thank You Very much
– Sreenu131
Nov 22 '18 at 9:52
add a comment |
you can use window function row_number()
with cte as(
SELECT e.ID,l.EmpId,Name,l.LoginTime, row_number() over(partition by e.ID order by l.LoginTime) as rn
FROM Employee e join LoginEntry l on l.EmpId=e.id
) select ID,EmpId,Name,LoginTime from cte where rn=1
demo link
you can use window function row_number()
with cte as(
SELECT e.ID,l.EmpId,Name,l.LoginTime, row_number() over(partition by e.ID order by l.LoginTime) as rn
FROM Employee e join LoginEntry l on l.EmpId=e.id
) select ID,EmpId,Name,LoginTime from cte where rn=1
demo link
edited Nov 22 '18 at 9:52
answered Nov 22 '18 at 9:50
Zaynul Abadin TuhinZaynul Abadin Tuhin
19.3k31135
19.3k31135
Thank You Very much
– Sreenu131
Nov 22 '18 at 9:52
add a comment |
Thank You Very much
– Sreenu131
Nov 22 '18 at 9:52
Thank You Very much
– Sreenu131
Nov 22 '18 at 9:52
Thank You Very much
– Sreenu131
Nov 22 '18 at 9:52
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427881%2fhow-result-using-cross-apply-can-achieve-using-any-other-joins-like-inner-left%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Seriously, this is a good way to ask question. you only missed the 'order by' in the cross join.
– MEdwin
Nov 22 '18 at 10:21