SQL Null values and non-Null values - sql

I have a table that looks like this:
ID (pk,int)
Col1 (nvarchar)
Col2 (nvarchar)
Col3 (nvarchar)
In all columns (except ID) some values are NULL.
I want to make a query that will look like this:
SELECT * FROM Table
WHERE (Col1=<parameter> AND Col1 IS NULL)
+ (Col2=<parameter> AND Col2 IS NULL)
etc.
I need values that are NULL and that are equal to parameter
Thanks

Your question, specifically the bit "I need values that are NULL and that are equal to parameter", makes no sense. The where clause:
Col1 = <parameter> AND Col1 IS NULL
will never be true, since a column is either NULL or something. It can't be both at the same time.
If you mean you want values that are equal to the parameter OR NULL, you should use:
Col1 = <parameter> OR Col1 IS NULL

Replace the AND with OR in your WHERE statements.
WHERE (Col1=<parameter> OR Col1 IS NULL)
ANd (Col2=<parameter> OR Col2 IS NULL)

Related

How to get results fastly with 'column1+column2=#variable'

I am using SQL Server 2016. I have a table more than 10m rows. When I want to search with the query show here, it is very slow.
CREATE TABLE dbo.table_name
(
Col1 int NOT NULL,
Col2 int NULL,
Col3 char(2) NULL,
Col4 char(15) NULL,
Col5 varchar(8) NULL,
Col6 varchar(12) NULL,
Col7 varchar(8) NULL,
Col8 int NULL,
Col9 int NULL,
Col10 varchar(16) NOT NULL
) ON PRIMARY
SELECT
colum3 + column4
FROM
tablename
WHERE
column3 + column4 = #variable
What index method should I use to speed up this query? (of type varchar in two columns)
Maybe you could consider a computed column and indexing that.
ALTER TABLE dbo.tablename ADD concat_column AS
CONCAT(column1 + column2);
CREATE INDEX ix_concat_column ON dbo.tablename(concat_column)
INCLUDE ...
Not sure an index on the separate columns would be of much help, since it would still have to perform the concat on every pair (think 'Rhy' + 'thm' is the same as 'R' + 'hythm').
There's no nice way to do this - but you have a few options.
The problem is that the query has to concatenate col3 and col4 for every row in the database and compare it to your variable. The concatenation means it won't use an index. The time to do that will increase linearly with the number of rows.
Firstly, if you create indexes on column3 and on column4, and change the query to be
select concat(col3, col4)
from table_name
where (
col3 like left(#variable, 3)
or col4 like left(#variable, 3)
and concat(col3, col4) = #variable
you should get a decent improvement in speed. That's because the first where clause can use an index, and should reduce the total number of rows on which the query has to concatenate col3 and col4. I've suggested the first 3 characters of #variable - adjust that to whatever works.
The second option is to create a view which concatenates column3 and column4 into a new column, and create an index on that column. That should be incredibly fast.
The model suggests that Col3 and Col4 values are always 2 and 15 char in lenght.
If this is the case, you could add an index including both column and using them seperatly in the where clause.
It will remains to figure out how Null values should be handled.
CREATE INDEX idx_myindex ON dbo.tablename(Col1, Col2);
GO
SELECT
Concat(colum3, column4)
FROM
tablename
WHERE
column3 = left(#variable,2) and (column4 = right(#variable,15)
Solution handling Null values based on the same assumptions.
SELECT
Concat(colum3, column4)
FROM
tablename
WHERE
( Len(#variable) = 17 AND
column3 = left(#variable,2) and (column4 = right(#variable,15) )
OR
( Len(#variable) = 2 AND
column3 = #variable AND column4 is null )
OR
( Len(#variable) = 15 AND
column3 is null AND column4 = #variable )

Showing the result of COALESCE into separate columns based from where they where retrieved

I have a table with many NULL values. Therefore I use the COALESCE function to retrieve the NON NULL values. This works fine when the result of the COALESCE is to be placed in a single Column. However I need to place the values of the COALESCE into separate Columns depending from where they where picked.
E.g. I have the following table.
SELECT COALESCE(Col1, Col2, Col3, Col4) FROM Table 1
Will produce:-
Column1
1
1
3
4
However I do not want that result but I want this result:-
Col1 Col2 Col3 Col4
1 - - -
- 1 - -
- - 3 -
- 4 - -
As you can see I want only one field populated (that why I'm suing COALESCE but the result of COALESCE should be placed as illustrated, NOTICE ONE VALUE PER ROW.
Any ideas of how I can achieve this result please.
coalesce can be built with case statements. You need something like the below:
select col1
, case when col1 is not null then null else col2 end 'Col2'
, case when col1 is not null or col2 is not null then null else col3 end 'Col3'
, case when col1 is not null or col2 is not null or col3 is not null then null else col4 end 'Col4'
from table
You can achieve this with a combination of PIVOT, UNPIVOT and ROW_NUMBER.
declare #t table(rn int identity(1,1) primary key, col1 int, col2 int, col3 int, col4 int);
insert #t values (1,null,null,null), (null,1,0,null), (null,null,3,null), (null,4,null,2);
with a as (
select *, ranking = row_number() over (partition by rn order by col)
from #t a
unpivot ([val] for [col] in ([col1],[col2],[col3],[col4])) p
)
select *
from a
pivot (min(val) for [col] in ([col1],[col2],[col3],[col4])) p
where ranking = 1

Select Column is its contain value SQL Server

I have one Audit Table which have Multiple Column,
Lets Say
Create table TestTable ( ID int, Col1 varchar(10), Col2 varchar(10), Col3 varchar(10), Col4 varchar(10), Col5 varchar(10), Col6 varchar(10), Col7 varchar(10));
insert into TestTable values(1,'Ram',null,null,null,null,null,null);
insert into TestTable values(2,null,1,null,'2',null,null,null);
insert into TestTable values(3,null,1,null,'2',null,null,null);
Now I want IF User run below Query
Select *[]* From TestTable where ID=1
Then Output should come like this.
**ID Col1
1 Ram**
and User run below query
Select *[]* From TestTable where ID=2
Then Output should come like this.
**ID Col2 Col4
1 1 2
Column is should not be static, If have value in row that column should come.
Any Idea how to get that results, I need to select the columns dynamically.
It is not impossible to do, but the query to generate that kind of result would be complex and require dynamic generation of the SQL statement.
Filtering which columns should be displayed should rather be the job of your frontend. It would also be hard for any other system to rely on a result set with a dynamic number of column.

Can CHECK constraints act like if else?

I have a table with 4 columns:
(ID (PK, int, NOT NULL), col1 (NULL), col2 (NULL), col3 (NULL))
I'd like to add a CHECK constraint (table-level I think?) so that:
if col1 OR col2 are NOT NULL then col3 must be NULL
and
if col3 is NOT NULL then col1 AND col2 must be NULL
i.e. col3 should be null if col1 and col2 are not null or vice-versa
I am very new to SQL and SQL server though and am not sure how to actually implement this or even if it can/should be implemented?
I think maybe:
CHECK ( (col1 NOT NULL OR col2 NOT NULL AND col3 NULL) OR
(col3 NOT NULL AND col1 NULL AND col2 NULL) )
But I am not sure if the brackets can be used to group the logic like this? If not, how can this best be implemented?
Absolutely, you can do this. See this sqlfiddle.
However, you need to make sure you bracket your logic properly. You should never mix ANDs and ORs in the same bracketing scope. So:
(col1 NOT NULL OR col2 NOT NULL AND col3 NULL)
Needs to become:
((col1 NOT NULL OR col2 NOT NULL) AND col3 NULL)
Or:
(col1 NOT NULL OR (col2 NOT NULL AND col3 NULL))
Depending on your intent.
Just be careful not to make mistake with brackets.
CREATE TABLE Test1 (col1 INT, col2 INT, col3 INT);
ALTER TABLE Test1
ADD CONSTRAINT CHK1
CHECK (((col1 IS NOT NULL OR col2 IS NOT NULL) AND col3 IS NULL) OR
((col1 IS NULL AND col2 IS NULL) AND col3 IS NOT NULL))
INSERT INTO Test1 VALUES (1,1,1); --fail
INSERT INTO Test1 VALUES (1,1,NULL); --good
INSERT INTO Test1 VALUES (1,NULL,NULL); --good
INSERT INTO Test1 VALUES (1,NULL,1); --fail
INSERT INTO Test1 VALUES (NULL,NULL,1); --good
I would say create a UDF like below
create FUNCTION dbo.fn_check_val
(#col1 int , #col2 int , #col3 int)
RETURNS bit
AS
BEGIN
declare #toRet bit
IF(#col1 is Not null OR #col2 is NOT NULL)
Begin
if(#col3 is null)
Begin
Set #toRet = 1
End
Else
Begin
Set #toRet = 0
End
End
Else
if(#col3 is not null)
Begin
Set #toRet = 1
End
Else
Begin
Set #toRet = 0
End
return #toRet
END
and then add following check statement in your table
([dbo].[fn_check_val]([col1],[col2],[col3])=(1))

SQL Server : stored procedure IFNULL check

Solution_id (Primary key, Int)
Col1 (varchar)
Col2 (varchar)
Col3 (varchar)
Col4 (varchar)
Col5 (varchar)
I am writing a stored procedure to update this table. There are 6 input parameters for the above 6 columns.
#Attached_File1 VARCHAR(MAX),
#Attached_File2 VARCHAR(MAX),
#Attached_File3 VARCHAR(MAX),
#Attached_File4 VARCHAR(MAX),
#Attached_File5 VARCHAR(MAX),
#Ticket_ID BIGINT
I want to write a SQL query which will update the table with the values specified in the input parameters. BUT I must not overwrite the attachment columns with null. I mean I need to use only those parameters which contains data.
For example, if the table has a row
[10, "aaa", "bbb", "efg", null, null]
and the input parameters are
(10, null, null, "mno", "ddd", null)
then after the update the row will become
[10, "aaa", "bbb", "mno", "ddd", null]
How to check for null/empty strings and generate the update query accordingly to achieve this?
Is this something like you're after?
UPDATE mytable
SET Col1 = ISNULL(#Attached_File1, Col1),
Col2 = ISNULL(#Attached_File2, Col2),
Col3 = ISNULL(#Attached_File3, Col3),
Col4 = ISNULL(#Attached_File4, Col4),
Col5 = ISNULL(#Attached_File5, Col5)
WHERE Solution_id = #Ticket_ID
ISNULL takes two values, if the first one is not null then it is used, otherwise the 2nd value is used.
See MSDN for more information on ISNULL
Update
I've just noticed your comment at the end, which talks about empty strings...
How to check for null/empty strings and generate the update query accordingly to achieve this?
In which case, you could do the following...
UPDATE mytable
SET Col1 = ISNULL(NULLIF(#Attached_File1,''), Col1),
Col2 = ISNULL(NULLIF(#Attached_File2,''), Col2),
Col3 = ISNULL(NULLIF(#Attached_File3,''), Col3),
Col4 = ISNULL(NULLIF(#Attached_File4,''), Col4),
Col5 = ISNULL(NULLIF(#Attached_File5,''), Col5)
WHERE Solution_id = #Ticket_ID
This uses the NULLIF statement which takes two values, if the first value is the same as the second value, then NULL is returned, otherwise it returns the first value.
See MSDN for more information on NULLIF
update YourTable
set col1 = isnull(#Attached_File1, col1)
, col2 = isnull(#Attached_File2, col2)
, col3 = isnull(#Attached_File3, col3)
, ...
where Solution_ID = #Ticket_ID
If the parameters can contain empty strings, consider #freefaller's answer. If it can contain whitepsace, try:
set col1 = case
when #Attached_File1 like '%[^ \t\r\n]%' then #Attached_File1
else col1
end
, col2 = ...
I would try this:
UPDATE Table
SET
Col1 = ISNULL(#Attached_File1, Col1),
Col2 = ISNULL(#Attached_File1, Col2),
Col3 = ISNULL(#Attached_File1, Col3),
Col4 = ISNULL(#Attached_File1, Col4),
Col5 = ISNULL(#Attached_File1, Col5),
WHERE
Solution_Id = #Ticket_ID
Checking only for Nulls, not for empty strings:
UPDATE
tableX
SET
Col1 = COALESCE(#Attached_File1, Col1),
...
Col5 = COALESCE(#Attached_File5, Col5)
WHERE
Solution_id = #Ticket_ID ;