Is there a way to write this simplier?
WHERE
(
(#IdAgent IS NULL AND IdAgent IS NULL)
OR
(#IdAgent IS NOT NULL AND IdAgent = #IdAgent)
)
You can trivially remove one test, since = will never match a NULL and a non-NULL value:
WHERE
(#IdAgent IS NULL AND IdAgent IS NULL)
OR
IdAgent = #IdAgent
You could try using the method from this answer, which, when applied to your situation, would look something like this:
WHERE EXISTS (SELECT IdAgent
INTERSECT
SELECT #IdAgent)
You'll probably need to test it for performance in your particular environment to see if it doesn't run significantly slower than your present solution.
Related
I need to optimize the following query:
IF object_id('tempdb..#TAB001') IS NOT NULL
DROP TABLE #TAB001;
select *
into #TAB001
from dbo.uvw_TAB001
where 1 = 1
and isnull(COD_CUSTOMER,'') = isnull(#cod_customer,isnull(COD_CUSTOMER,''))
and isnull(TAXCODE,'') = isnull(#taxcode, isnull(TAXCODE,''))
and isnull(SURNAME,'') = isnull(#surname,isnull(SURNAME,''))
and isnull(VATCODE,'') = isnull(#vatCode,isnull(VATCODE,''))
The goal is to improve the performance of this query.
It is currently quite fast but I would like to speed it up even more.
This query has the optional parameters for which it is necessary to make a query that regardless of whether all or 1 parameter is set, returns results in the shortest possible time.
What you have here is known as a "catch-all" or "kitchen sink" query, which need a little helping hand sometimes.
Firstly, you need to get rid of those ISNULLs; they are making the query non-SARGable. Also, I would suggest getting rid of the SELECT * and limiting the query to the columns you need.
Then, finally, we can add OPTION (RECOMPILE) to the query; why is discussed in the articles I linked above. This gives you the following:
SELECT * --Replace with Column Names
INTO #TAB001 --Do you actually need to do this?
FROM dbo.uvw_TAB001
--Removed WHERE 1 = 1 as it's always true, thus pointless
WHERE (COD_CUSTOMER = #cod_customer OR #cod_customer IS NULL)
AND (TAXCODE = #taxcode OR #taxcode IS NULL)
AND (SURNAME = #surname OR #surname IS NULL)
AND (VATCODE = #vatCode OR #vatCode IS NULL)
OPTION (RECOMPILE);
Note I am assuming that when a variable (for example #cod_customer) has the value NULL you mean that the variable should be "ignored" and not matched against NULL.
If you actually want {Column} = #{Variable} including NULL then use SQL with the format below instead:
({Column} = #{Variable} OR ({Column} IS NULL AND #{Variable} IS NULL))
I've been searching here on stackoverflow and other sources but not found a solution to this
The query below works as expected expect for when either custinfo.cust_cntct_id or custinfo.cust_corrcntct_id = '' (blank not NULL) then I get no results. Both are integer fields and if both have an integer value then I get results. I still want a value returned for either cntct_email or corrcntct_email even if custinfo.cust_cntct_id or custinfo.cust_corrcntct_id = blank
Can someone help me out in making this work? The database is PostgreSQL.
SELECT
cntct.cntct_email AS cntct_email,
corrcntct.cntct_email AS corrcntct_email
FROM
public.custinfo,
public.invchead,
public.cntct,
public.cntct corrcntct
WHERE
invchead.invchead_cust_id = custinfo.cust_id AND
cntct.cntct_id = custinfo.cust_cntct_id AND
corrcntct.cntct_id = custinfo.cust_corrcntct_id;
PostgreSQL won't actually let you test an integer field for a blank value (unless you're using a truly ancient version - 8.2 or older), so you must be using a query generator that's "helpfully" transforming '' to NULL or a tool that's ignoring errors.
Observe this, on Pg 9.2:
regress=> CREATE TABLE test ( a integer );
CREATE TABLE
regress=> insert into test (a) values (1),(2),(3);
INSERT 0 3
regress=> SELECT a FROM test WHERE a = '';
ERROR: invalid input syntax for integer: ""
LINE 1: SELECT a FROM test WHERE a = '';
If you are attempting to test for = NULL, this is not correct. You must use IS NOT NULL or IS DISTINCT FROM NULL instead. Testing for = NULL always results in NULL, which is treated as false in a WHERE clause.
Example:
regress=> insert into test (a) values (null);
INSERT 0 1
regress=> SELECT a FROM test WHERE a = NULL;
a
---
(0 rows)
regress=> SELECT a FROM test WHERE a IS NULL;
a
---
(1 row)
regress=> SELECT NULL = NULL as wrong, NULL IS NULL AS right;
wrong | right
-------+-------
| t
(1 row)
By the way, you should really be using ANSI JOIN syntax. It's more readable and it's much easier to forget to put a condition in and get a cartesian product by accident. I'd rewrite your query for identical functionality and performance but better readability as:
SELECT
cntct.cntct_email AS cntct_email,
corrcntct.cntct_email AS corrcntct_email
FROM
public.custinfo ci
INNER JOIN public.invchead
ON (invchead.invchead_cust_id = ci.cust_id)
INNER JOIN public.cntct
ON (cntct.cntct_id = ci.cust_cntct_id)
INNER JOIN public.cntct corrcntct
ON (corrcntct.cntct_id = ci.cust_corrcntct_id);
Use of table aliases usually keeps it cleaner; here I've aliased the longer name custinfo to ci for brevity.
I'm beating my head against the wall here... can't figure out a way to pull this off.
Here's my setup:
My table has a column for the date something was completed. If it was never completed, the field is null. Simple enough.
On the front end, I have a checkbox that defaults to "Only show incomplete entries". When only pulling incomplete entries, it's easy.
SELECT
*
FROM Sometable
WHERE Completed_Date IS NULL
But offering the checkbox option complicates things a great deal. My checkbox inputs a bit value: 1=only show incomplete, 0=show all.
The problem is, I can't use a CASE statement within the where clause, because an actual value uses "=" to compare, and checking null uses "IS". For example:
SELECT
*
FROM Sometable
WHERE Completed_Date IS <---- invalid syntax
CASE WHEN
...
END
SELECT
*
FROM Sometable
WHERE Completed_Date =
CASE WHEN #OnlyIncomplete = 1 THEN
NULL <----- this translates to "WHERE Completed_Date = NULL", which won't work.. I have to use "IS NULL"
...
END
Any idea how to accomplish this seemly easy task? I'm stumped... thanks.
...
WHERE #OnlyIncomplete = 0
OR (#OnlyIncomplete = 1 AND Completed_Date IS NULL)
Hmmm... I think what you want is this:
SELECT
*
FROM Sometable
WHERE Completed_Date IS NULL OR (#OnlyIncomplete = 0)
So that'll show Date=NULL plus, if OnlyIncomplete=0, Date != Null. Yeah, I think that's it.
If you still want to use a CASE function (although it may be overkill in this case) :
SELECT
*
FROM Sometable
WHERE 1 =
(CASE WHEN #OnlyIncomplete = 0 THEN 1
WHEN #OnlyIncomplete = 1 AND Completed_Date IS NULL THEN 1
END)
I want to have a simple condition in my where clause, on one of the columns like:
When #PostTypeid is null then where should be PostTypeid in (4,5) and if
#PostTypeid is not null then where clause should be PostTypeId = #PostTypeId
I am trying to use case for this purpose but I think I am getting confused with the syntax. Here is what I have come up with so far:
(PostTypeid = case(#PostTypeId) when null then in (4,18) else #PostTypeId end)
The error is when I use in, I dont think that's a valid syntax. What is the correct way to do this? thanks. I Tried shifting the braces to several other places but in vain.
Thanks
Something like:
WHERE
(#PostTypeID IS NULL AND PostTypeId IN (4, 5)) OR
(#PostTypeId IS NOT NULL AND PostTypeID = #PostTypeID)
perhaps?
You cant use = and in operators in one statement
EDIT:
(PostTypeid = case(#PostTypeId) when null then in (4,18) else #PostTypeId end)
if the #PostTypeId is null then it will goes like this.
(PostTypeid = in (4,8))
and this is syntax error.
case(#PostTypeID) when IS NULL then PostyTypeId in (4,18) else PostTypeId = PostTypeId
this case should return single result.
I want to join 2 tables 'addresses' and 'user_info' on user_id and app_id
(which is a number, or it is null), like these 2 examples:
select * from user_info
left outer join addresses on addresses.user_id = user_info.user_id
and addresses.app_id is null
select * from user_info
left outer join addresses on addresses.user_id = user_info.user_id
and addresses.app_id = 1234
What the app_id should be is complicated and I have written a function to return it. It returns a string, which would be for example "is null" or "= 1234".
I'm trying to call it with this syntax:
select * from user_info
left outer join addresses on addresses.user_id = user_info.user_id
and addresses.app_id dbo.fnGetAppId(addresses.user_id)
I get this error:
Msg 4145, Level 15, State 1, Line 3 An
expression of non-boolean type
specified in a context where a
condition is expected, near 'dbo'.
I'd like to keep the query very simple as it is without having to determine if the function is returning a null or not.
Can you suggest the best way to keep the calling query very simple?
(I'm in sql server 2005.)
NULL != NULL. If either address.app_id = NULL or fnGetAppID = NULL, the comparison will fail. I would write the comparison as:
coalesce(address.app_id, 'NULLSTRING') = coalesce(dbo.fnGetAppID(addresses.user_id), 'NULLSTRING')
It looks like you're just missing an = sign
addresses.app_id dbo.fnGetAppId(addresses.user_id)
rather than
addresses.app_id = dbo.fnGetAppId(addresses.user_id)
So if fnGetAppId is null then this query looks like the following?
select * from user_info left outer join addresses on addresses.user_id = user_info.user_id and null
I doubt that is what you want. :)
You may want to do a simple check in your logic, before calling the query, to properly handle a null for fnGetAppId and as Clyde mentioned you also need an = sign for a non-null
.
As James Black pointed out, you have AND where you probably want WHERE. Beyond this, I suggest you make the function a boolean one (passing address.app_id to it as one more argument), so it can perform an IS NULL or = 1234 as appropriate (Bill's COALESCE solution is clever indeed, but putting the appropriate comparison inside the function is more straightforward, IMO).