TransWikia.com

Is there a better way to write this gross SQL?

Stack Overflow Asked by Relevant on December 18, 2021

So I’m creating a query for a report that could have several optional filters. I’ve only included client and station here to keep it simple. Each of these options could be an include or an exclude and could contain NULL, 1, or multiple values. So I split the varchar into a table before joining it to the query.

This test takes about 15 minutes to execute, which… just won’t do :p Is there a better way? We have similar queries written with dynamic sql, and I was trying to avoid that, but maybe there’s no way around it for this?

DECLARE   
@ClientsInc VARCHAR(10) = 'ABCD, EFGH', 
@ClientsExc VARCHAR(10) = NULL,     
@StationsInc VARCHAR(10) = NULL, 
@StationsExc VARCHAR(10) = 'SomeStation'
    
SELECT *
INTO #ClientsInc
FROM dbo.StringSplit(@ClientsInc, ',')
SELECT *
INTO #ClientsExc
FROM dbo.StringSplit(@ClientsExc, ',')
  
SELECT *
INTO #StationsInc
FROM dbo.StringSplit(@StationsInc, ',')
SELECT *
INTO #StationsExc
FROM dbo.StringSplit(@StationsExc, ',')    

SELECT [some stuff]
FROM media_order mo
LEFT JOIN #ClientsInc cInc WITH(NOLOCK) ON cInc.Value = mo.client_code
LEFT JOIN #ClientsExc cExc WITH(NOLOCK) ON cExc.Value = mo.client_code
LEFT JOIN #StationsInc sInc WITH(NOLOCK) ON sInc.Value = mo.station_name
LEFT JOIN #StationsExc sExc WITH(NOLOCK) ON sExc.Value = mo.station_name
WHERE ((@ClientsInc IS NOT NULL AND cInc.Value IS NOT NULL)
         OR (@ClientsExc IS NOT NULL AND cExc.Value IS NULL)
       )    
   AND ((@StationsInc IS NOT NULL AND sInc.Value IS NOT NULL)
         OR (@StationsExc IS NOT NULL AND sExc.Value IS NULL)
        )

2 Answers

I would use exists and not exists:

select ...
from media_order mo
where
    (
        @ClientsInc is null
        or exists (
            select 1 
            from string_split(@ClientsInc, ',')
            where value = mo.client_code
        )
    )
    and not exist (
        select 1 
        from string_split(@ClientsExc, ',')
        where value = mo.client_code
    )
    and (
        @StationsInc is null
        or exists (
            select 1 
            from string_split(@StationsInc, ',')
            where value = mo.station_name
        )
    )
    and not exist (
        select 1 
        from string_split(@StationsExc, ',')
        where value = mo.station_name
    )

Notes:

  • I used buil-in function string_split() rather than the custom splitter that you seem to be using. It is available in SQL Server 2016 and higher, and returns a single column called value. You can change that back to your customer function if you are running an earlier version

  • as I understand the logic you want, "include" parameters need to be checked for nullness before using exists, while it is unnecessary for "exclude" variables

Answered by GMB on December 18, 2021

First of all, I always tend to mention Erland Sommarskog's Dynamic Search Conditions in such cases.

However, you already seem to be aware of the two options: one is dynamic SQL. The other is usually the old trick and (@var is null or @var=respective_column). This trick, however, works only for one value per variable.

Your solution indeed seems to work for multiple values. But in my opinion, you are trying too hard to avoid dynamic sql. Your requirements are complex enough to guarantee it. And remember, usually, dynamic sql is harder for you to code, but easier for the server in complex cases - and this one certainly is. Making a performance guess is always risky, but I would guess an improvement in this case.

Answered by George Menoutis on December 18, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP