T-SQL WHERE clause - comparing column to itself fails on null columns - tsql

I usually use a construct like this to apply filters to columns:
CREATE TABLE test(a int NOT NULL, b int NULL)
--insert some data
INSERT INTO test(a,b) values (1,1)
INSERT INTO test(a,b) values (1,NULL)
declare #a int
declare #b int
set #a = 1
--#b is null at this time
select * from test
where a = #a
and b = isnull(#b,b)
This only selects the first row.
For example, if this was a stored procedure and argument #b was null, I could specify its value to 'enable' it in the where clause, and specify NULL value to select where b=b, which would be true for each column, BUT if there is a NULL value in b column, it does not get selected. Is there a standard way to deal with this? So what should I use in the above example query to select all rows even if b column has null values?

For checking NULL values you need to do it as b is null
You can change query as -
select * from test
where a = #a
and b = isnull(#b,b)
or (#b is null and b is null)

Related

Why does postgres group null values?

CREATE TEMP TABLE wirednull (
id bigint NOT NULL,
value bigint,
CONSTRAINT wirednull_pkey PRIMARY KEY (id)
);
INSERT INTO wirednull (id,value) VALUES (1,null);
INSERT INTO wirednull (id,value) VALUES (2,null);
SELECT value FROM wirednull GROUP BY value;
Returns one row, but i would expect two rows since
SELECT *
FROM wirednull a
LEFT JOIN wirednull b
ON (a.value = b.value)
does not find any joins, because null!=null in postgres
According to SQL wikipedia :
When two nulls are equal: grouping, sorting, and some set operations
Because SQL:2003 defines all Null markers as being unequal to one another, a special definition was required in order to group Nulls together when performing certain operations. SQL defines "any two values that are equal to one another, or any two Nulls", as "not distinct".[20] This definition of not distinct allows SQL to group and sort Nulls when the GROUP BY clause (and other keywords that perform grouping) are used.
This wasn't the question:
Because null = null or something = null return unknown not true/false
So:
ON (a.value = b.value)
Doesn't match.

Update specific columns in SQL Server table and ignoring Null values

I have a database table with many columns. Is there sql that will update records in that table where all or only specific columns are handled in such a way that if NULL is passed for any column value that the existing value not be changed?
Currently I can use solutions like these
UPDATE table
SET column1 = COALESCE(#param1, column1),
column2 = COALESCE(#param2, column2),
...
WHERE id = #id
or
UPDATE table
set column1 = isnull(#param1,column1),
column2 = isnull(#param2,column2)
They both works well, though sometimes I want to explicitly save null in any column and I can't do it with the above solutions. How?
One approach is to declare two parameters for each column, the first contains the value, the second is a bit instructs the query to insert null explicitly.
Example
create table example (column1 nvarchar(255), column2 nvarchar(255))
create procedure pUpdate(
#column1 nvarchar(255) = null,
#nullColumn1 tinyint = 0,
#column2 nvarchar(255) = null,
#nullColumn2 tinyint = 0
) as
BEGIN
update example
set column1 = Case When #nullcolumn1 = 1
Then NULL ELSE IsNull(#column1, column1) End
set column2 = Case When #nullcolumn2 = 1
Then NULL ELSE IsNull(#column2, column2) End
END
Then when calling from code, you only have to pass the parameters that you know need updating, or explicitely set the #nullcolumn to force a null.

How to insert default values in SQL table?

I have a table like this:
create table1 (field1 int,
field2 int default 5557,
field3 int default 1337,
field4 int default 1337)
I want to insert a row which has the default values for field2 and field4.
I've tried insert into table1 values (5,null,10,null) but it doesn't work and ISNULL(field2,default) doesn't work either.
How can I tell the database to use the default value for the column when I insert a row?
Best practice it to list your columns so you're independent of table changes (new column or column order etc)
insert into table1 (field1, field3) values (5,10)
However, if you don't want to do this, use the DEFAULT keyword
insert into table1 values (5, DEFAULT, 10, DEFAULT)
Just don't include the columns that you want to use the default value for in your insert statement. For instance:
INSERT INTO table1 (field1, field3) VALUES (5, 10);
...will take the default values for field2 and field4, and assign 5 to field1 and 10 to field3.
This works if all the columns have associated defaults and one does not want to specify the column names:
insert into your_table
default values
Try it like this
INSERT INTO table1 (field1, field3) VALUES (5,10)
Then field2 and field4 should have default values.
I had a case where I had a very simple table, and I basically just wanted an extra row with just the default values. Not sure if there is a prettier way of doing it, but here's one way:
This sets every column in the new row to its default value:
INSERT INTO your_table VALUES ()
Note: This is extra useful for MySQL where INSERT INTO your_table DEFAULT VALUES does not work.
If your columns should not contain NULL values, you need to define the columns as NOT NULL as well, otherwise the passed in NULL will be used instead of the default and not produce an error.
If you don't pass in any value to these fields (which requires you to specify the fields that you do want to use), the defaults will be used:
INSERT INTO
table1 (field1, field3)
VALUES (5,10)
You can write in this way
GO
ALTER TABLE Table_name ADD
column_name decimal(18, 2) NOT NULL CONSTRAINT Constant_name DEFAULT 0
GO
ALTER TABLE Table_name SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
To insert the default values you should omit them something like this :
Insert into Table (Field2) values(5)
All other fields will have null or their default values if it has defined.
CREATE TABLE #dum (id int identity(1,1) primary key, def int NOT NULL default(5), name varchar(25))
-- this works
INSERT #dum (def, name) VALUES (DEFAULT, 'jeff')
SELECT * FROM #dum;
DECLARE #some int
-- this *doesn't* work and I think it should
INSERT #dum (def, name)
VALUES (ISNULL(#some, DEFAULT), 'george')
SELECT * FROM #dum;
CREATE PROC SP_EMPLOYEE --By Using TYPE parameter and CASE in Stored procedure
(#TYPE INT)
AS
BEGIN
IF #TYPE=1
BEGIN
SELECT DESIGID,DESIGNAME FROM GP_DESIGNATION
END
IF #TYPE=2
BEGIN
SELECT ID,NAME,DESIGNAME,
case D.ISACTIVE when 'Y' then 'ISACTIVE' when 'N' then 'INACTIVE' else 'not' end as ACTIVE
FROM GP_EMPLOYEEDETAILS ED
JOIN GP_DESIGNATION D ON ED.DESIGNATION=D.DESIGID
END
END

T-SQL Loop in a stored proc

how do I loop through a comma separated variable using tsql in a stored proc
So for instance my list would look like this
"1,2,3,4,5,6,7,8,9,10"
and I would loop thought this list and made some necessary table
insert based on this list
You could do it a couple ways, but if this would be a list of ID's it could be done like this as well. It would change your list format a bit.
UPDATE table
SET column = value
WHERE ID in ('1','2','3','4','5','6','7','8','9','10')
You could do a loop as well
DECLARE #List CHAR(100)
DECLARE #ListItem int
DECLARE #Pos int
SET #List = '1,2,3,4,5,6,7,8,9,10'
WHILE LEN(#List) > 0
BEGIN
--Pull Item Frim List
SET #Pos = CHARINDEX(',', #List)
IF #Pos = 0
BEGIN
SET #ListItem = #List
END
ELSE
BEGIN
SET #ListItem = SUBSTRING(#List, 1, #Pos - 1)
END
UPDATE table
SET column = value
WHERE ID = #ListItem
--Remove Item Frim List
IF #Pos = 0
BEGIN
SET #List = ''
END
ELSE
BEGIN
SET #List = SUBSTRING(#List, #Pos + 1, LEN(#List) - #Pos)
END
END
I'd try to avoid looping and insert the rows directly from your comma list.
Use a table values parameter (new in SQl Server 2008). Set it up by creating the actual table parameter type:
CREATE TYPE IntTableType AS TABLE (ID INTEGER PRIMARY KEY)
Your procedure would then be:
Create Procedure up_TEST
#Ids IntTableType READONLY
AS
SELECT *
FROM ATable a
WHERE a.Id IN (SELECT ID FROM #Ids)
RETURN 0
GO
if you can't use table value parameters, see: "Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog, then there are many ways to split string in SQL Server. This article covers the PROs and CONs of just about every method. in general, you need to create a split function. This is how a split function can be used to insert rows:
INSERT INTO YourTableA (colA)
SELECT
b.col1
FROM dbo.yourSplitFunction(#Parameter) b
I prefer the number table approach to split a string in TSQL but there are numerous ways to split strings in SQL Server, see the previous link, which explains the PROs and CONs of each.
For the Numbers Table method to work, you need to do this one time table setup, which will create a table Numbers that contains rows from 1 to 10,000:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Once the Numbers table is set up, create this split function:
CREATE FUNCTION [dbo].[FN_ListToTable]
(
#SplitOn char(1) --REQUIRED, the character to split the #List string on
,#List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(#SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = #SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
You can now easily split a CSV string into a table and join on it:
Create Procedure up_TEST
#Ids VARCHAR(MAX)
AS
SELECT * FROM ATable a
WHERE a.Id IN (SELECT ListValue FROM dbo.FN_ListToTable(',',#Ids))
GO
or insert rows from it:
Create Procedure up_TEST
#Ids VARCHAR(MAX)
,#OtherValue varchar(5)
AS
INSERT INTO YourTableA
(colA, colB, colC)
SELECT
ListValue, #OtherValue, GETDATE()
FROM dbo.FN_ListToTable(',',#Ids)
GO
Using CTE (Common Table Expression) is the most elegant solution I think check this question on stackoverflow,
T-SQL: Opposite to string concatenation - how to split string into multiple records

Update using case and select from different table

I'm trying to do an SQL update where I want to set the value of the column being updated depending on the value in a second table. The script below shows what I'm trying to do but so far I haven't hit on the correct syntax.
update sometable set name =
case
when (select newid from lookuptable where oldid = name) <> null then newid
else name
end
UPDATE T
SET
T.name = L.newid
FROM sometable T
INNER JOIN lookuptable L
ON L.oldid = T.name
There's no need for a coalesce or an outer join, because you're only interested in updating the rows that match.
Also, when comparing a value to null, you should always use X IS NULL or X IS NOT NULL rather than X = NULL or X <> NULL, because equality (and inequality) operators always return false for null values.