Better way to write "like operator" in SQL Server - sql-server

Is there any better way to re-write the below code?
SELECT *
FROM PROFILE
WHERE GRP_NUMBER NOT LIKE '2%' AND GRP_NUMBER NOT LIKE '7%'

SELECT *
FROM PROFILE
WHERE GRP_NUMBER LIKE '[^27]%'

Try below sample
DECLARE #Table TABLE(
Col VARCHAR(50)
)
INSERT INTO #Table SELECT '2ABC'
INSERT INTO #Table SELECT '4Italy2'
INSERT INTO #Table SELECT '3Apple'
INSERT INTO #Table SELECT '234.62'
INSERT INTO #Table SELECT '2:234:43:22'
INSERT INTO #Table SELECT '7'
INSERT INTO #Table SELECT '6425.23'
INSERT INTO #Table SELECT '2'
INSERT INTO #Table SELECT 'Lions'
SELECT * FROM #Table
WHERE Col NOT LIKE '[27]%'

SELECT *
FROM PROFILE
WHERE GRP_NUMBER NOT LIKE '[27]%'

Related

Passing multiple values into variable

I'm trying to pass a value from a table into a variable which I can then use in a query. The problem is that I need the variable to have multiple values, which I've never done before. Below is an example of what I'm trying to do.
CompanyID has multiple values for control number. How would I be able to pass multiple values into the variable? The query I'm using is using Open Query so I can't join to a temp table.
declare #t table( companyid int, control_number int)
insert into #t
values(5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
select *
from #t
declare #CN int
set #CN = (select control_number from #t where companyid = 5555)
select *
from #table
where control_number IN(#CN)
Instead of setting it into variable you can directly use it IN like this :
declare #t table( companyid int, control_number int)
insert into #t
values(5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
select *
from #t
select *
from #table
where control_number IN(select control_number from #t where companyid = 5555)
Try this out I haven't able to run this because you haven.t shared schema of #table
Another way to skin the cat. Make your second variable a table variable. Then just join to it.
declare #CN table (cntNbr int)
insert #CN (cntNbr)
select control_number from #t where companyid = 5555;
select t.*
from #t as t
join #CN as c
on c.cntNbr = t.control_number;
Rextester link: https://rextester.com/SCYCX42852
Method 1 (Dynamic SQL):
CREATE TABLE #temp ( companyid INT, control_number INT )
INSERT INTO #temp
VALUES (5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
SELECT * FROM #temp
DECLARE #controlNum VARCHAR(MAX)
SELECT #controlNum = ISNULL(#controlNum + ', ', '') + CAST(control_number AS VARCHAR) FROM #temp WHERE companyid = 5555
DECLARE #sql NVARCHAR(MAX) = 'SELECT * FROM #temp WHERE control_number IN ( ' + #controlNum + ')'
EXEC sp_executesql #sql
Method 2:
DECLARE #temp TABLE( companyid INT, control_number INT )
INSERT INTO #temp
VALUES (5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
SELECT * FROM #temp
SELECT * FROM #temp WHERE control_number IN (SELECT control_number FROM #temp WHERE companyid = 5555)

How to create a SQL procedure to union tables from a growing list of tables In SQLserver

I need to consolidate information from multiple tables into a single table. The issue is new tables are being created and I have no control over when they are created or what they are called other than the beginning part of the name.
I would love it if this worked:
Select t.name
into #aReading
from sys.tables as t
where t.name like 'Fast_a%'
Select *
from (Select name from #aReading)
This works but constantly needs new tables added
Insert (col1, col2) into TestTable
Select x.* from (col1,col2
from test1
union
Select col1,col2
from test1_01022019
union
Select col1,col2
from test1_09122019 ) x
I am still learning SQL and not very good with While but thought that might be the answer.
Here's a dynamic SQL example (e.g. build the query as a string and then use built in procedure sp_executesql to execute the query).
This example uses STUFF and FOR XML PATH('') to concatenate a bunch of queries together and stick ' UNION ' between each one.
DECLARE #sql NVARCHAR(MAX) = 'INSERT INTO TestTable (col1, col2) '
SELECT #sql += STUFF(
(SELECT ' UNION SELECT col1, col2 FROM ' + t.name
FROM sys.tables as t
WHERE t.name like 'Fast_a%'
FOR XML PATH('')), 1, 7, '')
EXEC sp_executesql #sql
So, for this schema:
CREATE TABLE fast_a1 (col1 INT, col2 INT)
CREATE TABLE fast_a2 (col1 INT, col2 INT)
CREATE TABLE fast_aasdf (col1 INT, col2 INT)
CREATE TABLE TestTable (col1 INT, col2 INT)
It builds this dynamic query:
INSERT INTO TestTable (col1, col2)
SELECT col1, col2 FROM fast_a1
UNION
SELECT col1, col2 FROM fast_a2
UNION
SELECT col1, col2 FROM fast_aasdf
Edit:
Liz, run these statements (or here's a SQL fiddle) in sequence, and you'll see that they do insert data:
CREATE TABLE fast_a1 (col1 INT, col2 INT);
CREATE TABLE fast_a2 (col1 INT, col2 INT);
CREATE TABLE fast_aasdf (col1 INT, col2 INT);
CREATE TABLE TestTable (col1 INT, col2 INT);
INSERT INTO dbo.fast_a1 VALUES (1, 1);
INSERT INTO dbo.fast_a2 VALUES (2, 2);
INSERT INTO dbo.fast_aasdf VALUES (3, 3);
DECLARE #sql NVARCHAR(MAX) = 'INSERT INTO TestTable (col1, col2) '
SELECT #sql += STUFF(
(SELECT ' UNION SELECT col1, col2 FROM ' + t.name
FROM sys.tables as t
WHERE t.name like 'Fast_a%'
FOR XML PATH('')), 1, 7, '')
EXEC sp_executesql #sql
SELECT * FROM dbo.TestTable
Returns:
col1 col2
1 1
2 2
3 3

SQL IF and ELSE block with temp tables inside

I got a quite big query with CTEs, temp tables and I'd like to put it into IF and ELSE blocks, for having different conditions for both of them, depend on parameter. In simplified it looks as below:
DECLARE #parameter varchar(15)
If(OBJECT_ID('tempdb..#table1') Is Not Null)
Begin
Drop Table #table1
End
create table #table1
(
column1
column2
column3
)
If(OBJECT_ID('tempdb..#table2') Is Not Null)
Begin
Drop Table #table2
End
create table #table2
(
column1
column2
column3
)
IF #parameter = 'Option1' BEGIN
select * from (
INSERT INTO #table1
select * from... where 'condition_for_Option1'
INSERT INTO #table2
select * from... where 'condition_for_Option1'
select * from #table1
union all
select * from #table2) as DATA
END ELSE
IF #parameter = 'Option2' BEGIN
SELECT *
FROM
(
INSERT INTO #table1
select * from... where 'condition_for_Option2'
INSERT INTO #table2
select * from... where 'condition_for_Option2'
select * from #table1
union all
select * from #table2)
as DATA
END
I put the #temp tables at the beginning and it fixed a part of issues, but I still got:
Msg 156, Level 15, State 1, Line 31
Incorrect syntax near the keyword 'INSERT'.
Msg 102, Level 15, State 1, Line 37
Incorrect syntax near ')'.
Msg 156, Level 15, State 1, Line 48
Incorrect syntax near the keyword 'INSERT'.
Msg 102, Level 15, State 1, Line 54
Incorrect syntax near ')'.
Is this any way how to make this work?
You can not have insert statement in select statement. Actualy you can rewrite:
IF #parameter = 'Option1'
BEGIN
INSERT INTO #table1
SELECT * FROM... WHERE 'condition_for_Option1'
INSERT INTO #table2
SELECT * FROM... WHERE 'condition_for_Option1'
SELECT * FROM #table1
UNION ALL
SELECT * FROM #table2
END
ELSE IF #parameter = 'Option2'
BEGIN
INSERT INTO #table1
SELECT * FROM... WHERE 'condition_for_Option2'
INSERT INTO #table2
SELECT * FROM... WHERE 'condition_for_Option2'
SELECT * FROM #table1
UNION ALL
SELECT * FROM #table2
END
but I can't see any usage of temp table here, so you can rewrite:
IF #parameter = 'Option1'
BEGIN
SELECT * FROM... WHERE 'condition_for_Option1'
UNION ALL
SELECT * FROM... WHERE 'condition_for_Option1'
END
ELSE IF #parameter = 'Option2'
BEGIN
SELECT * FROM... WHERE 'condition_for_Option2'
UNION ALL
SELECT * FROM... WHERE 'condition_for_Option2'
END
Why not this ?
IF #parameter = 'Option1' BEGIN
INSERT INTO #table1
select * from... where 'condition_for_Option1'
INSERT INTO #table2
select * from... where 'condition_for_Option1'
select * from (
select * from #table1
union all
select * from #table2) as DATA
END
ELSE
IF #parameter = 'Option2' BEGIN
INSERT INTO #table1
select * from... where 'condition_for_Option2'
INSERT INTO #table2
select * from... where 'condition_for_Option2'
SELECT *
FROM
(
select * from #table1
union all
select * from #table2)
as DATA
END

Concatenating Value in Update

Ok, I have been banging my head against the wall for about 20 minutes and I can't seem to figure this one out. I have two tables each with a common field (ID) and what I want to do is to concatenate the values form #T2's UDValue column into #T1's UDValue column
CREATE TABLE #T1(ID INT, UDValue NVARCHAR(50))
CREATE TABLE #T2(ID INT, UDValue NVARCHAR(50))
INSERT INTO #T1(ID)
VALUES(1)
INSERT INTO #T2(ID, UDValue)
VALUES(1, 'Tom')
,(1, 'Dick')
,(1, 'Harry')
,(2, 'Chevy')
,(3, 'Apple')
,(2, 'Ford')
UPDATE #T1
SET UDValue = COALESCE(t1.UDValue, '') + t2.UDValue + ','
FROM
#T1 AS t1
INNER JOIN #T2 AS t2 ON t2.ID = t1.ID
SELECT * FROM #T1
DROP TABLE #T1
DROP TABLE #T2
So what I am looking for is to see my data like this:
ID UDValue
1, Tom,Dick,Harry
2, Chevy,Ford
3, Apple
but this is what I am getting:
ID UDValue
1 Tom,
2 Chevy,
3 Apple,
I want to avoid having to loop through each row but I don't see any alternatives.
you can use stuff with for xml path to concatenate column values
you can use a corelated sub query to get the comma separated values
Also it is not a good idea to store it as comma separated values in the database.
;with cte
as
(
select ID,
stuff((select ','+ T2.UDValue
from #T2 T2
where T2.ID = T1.ID
FOR XML PATH ('')), 1,1,'') as NewValue
from #T1 T1
)
update #T1
set UDValue = cte.NewValue
from cte
join #T1
on cte.ID = #T1.ID
select * from #T1
Concatenating Value in Update:
create table #T (Id int, Value varchar(50), primary key (Id, value));
declare #Id int;
declare #Value varchar(500);
insert into #T
( Id , Value )
values
( 1 , 'Tom' ),
( 1 , 'Dick' ),
( 1 , 'Harry' ),
( 2 , 'Chevy' ),
( 3 , 'Apple' ),
( 2 , 'Ford' );
update #T set
#Value = case when #Id is null or #Id = Id then #Value else null end,
#Value = Value = coalesce(#Value + ', ', '') + Value,
#Id = Id;
select Id, max(Value) from #T group by Id;
drop table #T;
The example works only if "primary key" is defined on the table.
More about "Quirky Update" is in Solving the Running Total and Ordinal Rank Problems
This is what I have come up with so far but I am not sure that it is the most efficient way to do this:
CREATE TABLE #T1(ID INT, UDValue NVARCHAR(50))
CREATE TABLE #T2(ID INT, UDValue NVARCHAR(50))
INSERT INTO #T1(ID)
VALUES(1)
,(2)
,(3)
INSERT INTO #T2(ID, UDValue)
VALUES(1, 'Tom')
,(1, 'Dick')
,(1, 'Harry')
,(2, 'Chevy')
,(3, 'Apple')
,(2, 'Ford')
DECLARE #id INT = 1, #UDValue NVARCHAR(MAX)
WHILE(#ID < 4)
BEGIN
SELECT #UDValue = STUFF((SELECT DISTINCT N',' + UDValue
FROM
#T2
WHERE ID = #ID
ORDER BY N',' + UDValue
FOR XML PATH(''), TYPE
).value(N'.[1]',N'nvarchar(max)'),1,1,'');
UPDATE #T1
SET UDValue = #UDValue
FROM
#T1 AS t1
WHERE
t1.ID = #ID
SELECT #ID += 1
END
SELECT * FROM #T1
DROP TABLE #T1
DROP TABLE #T2

How to filter records when filter is a comma separated list of values

I have a table which has a column in it containing a string of comma separated values (CSV).
e.g. VALUE1, VALUE2, VALUE3
Being passed in as a filter is another set of CSV.
e.g. VALUE2, VALUE3
So in the example above, the query should return any records where any of the filter values are in the CSV column.
Example
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1, VALUE2, VALUE3')
insert into #table values (2,'VALUE1, VALUE2')
insert into #table values (3,'VALUE1, VALUE3')
insert into #table values (4,'VALUE3, VALUE4')
insert into #table values (5,'VALUE1, VALUE2, VALUE3')
insert into #table values (6,'VALUE3, VALUE4, VALUE2')
insert into #table values (7,'VALUE3')
declare #Filter nvarchar(50)
set #Filter = 'VALUE1,VALUE2'
select * from #table
So in the example above, rows 1, 2, 3, 5 and 6 should be returned by a query as they all contain either VALUE1 or VALUE2.
If I well understood it, this will solve it:
You create a function to do the split:
CREATE FUNCTION [dbo].[ufn_CSVToTable] ( #StringInput VARCHAR(8000), #Delimiter nvarchar(1))
RETURNS #OutputTable TABLE ( [String] VARCHAR(10) )
AS
BEGIN
DECLARE #String VARCHAR(10)
WHILE LEN(#StringInput) > 0
BEGIN
SET #String = LEFT(#StringInput,
ISNULL(NULLIF(CHARINDEX(#Delimiter, #StringInput) - 1, -1),
LEN(#StringInput)))
SET #StringInput = SUBSTRING(#StringInput,
ISNULL(NULLIF(CHARINDEX(#Delimiter, #StringInput), 0),
LEN(#StringInput)) + 1, LEN(#StringInput))
INSERT INTO #OutputTable ( [String] )
VALUES ( #String )
END
RETURN
END
GO
Then you can do this:
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1, VALUE2, VALUE3')
insert into #table values (2,'VALUE1, VALUE2')
insert into #table values (3,'VALUE1, VALUE3')
insert into #table values (4,'VALUE2, VALUE3')
insert into #table values (5,'VALUE1, VALUE2, VALUE3')
insert into #table values (6,'VALUE3, VALUE1, VALUE2')
insert into #table values (7,'VALUE2, VALUE1')
declare #Filter nvarchar(50)
set #Filter = 'VALUE3,VALUE4'
select * from #table
SELECT * INTO #FilterTable FROM ufn_CSVToTable(#Filter, ',')
SELECT * FROM #FilterTable
select * from #table where EXISTS(SELECT String FROM #FilterTable WHERE csv like '%' + String + '%')
DROP TABLE #FilterTable
I'm considering the description "return any rown containing any of the calues in the filter"
You can use the PatIndex to find out the pattern in the field. Like the Following :
SELECT * FROM #TABLE WHERE PATINDEX('%'+#FILTER+'%',CSV)>0
What about this now? I didn't have used any User defined functions at all.
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1,VALUE2,VALUE3')
insert into #table values (2,'VALUE1,VALUE2')
insert into #table values (3,'VALUE1,VALUE3')
insert into #table values (4,'VALUE2,VALUE3')
insert into #table values (5,'VALUE1,VALUE2,VALUE3')
insert into #table values (6,'VALUE3,VALUE1,VALUE2')
insert into #table values (7,'VALUE2,VALUE1')
DECLARE #FILTER VARCHAR(50)
DECLARE #IN VARCHAR(MAX)
SET #FILTER='VALUE1,VALUE2'
SET #IN=REPLACE(#FILTER,',','%')
SET #IN='%'+#IN+'%'
SELECT #IN
SELECT * FROM #table WHERE PATINDEX(#IN,RTRIM(LTRIM(CSV))) >0
Try this one -
DECLARE #table TABLE (rownum INT, csv NVARCHAR(300))
INSERT INTO #table
VALUES
(1,'VALUE1, VALUE2, VALUE3')
, (2,'VALUE1, VALUE2')
, (3,'VALUE1, VALUE3')
, (4,'VALUE2, VALUE3')
, (5,'VALUE1, VALUE2, VALUE3')
, (6,'VALUE3, VALUE1, VALUE2')
, (7,'VALUE2, VALUE1')
DECLARE #Filter NVARCHAR(50)
SELECT #Filter = 'VALUE1,VALUE2'
;WITH cte AS
(
SELECT token = SUBSTRING(
t.string
, n.number + 1
, ABS(CHARINDEX(',', t.string, n.number + 1) - n.number - 1))
FROM ( SELECT string = ',' + #Filter ) t
CROSS JOIN [master].dbo.spt_values n
WHERE n.[type] = 'p'
AND n.number <= LEN(t.string)
AND SUBSTRING(t.string, n.number, 1) = ','
)
SELECT DISTINCT rownum, csv
FROM cte
JOIN #table ON PATINDEX('%'+ token +'%', CSV) = 0
I just modified #JoseTeixeira code using STRING_SPLIT function.
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1, VALUE2, VALUE3')
insert into #table values (2,'VALUE1, VALUE2')
insert into #table values (3,'VALUE1, VALUE3')
insert into #table values (4,'VALUE2, VALUE3')
insert into #table values (5,'VALUE1, VALUE2, VALUE3')
insert into #table values (6,'VALUE3, VALUE1, VALUE2')
insert into #table values (7,'VALUE2, VALUE1')
declare #Filter nvarchar(50)
set #Filter = 'VALUE3,VALUE4'
--select * from #table
select * from #table where EXISTS(SELECT [value] FROM string_split(#Filter, ',')
WHERE csv like '%' + [value] + '%') -- Table with filtered records

Resources