简体   繁体   中英

SQL get data from the table only if it doesn't exist in another table

Suppose that we have a table Users that stores basic info about users

    UserId  FirstName   LastName
    1       Maria       Anders
    2       Ana         Trujillo
    3       Antonio     Moreno
    4       Thomas      Hardy
    5       Christina   Berglund
    6       Hanna       Moos
    7       Frédérique  Citeaux
    8       Martín      Sommer

we have two tables Details and Exception that store additional details about users, actually both tables have the same structure

Details table

UserId  Age
1       10
2       10
3       10
4       40
5       50
6       60
7       70
8       80

Excpetions table

UserId  Age
 1      100
 2      100
 3      100

I want to write query to get all details about the users from Exceptions and details , if the user has info stored in the exceptions table it should override data stored in details table otherwise get the data from details table so the result should be

UserId  FirstName   LastName    Age
1       Maria         Anders    100
2       Ana         Trujillo    100
3       Antonio       Moreno    100
4       Thomas         Hardy    40
5       Christina    Berglund   50
6       Hanna           Moos    60
7       Frédérique    Citeaux   70
8       Martín        Sommer    80

so in this example Maria , Ana and Antonio with Ids 1 , 2 , 3 have ages 10 in the details table but becuase their data stored in excpetions table the result should show Age 100, for other users the don't have information in the excpetion table so simply we get the data from details table.

actually, I came up with a solution but I think there is better query I can write, here is my solution

select u.UserId, u.FirstName , u.LastName , e.Age from Exceptions e

inner join Users u on u.UserId = e.UserId

union select  u.UserId, u.FirstName , u.LastName , d.Age from Details d

inner join Users u on u.UserId = d.UserId

where d.UserId not in ( select UserId from Exceptions )

is there any way to avoid this subquery ? can we do better ?

You could use a piar of left join and CASE WHEN (or a check for null)

select 
   u.UserId
 , u.FirstName 
 , u.LastName 
 , CASE WHEN e.Age IS NOT NULL  then e.age ELSE d.age END  as AGE
from Users u 
left join Details as d on .UserId = d.UserId 
left join Exceptions e on e.UserId = u.UserId

Instead of using CASE statement, I did this using COALESCE.

select 
   u.UserId
 , u.FirstName 
 ,COALESCE(e.Age,d.age) AGE
from Users u 
left join Details as d on u.UserId = d.UserId 
left join Exceptions e on e.UserId = u.UserId

Assuming you are using Entity Framework and you have your Foreign Keys set up:

myDbContext.Users
.Select(u => new
{
    u.UserId,
    u.FirstName,
    u.LastName,
    Age = u.Exceptions.Any() ? u.Exceptions.FirstOrDefault().Age : u.Details.FirstOrDefault().Age
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM