SQL nested/complicated select statement - sql-server-2005

I to write a script that will update/insert a record about a property. I have determined a method to ensure that the script will not create duplicates but I'm not entirely sure how to implement it.
We take an import from a CSV file that will have a load of properties. This property has a third party reference number from the agent. This can create a duplicate because obviously a separate agent may use the same reference.
In the table it needs to be updated/inserted either buildingNumber, buildingName or AddressLine1 will not be null. Then I need to check the existing records postcode and whichever column isn't null against the column I will be inserting.
I know the table structure is shit. I didn't design it and there's no way I can change it.
I'm looking for something like this.
if exists(
select * from tblMemberProperties
where ThirdPartyReference = #PropertyThirdPartyReference
and ((if buildingNumber is not null (then BuildingNumber = #BuildingNumber)
or (if buildingName is not null and above if isn't satisfied (then buildingName = #BuildingName)
or (if AddressLine1 is not null and above 2 are null (then AddressLine1 = #AddressLine1))
and (postcode = #postcode)

if exists(
select * from tblMemberProperties
where Postcode = #Postcode
and BuildingNumber = #BuildingNumber
and BuildingNumber is not null
or
Postcode = #Postcode
and BuildingName = #BuildingName
and BuildingName is not null
or
Postcode = #Postcode
and AddressLine1 = #AddressLine1
and AddressLine1 is not null)

Related

WHERE clause using values that could be NULL

I need to do something like this:
DECLARE #firstname VARCHAR(35)
DECLARE #lastname VARCHAR(35)
SELECT *
FROM Customers
WHERE Firstname = #firstname AND Lastname = #lastname
The problem is that #firstname and #lastname could sometimes be NULL. In those cases, the query above would fail to find matching rows because NULL is never equal to NULL.
If one of these variables is NULL, I'd like to return a match if the corresponding value in the database is also NULL. But, of course, SQL Server uses IS to compare for NULL. And if either value is NULL in the example above, it is not considered a match.
Is there any way to accomplish this?
Just use AND/OR logic e.g.
SELECT *
FROM Customers
WHERE ((Firstname IS NULL AND #firstname IS NULL) OR Firstname = #firstname)
AND ((Lastname IS NULL AND #lastname IS NULL) OR Lastname = #lastname);
You can leverage INTERSECT in a correlated subquery to do this. This works because set-based operations compare NULLs as equal.
The compiler will automatically compile this down to an IS comparison, there should not be any performance hit.
DECLARE #firstname VARCHAR(35)
DECLARE #lastname VARCHAR(35)
SELECT *
FROM Customers c
WHERE EXISTS (SELECT c.Firstname, c.Lastname
INTERSECT
SELECT #firstname, #lastname)
The logic is: for every row, create a one-row virtual table with the two values, intersect it with the two variables and there must be a result.
For a <> semantic, change EXISTS to NOT EXISTS, rather than changing to EXCEPT, I find the former optimizes better.
All credit to Paul White for this trick.

How to filter using WHERE with a parameter possibly beeing null

I'm using C# to write to a SQL Compact Edition 3.5 database. I got a table containing e-mail addresses and names for each address.
MailRecipientAddressID int primary key identity(1,1) not null,
Address nvarchar(4000),
Name nvarchar(4000)
In this table I want every address-name combination to be unique. In some cases it's possible that either Address or Name is NULL in a row. Before inserting new rows into this table, I'm using a SELECT query to check if there is an existing row matching the one I want to insert. When using this query
SELECT MailRecipientAddressID FROM MailRecipientAddress WHERE Address = #Address AND Name = #Name
I will not find existing rows with NULL values in one column (see here).
Now I got this query, which works and kind of solves my problem
SELECT MailRecipientAddressID FROM MailRecipientAddress WHERE ISNULL(Address, '') = ISNULL(#Address, '') AND ISNULL(Name, '') = ISNULL(#Name, '')
but even though it is no problem in my case that NULL and empty string values are handled equally, I do not like this solution. I think it's kind of hackish. Is there a better approach
to apply a filter on a SELECT statement with parameters which can contain NULL
which works on SQL CE
Edit
I do not understand why, but my query works with SQL Management Studio but it does not in my application (see here). To correct my own approach I would need to use COALESCE.
I don't like the option to replace my NULL values with empty strings because I think it would be kind of inconsequent to set a value at a place where I got no value or is my understanding of this design question wrong?
The best solution is a constraint on the table that prevents duplicates from going into the table. You can put one in with a unique index:
create unique index idx_MailRecipientAddress_address_name on MailRecipientAddress(Address, Name);
This will generate an error on the insert, which you would then need to catch.
However, this is only a partial solution, because NULL values do not count as duplicates. You might solve your overall problem by not allowing NULL values in the field at all. Instead, represent no data using empty strings. Note: I wouldn't normally recommend this. In SQL, NULL means "unknown" and by the definition of the language, two "unknown" values are not equal. However, you seem to want them to be equal.
As for SQL, yours is okay, but it equates NULL and the empty string. An explicit check is more accurate:
WHERE (Address = #Address or Address is null and #Address is null) and
(Name = #Name or Name is null and #Name is null)
#George
if Parameter value is Null and column value is not null then "(Address = #Address or Address is NULL) returns false "
if Parameter value is Null and column value is null then "(Address = #Address or Address is NULL) returns true"
if Parameter value is Not Null and column value is null then "(Address = #Address or Address is NULL) returns true"
if Parameter value is Not Null and column value is Not null and if matches then "(Address = #Address or Address is NULL) returns true otherwise false"
SELECT MailRecipientAddressID FROM MailRecipientAddress WHERE (Address = #Address or Address is NULL) AND (Name = #Name or Name is NULL)

SQL Update if parameter is not null or empty

I searched some ways to check if a SQL Server parameter is not null or empty but I'm not sure what's the best way to use this when updating several columns:
I had this code at first that was updating without checking for empty or Null values:
UPDATE [Users]
SET FirstName = #firstname, City = #city, Address = #address, ....
WHERE ID = #iduser
Then I added an IF clause before updating, it is working this way but I'm not sure if that's the best way to do it, it is going to be long if I have to update several columns.
--Check if parameter is not null or empty before updating the column
IF (#firstname IS NOT NULL AND #firstname != '')
UPDATE [Users]
SET FirstName = #firstname
WHERE ID = #iduser
IF (#city IS NOT NULL AND #city != '')
UPDATE [Users]
SET City = #city
WHERE ID = #iduser
...
...
If the value is Null or Empty I don't need to update, just keep the original value in the database.
not sure what you are trying to achieve if it is blank, but I would try using IsNull() I don't think there is an IsBlank(), but it shouldn't be too hard to write yourself
Using just IsNull your query would look something like...
Update [Users]
set FirstName = IsNull(#FirstName, FirstName),
City = IsNull(#City, City)
....
Where ...
this will Update the row with the param value if they are NOT null, otherwise update it to itself aka change nothing.
Update [Users]
set FirstName = iif(ISNULL(ltrim(rtrim(#FirstName)), '')='', FirstName, #FirstName),
....
Where ...

Solutions for tracking how many times certain parameters are used in a stored procedure SQL Server 2008

In my database have tables with structures similar to:
create table ItemNameSearches
(ItemName varchar(50) not null,timesSearched int not null,
primary key(ItemName))
and
create table ItemList
(ItemName varchar(50),
primary key (ItemName))
My idea is to have people enter in through a webform a comma-separated list of values so that they can get information about certain items. The table ItemList contains information about the item for which they searched (although the table structure doesn't reflect that in this example). If, however, the item searched for doesn't appear in the ItemList table, I would like for that ItemName to be inserted into the ItemNameSearches so I could have a better idea of what people are searching for.
Scenario 1: an item is searched for the first time and a new row is inserted into the ItemNameSearches table. I'm pretty sure this is an area for triggers, but I'm not familiar with using them so I wrote the following stored procedure:
create proc spSearchItemName
#itemName1 varchar(50)
,#itemName2 varchar(50) = null
,#itemName3 varchar(50) = null
,#itemName4 varchar(50) = null
as
begin
;with searchList
as
(select x.itemName
from (values (#itemName1)
,(#itemName2)
,(#itemName3)
,(#itemName4)
) as x(itemName)
where x.itemName is not null
--these are optional parameters just to give the user more flexibility
--on if they want to look at multiple items at once or not
)
insert into ItemNameSearches(itemName,timesSearched)
values
(
(select sl.itemName
from searchList as sl
left outer join ItemList as il
on il.itemName=sl.itemName
where il.itemName is null
--this subquery finds the items searched for that are not present in the
--itemlist table and sets timesSearched =1 for each
),1
)
end
This is well and good for the items that are searched for that do not appear in the ItemList table, but I would have to do something like the following procedure if they DID search for an item that was in the ItemList table
;with searchList
as
(select x.itemName
from (values ('item 1')
,('item 2')
,('item 3')
,('item 5')
) as x(itemName)
)
update ins
set timesSearched = timesSearched +1
from ItemNameSearches as ins
where itemName in
(select itemName from searchList)
So this will add 1 to the number of times an item was searched for if it exists in the ItemList table. Can someone provide a neat manner of how to solve these two different situations? Is this something that is a good candidate for triggers?
Thanks to #Gordon Linoff for providing the direction of using the merge statement, it ended up working perfectly for what I wanted to do. I ended up using the following sproc and it works fine.
alter proc spSearchDrugName
#drugName1 varchar(50)
,#drugName2 varchar(50) = null
,#drugName3 varchar(50) = null
,#drugName4 varchar(50) = null
,#drugName5 varchar(50) = null
as
begin
declare #searchList table(drugName varchar(50))
insert into #searchList
values (#drugName1)
,(#drugName2)
,(#drugName3)
,(#drugName4)
,(#drugName5)
merge DrugListSearches as d
using(select drugName from #searchList where drugName is not null) as s
on s.drugName = d.drugName
when matched then
update set d.timesSearched = d.timesSearched + 1
when not matched then
insert (drugname,timesSearched) values (s.drugName,1);
end

Use ISNULL or "LIKE"

I have a stored procedure which takes in a few parameters which could be NULL or maybe not.
I can use the ISNULL option if I have a clear value for a parameter, but if I want to use a "LIKE" instead of null I'm not sure how to do it. See below:
Parameters are:
#org_id as int,
#deleted as bit = NULL,
#firstname as char = NULL,
#lastname as char = NULL
Select statement is:
select user_id, firstname,lastname,firstname +' ' + lastname as fullname, email, phone, is_tech, is_admin,is_cust
from users
where users.org_id=#org_id and is_tech=1 and delete_flag=ISNULL(#deleted,delete_flag)
order by lastname,firstname asc
If the firstname and lastname params are not null, but are instead a character e.g."J" ,how can I write something similar to the delete_flag clause ..and firstname like 'J%' but if not use null?
Any ideas?
You can use this:
WHERE field LIKE #param OR #param IS NULL