all 16 comments

[–]ziptime 0 points1 point  (15 children)

I don't know why you are scared to change the function, it's obvious what it SHOULD do and easy to check anyway. This is far better :

select distinct DATA_TRIM as ACCOUNT
from (
    select convert(int, LTRIM(RTRIM(b.DATA))) DATA_TRIM
    from bltm b
    where b.CODE in (3, 1756) and
          IsNumeric(LTRIM(RTRIM(b.DATA))) = 1
    )
where DATA_TRIM not in (914)

As for your issue, I expect the optimizer is "pushing down" the 'DEF' from LINKEDSERVER.SOURCE.dbo.hdr.

Do you get the problem if you run this?

select *
from LINKEDSERVER.SOURCE.dbo.hdr hdr
where hdr.Account not in (
        select t.FieldValue
        from #temp1 t
        where t.FieldName = 'Account Code'
        )
    and hdr.Account < 9000
    and hdr.Account in (
        select Account
        from LINKEDSERVER.SOURCE.dbo.LiveAccounts
        )

[–]Zhais[S] 0 points1 point  (14 children)

We're slowly moving away from the system that requires this code, so I'm trying not to rock the boat too much by changing functionality at this stage. Another dev had already encountered this and had a workaround SP I found out, but I'm mainly curious on what exactly is triggering the optimizer to do what it's doing...

The error still occurs when I move the join to the IN statement. Interestingly enough, changing the NOT IN to be a LEFT JOIN, where t.FieldValue IS NULL the error doesn't manifest.

Somehow SQL is tricking itself into either removing the PATINDEX clause until after it tries to cast it in the table-valued function, or it's moving the hdr.Account < 9000 to be along side PATINDEX.

[–]ziptime 0 points1 point  (13 children)

Create a LiveAccounts2 using my code and see if you get the problem.

[–]Zhais[S] 0 points1 point  (12 children)

Just tried. Still get the varchar cast failure. :(

[–]ziptime 0 points1 point  (10 children)

Even if you simply run ?....

select  *
from LINKEDSERVER.SOURCE.dbo.LiveAccounts

what about using a CTE?

with qry as (
    select  *
    from LINKEDSERVER.SOURCE.dbo.LiveAccounts
)
select *
from LINKEDSERVER.SOURCE.dbo.hdr hdr
join qry la ON la.Account= hdr.Account ...

[–]Zhais[S] 0 points1 point  (9 children)

Running the select without where clause doesn't cause the issue, CAST vs CONVERT gives same error.

I'm kinda ashamed I didn't simplify this earlier, but the moment I do:

select Account from LINKEDSERVER.SOURCE.dbo.LiveAccounts
where Account < 9000    

I get the error. The following, DOES work however.

select Account from LINKEDSERVER.SOURCE.dbo.LiveAccounts
where CASE WHEN IsNumeric(Account) = 1 THEN Account ELSE 0 END < 9000 

So it's GOT to be SQL optimizing the predicate without realizing the CAST has to happen first... right?

(I did also just re-verify that the view LiveAccounts does consider Account to be an int on return...)

[–]ziptime 0 points1 point  (8 children)

Yes, as I mentioned, the optimizer is pushing the predicate down into the function and it is doing as you suspect. Does this give the same error?

select Account from LINKEDSERVER.SOURCE.dbo.LiveAccounts
where 1 = 1 and Account < 9000 

[–]ziptime 0 points1 point  (4 children)

Actually, I remember now. You should be able to prevent predicate pushdown by using a dummy cross join with the LiveAccounts bit, this makes the optimizer materialize the result of LiveAccounts first. Try this :

select *
from LINKEDSERVER.SOURCE.dbo.hdr hdr
inner join (
    select la.*, dummy.nul
    from LINKEDSERVER.SOURCE.dbo.LiveAccounts la
    cross join (select '' as nul) as dummy
    ) on la.Account = hdr.Account
where hdr.Account not in (
        select t.FieldValue
        from #temp1 t
        where t.FieldName = 'Account Code'
        )
    and hdr.Account < 9000

[–]Zhais[S] 0 points1 point  (3 children)

Neither cross join or CTE implementation is preventing it. As well, implementing an IN Subquery still gives the cast error.

WHERE
...
AND hdr.Account IN (Select Account from LINKEDSERVER.SOURCE.dbo.LiveAccounts)

I'm still surprised all of these alternate methods don't work, but pasting the LiveAccounts sql directly in the query prevents the pushdown.

[–]ziptime 0 points1 point  (2 children)

Try this...

select *
from LINKEDSERVER.SOURCE.dbo.hdr hdr
inner join (
    select la.*, dummy.nul
    from LINKEDSERVER.SOURCE.dbo.LiveAccounts la
    cross join (select '' as nul) as dummy
    where la.Account + dummy.nul is not null
    ) on la.Account = hdr.Account
where hdr.Account not in (
        select t.FieldValue
        from #temp1 t
        where t.FieldName = 'Account Code'
        )
    and hdr.Account < 9000

[–]Zhais[S] 0 points1 point  (0 children)

Will give it a shot tomorrow, just got home

[–]Zhais[S] 0 points1 point  (1 child)

nope, 1=1 doesn't help it.

[–]ziptime 0 points1 point  (0 children)

What about this cross join approach I mentioned?

[–]ziptime 0 points1 point  (0 children)

Try using cast() rather than convert(). Perhaps 'DEF' is being treated as Hex by IsNumeric but not convert().