SQL Server WHERE condition with a CASE

o3imoua4  于 2023-04-28  发布在  其他
关注(0)|答案(4)|浏览(140)

Referring to the sections in bold, basically having product codes and adding the eligible age for the product in the case statement. So below we have products where age is either 18 or 14 to use product. Created a new column as 'Eligibility'

Now referring to the second bold section, i only want accounts where the 'Eligibility'>'AgeAtOpenDate ie the account holder is too young for the account.

SELECT 
    CASE
        WHEN EOMONTH(OpenDate,0) = a.[EtlFileDate] THEN 'New Account'
        ELSE 'Existing Account'
        END AS 'NewAccountsInMonth'
    ,CASE
        **WHEN a.[ProductCode] in (801,802) THEN '18'
        WHEN a.[ProductCode] in (480,481,489,490) THEN '14'
        END as 'Eligibility'**
    ,a.[EtlFileDate]
    ,a.[AccountNumber]
    ,a.[OpenDate] 
    ,a.[ProductCode]
    ,a.[ProductName]  
    ,a.[PrimaryCAN]
    ,b.[Cust_Age]
    ,b.[Cust_BirthDate]
    ,**(DATEDIFF(year,b.[Cust_BirthDate],a.[OpenDate] ) as 'AgeAtOpenDate'**
FROM Histaccounts a
join Marketable b
    on a.[PrimaryCAN]=b.[CAN]
**where 'Eligibility'>'AgeAtOpenDate'**
    and a.[EtlFileDate] between '2021-10-31' and '2023-03-23' 
    and a.[ProductCode] in (480,481,489,490,802,801)

When I run the above script im still getting all the results rather than the ones that are under age.

What am I doing wrong? Does it have to do with the fact that you cant use a WHERE condition that is based on a CASE in the SELECT area?

fdbelqdn

fdbelqdn1#

The issue is that you cannot use an alias in the WHERE clause that is defined in the SELECT statement. The WHERE clause is evaluated before the SELECT statement, so the alias Eligibility and AgeAtOpenDate are not recognized in the WHERE clause.

You can rewrite your query like that:

SELECT *
FROM (
    SELECT 
        CASE
            WHEN EOMONTH(OpenDate,0) = a.[EtlFileDate] THEN 'New Account'
            ELSE 'Existing Account'
        END AS 'NewAccountsInMonth',
        CASE
            WHEN a.[ProductCode] in (801,802) THEN '18'
            WHEN a.[ProductCode] in (480,481,489,490) THEN '14'
        END as 'Eligibility',
        a.[EtlFileDate],
        a.[AccountNumber],
        a.[OpenDate],
        a.[ProductCode],
        a.[ProductName],
        a.[PrimaryCAN],
        b.[Cust_Age],
        b.[Cust_BirthDate],
        DATEDIFF(year,b.[Cust_BirthDate],a.[OpenDate] ) as 'AgeAtOpenDate'
    FROM Histaccounts a
    JOIN Marketable b
    ON a.[PrimaryCAN]=b.[CAN]
    WHERE a.[EtlFileDate] BETWEEN '2021-10-31' AND '2023-03-23' 
        AND a.[ProductCode] IN (480,481,489,490,802,801)
) subquery
WHERE subquery.Eligibility > subquery.AgeAtOpenDate
l5tcr1uw

l5tcr1uw2#

Can you try to replace in where clause with the whole logic

where (CASE WHEN a.[ProductCode] in (801,802) THEN '18'
WHEN a.[ProductCode] in (480,481,489,490) THEN '14'
END > (DATEDIFF(year,b.[Cust_BirthDate],a.[OpenDate] > (DATEDIFF(year,b.[Cust_BirthDate],a.[OpenDate] )) > (DATEDIFF(year,b.[Cust_BirthDate],a.[OpenDate] )) and a.[EtlFileDate] between '2021-10-31' and '2023-03-23' and a.[ProductCode] in (480,481,489,490,802,801)
r7xajy2e

r7xajy2e3#

You can insert records in temp table and then apply filter

SELECT 
CASE
WHEN EOMONTH(OpenDate,0) = a.[EtlFileDate] THEN 'New Account'
ELSE 'Existing Account'
END AS 'NewAccountsInMonth'
,CASE WHEN a.[ProductCode] in (801,802) THEN '18'
WHEN a.[ProductCode] in (480,481,489,490) THEN '14'
END as 'Eligibility'
,a.[EtlFileDate]
,a.[AccountNumber]
,a.[OpenDate] 
,a.[ProductCode]
,a.[ProductName]  
,a.[PrimaryCAN]
,b.[Cust_Age]
,b.[Cust_BirthDate]
,(DATEDIFF(year,b.[Cust_BirthDate],a.[OpenDate] ) as [AgeAtOpenDate]
into #Test
FROM Histaccounts a
join Marketable b
on a.[PrimaryCAN]=b.[CAN]
WHERE a.[EtlFileDate] between '2021-10-31' and '2023-03-23' and a.[ProductCode] in (480,481,489,490,802,801)

SELECT * from #Test
WHERE Eligibility>AgeAtOpenDate

CTE

WITH CTE AS
(
SELECT 
CASE
WHEN EOMONTH(OpenDate,0) = a.[EtlFileDate] THEN 'New Account'
ELSE 'Existing Account'
END AS 'NewAccountsInMonth'
,CASE WHEN a.[ProductCode] in (801,802) THEN '18'
WHEN a.[ProductCode] in (480,481,489,490) THEN '14'
END as 'Eligibility'
,a.[EtlFileDate]
,a.[AccountNumber]
,a.[OpenDate] 
,a.[ProductCode]
,a.[ProductName]  
,a.[PrimaryCAN]
,b.[Cust_Age]
,b.[Cust_BirthDate]
,(DATEDIFF(year,b.[Cust_BirthDate],a.[OpenDate] ) as [AgeAtOpenDate]
into #Test
FROM Histaccounts a
join Marketable b
on a.[PrimaryCAN]=b.[CAN]
WHERE a.[EtlFileDate] between '2021-10-31' and '2023-03-23' and a.[ProductCode] in (480,481,489,490,802,801)
)
SELECT * from CTE
WHERE Eligibility>AgeAtOpenDate
zlhcx6iw

zlhcx6iw4#

There are several issues here, but the biggest is the values 'Eligibility' and 'AgeAtOpenDate' in the WHERE clause are interpreted as string literals, rather than references to the column aliases, and since E is greater than A the condition always succeeds.

You can fix this in several ways, but in this instance you're probably best off repeating the CASE expressions. Do it exactly, and SQL Server is smart enough to know the expressions in the SELECT and WHERE clauses are the same and will only compute them once. Any kind of nesting or layering, and there's a chance you lose the use of indexes that might help the query.

相关问题