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

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 )

Related

How to check all the columns are 0 in SQL Server without specifying all columns with OR condition?

I want to return an error flag when all columns are 0s in a temp table.
Is there any good method other than specifying all columns checking to 0 with OR condition?
An OUTER APPLY can be used to calculate the flag.
For example, from this sample data:
create table #test (
id int identity(1,1) primary key,
col1 int not null,
col2 float,
col3 decimal(10,2)
);
insert into #test (col1, col2, col3) values
(1,0,0),(0,0.2,0),(0,null,0.3),(0,0,null),(0,0,0);
This query:
-- sum of nums check
select *
from #test t
outer apply (
select cast(iif(sum(abs(v.num))>0,0,1) as bit) as AllZeroOrNullFlag
from (values (col1),(col2),(col3)) v(num)
) ca
where ca.AllZeroOrNullFlag = 1;
Returns:
id col1 col2 col3 AllZeroOrNullFlag
4 0 0 NULL True
5 0 0 0,00 True
Without more information at the moment, all I can suggest you is the following :
SELECT id, 'ERROR'
FROM temp
WHERE value1+value2+value3 = 0;
Assuming you can provide all numeric columns that you would have checked in OR condition. (EDIT: In fact it would have been AND condition instead of OR...)
SEE A DEMO HERE

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

SQL Check constraint on column referencing other columns

I want to limit a column that it can only have a value when another column has a value.
example: (this doesn't work)
create table testConstraint (
col1 int not null identity(1, 1) primary key,
col2 int,
col3 int check (col2 is not null),
col4 int)
This is not possible because he cannot reference another column.
Error:
Column CHECK constraint for column 'col3' references another column,
table 'testConstraint'.
Another try was: (also doesn't work)
create table testConstraint (
col1 int not null identity(1, 1) primary key,
col2 int,
col3 int,
col4 int)
GO
alter table testConstraint add constraint ck_columnNotNull check (case when col2 is null then col3 is null end)
GO
Anyone have an idea how this would be possible with a constraint?
You can write a trigger.
Also, you can try this
(1)
ALTER TABLE TestConstraint ADD CONSTRAINT
CK_TestConstraint CHECK (NOT ( (col3 is not null) and (col2 is null) ))
GO
or this
(2)
ALTER TABLE TestConstraint ADD CONSTRAINT
CK_TestConstraint CHECK
(
((col3 is not null) and (col2 is not null)) or
((col3 is null) and (col2 is null))
)
GO
depending on what exactly you need.
I just tested it and it works OK, I think.
insert into
TestConstraint
(col2, col3, col4)
values
(null, 1, 2)
-- ERROR
insert into
TestConstraint
(col2, col3, col4)
values
(1, 1, 2)
-- OK
ALTER TABLE testConstraint
ADD CONSTRAINT ck_columnNotNull
CHECK ( 1 = CASE
WHEN col2 IS NULL AND col3 IS NULL THEN 1
WHEN col2 IS NOT NULL AND col3 IS NOT NULL THEN 1
ELSE 0
END)
Only simple logic is required, plus it needs (as per your second attempt) to be a table check constraint, so you can't declare it inline with the declaration of col3:
create table testConstraint (
col1 int not null identity(1, 1) primary key,
col2 int,
col3 int,
col4 int)
GO
alter table testConstraint add constraint ck_columnNotNull check (
col3 is null
or col2 is not null
)
GO
If col3 is null, then we don't care what the value of col2 is. Conversely, if it's not NULL, then we do want to enforce the col2 isn't null. That's what the two sides of the or effectively give us.

SQL Column 2 change from NULL to NOT NULL if the value of Column 1 is 1

I have an sql table with let say col1 and col2, i want to create a constraint or a trigger (whatever works) such that col2 should change from NULL to Not Null if and only if the value entered in col1 is 1.
The point is, i want to make a col2 field mandatory if col1 is set to 1 otherwise remain optional.
You mention SQL Server in a comment
CREATE TABLE YourTable
(
Col1 INT,
Col2 VARCHAR(25) NULL,
CONSTRAINT ck_foo CHECK (NOT (Col1 = 1 AND Col2 IS NULL))
);
would disallow NULL as stated in the question. To also disallow empty strings the constraint definition could be
CONSTRAINT ck_foo CHECK (NOT (Col1 = 1 AND ISNULL(Col2,'') = ''))
ALTER TABLE YourTable WITH CHECK ADD CONSTRAINT [CK_YourTable] CHECK (([col1]=(1) AND [col2] IS NOT NULL OR [col1]<>(1)))
GO
If you want to exclude empty string too then:
ALTER TABLE YourTable WITH CHECK ADD CONSTRAINT [CK_YourTable] CHECK (([col1]=(1) AND ( [col2] IS NOT NULL AND [col2] <> '') OR [col1]<>(1)))
GO

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 ;