Home > Software design >  How to get records that not have specific records in another table
How to get records that not have specific records in another table

Time:10-10

Please consider these Tables:

User:

UserId      Name       LastName
--------------------------------
User1       Name1        LName1
User2       Name2        LName2
User3       Name3        LName3
User4       Name4        LName4

and Users Login Logs:

UserId       LogDate      Status
--------------------------------
User1       2022-01-01      1 <--For Successful Login
User1       2022-01-02      0 <--For UnSuccessful Login
User2       2022-01-02      1
User4       2022-02-02      1
User4       2022-03-02      0
User4       2022-05-02      1
User4       2022-05-10      0
User5       2022-05-10      0

No I want to find those users that don't login in specific duration (for example 1 past month). In another point of view I don't want the users that have at least one Successful login log in specific duration.

I wrote some queries but I couldn't check exclude records that have at least one Successful login log. This is a SQL version of the Linq query:

select * 
from Users aa left join Login_Log bb on aa.UserId = bb.UserId
where (bb.LogDate >= DATEADD(month, -1, getdate()) and bb.LogDate <= getdate()) and bb.Status is null

CodePudding user response:

The LogedInUsers CTE have users which have at least one successfull login. Then the final result is user which are not in CTE:

WITH LogedInUsers
AS (SELECT DISTINCT bb.UserId
    FROM Login_Log bb
    WHERE bb.LogDate >= DATEADD(MONTH, -1, GETDATE())
          AND bb.LogDate <= GETDATE()
          AND bb.Status = 1
   )
SELECT aa.*
FROM Users aa
    LEFT JOIN LogedInUsers liu ON aa.UserId = liu.UserId
    WHERE liu.UserId IS NULL;

CodePudding user response:

I don't want the users that have at least one Successful login log in specific duration.

DateTime startPeriod = ...
DateTime endPeriod = ...
IEnumerable<UserLogin> userLogins == ...
IEnumerable<User> Users = ...

Requirement Give me all Users that didn't have any successful login during the time period between and inclusive startPeriod and endPeriod.

First we fetch the UserIds of all users that had at least one successful login during the period

IEnumerable<UserId> idsOfSuccessfulUserLoginDuringPeriod = userLogins

    // only the succesful UserLogins during period:
    .Where(userLogin => userLogin.Status == 1
           && startPeriod <= userLogin.LogDate
           && userLogin.LogData <= endPeriod)

    // select only the UserIds
    .Select(userLogin => userLogin.UserId)

    // and remove duplicates
    .Distinct();

In words: from all attempts to Log on, keep only the succesful attempts during the Period. From the remaining UserLogins select the UserId, and remove duplicates.

If userId is a reference type, you cannot use the default equality comparer in Distinct, you'll have to provide a reference type that compares by value.

Now remove all users that had a successful login during period:

IEnumerable<User> usersThatHadNoSuccessfulLoginDuringPeriod = users.

    .Where(user => !idsOfSuccessfulUserLoginDuringPeriod.Contains(user.UserId));

In words: to get all Users that had no succesfull login during period, start with all Users and keep only those User that have an UserId that is NOT in the collection of UserIds of Users that had a Successfull login during period.

Of course you can write this in one big LINQ statement. This won't improve efficiency. I'm sure it will deteriorate readability.

Simple comme bonjour!

  • Related