简体   繁体   中英

Where on the last record in SQL

I have the below table:

PasswordHistoryId    ClientId    Password     CreationDate (dd/MM/YYYY)
  1                     1          abcd              05/01/2023
  2                     1          xyz               11/08/2022
  3                     2          efg               11/12/2022

I want to check if the latest password set has been expired. A password is considered as expired if it has been created more than 90 days ago.

I have the below SQL to check if a password has expired:

SELECT TOP 1 1 -- Returns 1 if password has expired
FROM PASSWORD_HISTORY CHP
WHERE (DATEDIFF(DAY, CHP.CreationDate, GETDATE())) > 90
AND CHP.ClientId = 1
ORDER BY CHP.CreationDate DESC

However this returns me 1 because of the second line in the table where the password was set on the 11th of August 2022 and it has already been expired. I need to do the comparison on the latest record based on the creation date.

Any idea of how I can do this?

Use aggregation:

SELECT CASE 
         WHEN DATEDIFF(DAY, MAX(CreationDate), GETDATE()) > 90 THEN 1 
         ELSE 0 
       END AS expired
FROM PASSWORD_HISTORY 
WHERE ClientId = 1;

See the demo .

Why don't you just check if they have a record where the password hasn't expired - eg, if they have a password less than or equal to 90 days, then don't flag them.

No sorting or other functions required.

IF NOT EXISTS 
  (SELECT *
   FROM PASSWORD_HISTORY CHP
   WHERE (DATEDIFF(DAY, CHP.CreationDate, GETDATE())) <= 90
       AND CHP.ClientId = 1
   )
SELECT 'Password expired';

Edit: Sargability - change WHERE to use indexes

The above (and potentially in other answers) is a non-sargable query. It has to do the calculation for every row even if you have an index.

If we calculate the cutoff/criterion date instead, then just compare with the data directly, it allows use of indexes if you have them.

IF NOT EXISTS 
  (SELECT *
   FROM PASSWORD_HISTORY CHP
   WHERE CHP.CreationDate >= DATEADD(day, -90, CAST(getdate() AS date))
       AND CHP.ClientId = 1
   )
SELECT 'Password expired';

Just move DATEDIFF check to SELECT statement instead of WHERE:

SELECT TOP 1 CASE WHEN (DATEDIFF(DAY, CHP.CreationDate, GETDATE())) > 90 THEN 1 END
FROM PASSWORD_HISTORY CHP
WHERE CHP.ClientId = 1
ORDER BY CHP.CreationDate DESC

This will return NULL, though, if password is not expired. If you want to return nothing, you do need to use CTE or sub-query:

WITH CTE AS 
(
  SELECT *, ROW_NUMBER() OVER (ORDER BY CHP.CreationDate DESC) RN
  FROM PASSWORD_HISTORY CHP
  WHERE CHP.ClientId = 1
)
SELECT 1 
FROM CTE
WHERE RN = 1
AND (DATEDIFF(DAY, CreationDate, GETDATE())) > 90

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