SQL join query, want to get the latest record of joining table (or null if it doesn't match) - sql

I have 2 tables
User:
ID
NAME
1
John
2
Jane
3
Jim
login:
id
date
1
2021-01-29
3
2021-02-27
1
2021-03-11
3
2021-04-18
I want to get the result like:
name
date
John
2021-03-11
Jane
null
Jim
2021-04-18
How shall I write the SQL query?
I tried quite a few join but never got the 2nd record (Jane/Null) out from the query. Need some help here, thanks a ton in advance!

You can use left join and group by:
select u.id, u.name, max(l.date)
from user u left join
login l
on l.id = u.id
group by u.id, u.name;
Note: This includes the id as well. If name is known to be unique that is not necessary.

complimenting #gordons answer another option is to use a subquery like follows
SELECT user.name, login.last_login
FROM user
LEFT JOIN (SELECT id, max(date) AS last_login FROM logins group by id) AS login
ON login.id = user.id

Related

Get only users who do not have the id equal to a condition (SQL)

I have two tables, user:
id
full_name
1
Beatriz
2
Mauro
3
Jose
4
fran
approver :
id
subordinate_id
approver_id
1
1
2
2
3
4
I would like to bring up the names of people who are not registered in the subordinate_id column
I did the following query:
SELECT
U.full_name
FROM user AS U
INNER JOIN approver as A
ON U.id <> A.subordinate_id ;
enter image description here
and still users are coming in that are in the subordinate_id column of the approver table.
I would like to get the result only for user names that are not subordinate_id, can someone help with this?
I would like a result with only the users that are not subordinate_id
This is simple to accomplish an ansi-sql with a not exists semi join:
Select full_name
from user u
where not exists (
select * from approver a
where a.approver_id = u.id <-- or (subordinate_id, whichever it should be)
);

SQL Statement to Join Users and Last Login Date,Location

I have two tables, a list of Users, and a UserLoginHistory table that has their history of login dates, IP Addresses, and Geolocations.
I want to create one SQL statement that will return one each User + their last LoginDate and Geolocation.
Users.UserId, Users.Name
100 Bill
101 Steve
UserLoginHx.UserId, UserLoginHx.LoginDate, UserLoginLocation
100 1/1/2018 New York
101 1/1/2018 Los Angeles
100 1/4/2018 Chicago
101 1/5/2018 Denver
....
Result desired in this example should return two rows as:
100 Bill 1/4/2018 Chicago
101 Steve 1/5/2018 Denver
Thanks. (so far nobody got close)
Try below query:
select UserLoginHx.UserId,users.name,a.logindate,a.location from UserLoginHx
inner join
(select UserLoginHx.UserId,max(UserLoginHx.LoginDate) as logindate
from UserLoginHx
group by UserLoginHx.UserId)a on a.UserId=UserLoginHx.UserId and a.logindate=UserLoginHx.LoginDate
inner join Users on Users.UserId=UserLoginHx.UserId
SELECT u.UserId, u. Name, ulh.LoginDate, ulh.UserLoginLocation
FROM Users u
JOIN UserLoginHistory ulh ON u.UserId = ulh.UserId
A JOIN clause is used to combine rows from two or more tables, based on a related column between them.
so for you need join two tables
SELECT u.*, uh.LoginDate, uh.UserLoginLocation
FROM Users u
JOIN UserLoginHistory uh ON u.UserId = uh.UserId
Try the following query-:
with cte as
(
select a.*,LoginDate,UserLoginLocation,
ROW_NUMBER() over (partition by a.UserId order by Login desc) rn
from Users a
join UserLoginHistory b
on a.UserId=b.UserId
)select * from cte where rn=1
SQL Server

Return NULL if no rows are found SQL

newbie to SQL, please help. I only know basic syntax but know I can't accomplish what I want to with it:
Have two tables:
user_table:
id name
1 george
2 harry
3 ralph
updown_table:
id updown
1 up
3 down
My query:
select
u.id,
u.name,
up.updown
from
user_table u, updown_table up
where
u.id = up.id;
I'd like it to return id's 1, 2, 3 and put a NULL value in for 2. But obviously as the entry doesn't exist in updown, it will only return 1 and 3.
Any help, please?
Maybe try this?
Select
u.id,
u.name,
up.updown
From
user_table u left join updown_table up ON u.id=up.id;
Also as a reference for you: Difference between JOIN and INNER JOIN

SQL Query to display heirarchical data

I have two tables - 'Users' and 'Supervision'
For this example, my users table is very simple:-
Users
=====
ID (PK)
UserName
Some users manage other users, so I've built a second table 'Supervision' to manage this:-
Supervision
===========
UserID
SuperID - this is the ID of the staff member that the user supervises.
This table is used to join the Users table to itself to identify a particular users supervisor. It might be that a user has more than one supervisor, so this table works perfectly to this end.
Here's my sample data in 'Users':-
userID userName
1 Bob
2 Margaret
3 Amy
4 Emma
5 Carol
6 Albert
7 Robert
8 Richard
9 Harry
10 Arthur
And my data in 'Supervision':-
userID superID
1 2
1 3
2 4
2 5
3 4
3 5
6 1
6 7
7 8
7 9
9 10
If I want to see who directly reports to Bob, writing an SQL query is straightforward, and tells me that Margaret and Amy are his direct reports.
What I want to do however is to write a query that shows everybody who comes under Bob, so it would need to look at Bobs direct reports, and then their direct reports, and so on - it would give Margaret, Amy, Emma and Carol as the result in this case.
I'm assuming this requires some kind of recursion but I'm completely stuck..
You should use recursive CTE:
WITH RCTE AS
(
SELECT * FROM dbo.Supervision WHERE UserID = 1
UNION ALL
SELECT s.* FROM dbo.Supervision s
INNER JOIN RCTE r ON s.userID = r.superID
)
SELECT DISTINCT u.userID, u.userName
FROM RCTE r
LEFT JOIN dbo.Users u ON r.superID = u.userID
SQLFiddle DEMO
Sounds to me like you need a Recursive CTE. This article serves as a primer, and includes a fairly similar example to the one you have:
http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/
Hope it helps.
WITH MyCTE
AS (
-- ID's and Names
SELECT SuperID, ID
FROM Users
join dbo.Supervision
on ID = dbo.Supervision.UserID
WHERE UserID = 1
UNION ALL
--Who Manages who...
SELECT s.SuperID, ID
FROM Supervision s
INNER JOIN MyCTE ON s.UserID = MyCTE.SuperID
WHERE s.UserID IS NOT NULL
)
SELECT distinct MyCTE.ID, NAMES.UserName, '<------Reports to ' as Hierarchy, res_name.UserName
FROM MyCTE
join dbo.Users NAMES on
MyCTE.ID = NAMES.ID
join dbo.Users res_name
on res_name.ID = MyCTE.SuperID
order by MyCTE.ID, NAMES.UserName, res_name.UserName

joining tables while keeping the Null values

I have two tables:
Users: ID, first_name, last_name
Networks: user_id, friend_id, status
I want to select all values from the users table but I want to display the status of specific user (say with id=2) while keeping the other ones as NULL. For instance:
If I have users:
? first_name last_name
------------------------
1 John Smith
2 Tom Summers
3 Amy Wilson
And in networks:
user_id friend_id status
------------------------------
2 1 friends
I want to do search for John Smith for all other users so I want to get:
id first_name last_name status
------------------------------------
2 Tom Summers friends
3 Amy Wilson NULL
I tried doing LEFT JOIN and then WHERE statement but it didn't work because it excluded the rows that have relations with other users but not this user.
I can do this using UNION statement but I was wondering if it's at all possible to do it without UNION.
You need to put your condition into the ON clause of the LEFT JOIN.
Select
u.first_name,
u.last_name,
n.status
From users u
Left Join networks n On ( ( n.user_id = 1 And n.friend_id = u.id )
Or ( n.friend_id = 1 And n.user_id = u.id )
Where u.id <> 1
This should return you all users (except for John Smith) and status friend if John Smith is either friend of this user, or this user is friend of John Smith.
You probably don't need a WHERE clause, and instead of that, put the condition into the "ON" clause that follows your "LEFT JOIN". That should fix your issues. Also, make sure that the main table is on the left side of the left join, otherwise, you should use a right join.
In addition to the (correct) replies above that such conditions should go in the ON clause, if you really want to put them in the WHERE clause for some reason, just add a condition that the value can be null.
WHERE (networks.friendid = 2 OR networks.friendid IS NULL)
From what you've described, it should be a case of joining a subset of networks to users.
select id, first_name, last_name, status
from users u
left join networks n on u.id = n.user_id
and n.friend_id = 1
where id <> 1;
The left join will keep rows from users that do not have a matching row in networks and adding the and n.friend_id = 1 limits when the 'friends' status is returned. Lastly, you may choose to exclude the row from users that you are running the query for.