MSSQL - WHERE LIKE a part of a string - sql-server

if i hava a variable
declare #tag nvarchar(max) = '1570,20342'
and I wanna select a data ,her field "tag" value is
"1443,1570,3245,20342"
this value is string, and was combined by "1570" and "20342",
how to select that data out ?

Use a subquery to get the string stored in the variable:
Example:
DECLARE #tag NVARCHAR(MAX)
SET #tag = '1570'
SELECT *
FROM TABLE
WHERE COLUMN LIKE (SELECT '%'+#tag+'%')
You won't be able to search for both values in a column without splitting them first. You could do this by using two variables, like:
DECLARE #tag1 NVARCHAR(MAX)
SET #tag1 = '1570'
DECLARE #tag2 NVARCHAR(MAX)
SET #tag2 = '20342'
SELECT *
FROM TABLE
WHERE COLUMN LIKE (SELECT '%'+#tag1+'%')
OR COLUMN LIKE (SELECT '%'+#tag2+'%')
Although this is a quick workaround for this situation, it does not scale well and the only way to fix this would be to normalize your tables, stop using more values separated by commas on one row, instead use one value per row.

Related

How to search by multiple values in "Always Encrypted" column?

If I am using deterministic encryption I am able to perform searches in encrypted column. For example:
DECLARE #email NVARCHAR(222) = 'test';
SELECT *
FROM Users
Where email = #email;
But how to perform searches by multiple values? For example, if I want to get records where email addresses are userA#gmail.com, userB#gmail.com and userC#gmail.com.
I can't create many input parameters because usually the values are dynamic and passed as CSV string, for example.
In you situation, I would recommend splitting if it suits you.
Try this query: Let me know if it works for you
DECLARE #email NVARCHAR(222) = 'userA#gmail.com,userB#gmail.com,userC#gmail.com'
DECLARE #Delimiter NCHAR(1) = ','
DECLARE #EmailParam TABLE(email NVARCHAR(222))
;WITH Split(StPos,EndPos)
AS(
SELECT 0 AS StPos, CHARINDEX(#Delimiter,#email) AS EndPos
UNION ALL
SELECT EndPos+1, CHARINDEX(#Delimiter,#email,EndPos+1)
FROM Split
WHERE EndPos > 0
)
INSERT INTO #EmailParam (email)
SELECT SUBSTRING(#email,StPos,COALESCE(NULLIF(EndPos,0),LEN(#email)+1)-StPos) FROM Split
SELECT Users.*
FROM Users
INNER JOIN #EmailParam EmailParam
ON Users.email = EmailParam.email;
Explanation:
I have just extended your query to deal with multiple emails.
As you mentioned if are sure about input format being comma separated string, it might worth trying to derive table variable from it.
So If your input is like:
DECLARE #email NVARCHAR(222) = 'userA#gmail.com,userB#gmail.com,userC#gmail.com'
You can split it using any tsql technique, I have used common table expression here.
Then once you have it in tabular format. I have got it in table variable named #EmailParam here. You can then easily use add a join and filter it.
if your query works with deterministic encryption, then this query may work in the similar way as only additional change in regard to filer is we have inner join now. ,

SQL Query Results to Local Variable without unique identifier

I'm relatively new to SQL and I'm trying to write a query that will assign the result of multiple rows into a local variable
DECLARE #x VARCHAR(MAX)
SET #x= (SELECT someCol
FROM table)
--Does important stuff to the #x variable
SELECT #x
During my research I realized that this won't work because the subquery can only return one value and my query will return multiple results. However I can not do something like this:
DECLARE #x VARCHAR(MAX)
SET #x= (SELECT someCol
FROM table
where id= 'uniqueIdentifier')
--Does important stuff to the #x variable
SELECT #x
The reason I can't use a where clause is that I need to do this for the entire table and not just one row. Any ideas?
EDIT: I realized my question was too broad so I'll try to reformat the code to give some context
SELECT col_ID, col_Definition
FROM myTable
If I were to run this query col_Definition would return a large varchar which holds a lot of information such as the primary key of another table that I'm trying to obtain. Lets say for example I did:
DECLARE #x VARCHAR(MAX)
SET #x= (SELECT col_Definition
FROM myTable
WHERE col_ID = 1)
--Function to do the filtering of the varchar variable that works as expected
SELECT #x as [Pk of another table] --returns filtered col_Definition
This will work as expected because it returns a single row. However, I would like to be able to run this query so that it will return the filtered varchar for every single row in the "myTable" table.
If I understand correctly, you store a PK embedded in a string that you want to eventually get out and use to join to that table. I would think putting the group of records you want to work with into a temp table and then applying some logic to that varchar column to get the PK. That logic is best as set based, but if you really want row by row, use a scalar function rather than a variable and apply it to the temp table:
select pk_column, dbo.scalarfunction(pk_column) as RowByRowWithFunction, substring(pk_column,5,10) as SetBasedMuchFaster
from #tempTable.
You need to define what the 'uniqueIdentifier' is first.
Not sure about using a subquery and grabbing the result and executing another query with that result unless you do an INNER JOIN of some sort or if using python or another language to process the data then use:
("SELECT someCol
FROM table
where id='%s'" % Id)

Does REPLACE function in SQL Server accept input from a table for 'string_pattern' parameter?

I'm still learning my ropes with SQL Server and maybe this question sounds very naive/ridiculous. Please bear with me on this. :)
I saw a function in SQL Server defined as below:
CREATE FUNCTION [dbo].[fn_CleanNumeric]
(
#InputString VARCHAR(500)
)
RETURNS NVARCHAR(500)
as
BEGIN
SELECT
#InputString = REPLACE(#InputString, n.Symbol, '')
FROM
NonNumeric n
RETURN #InputString
END
NonNumeric is a table with a column named, [Symbol], containing a bunch of non-numeric ASCII characters. From looking at SQL Server documentation for REPLACE, I don't think it (REPLACE) accepts a table's column nor does it seem to accept a cursor. Is it because we are using REPLACE in function context? If someone could point me to a good resource that explains it, I'd greatly appreciate that.
Thank you in advance!
This is a hacky trick called Quirky Update
This is slow and in most cases something one should avoid
Some examples:
DECLARE #tbl TABLE(SomeInt INT);
INSERT INTO #tbl VALUES (1),(2),(3);
DECLARE #SumOfInts INT=0
SELECT #SumOfInts = #SumOfInts + SomeInt FROM #tbl;
SELECT #SumOfInts; --SELECT SUM(SomeInt) FROM #tbl is clearly better...)
String concatenation
DECLARE #tbl2 TABLE(SomeText VARCHAR(100));
INSERT INTO #tbl2 VALUES ('a'),('b'),('c');
DECLARE #ConcatString VARCHAR(100)='';
SELECT #ConcatString = #ConcatString + ', ' + SomeText FROM #tbl2;
SELECT #ConcatString;
Better was the usual approach with FOR XML PATH('') and STUFF(), which is a hacky workaround too. (Newer versions will bring a built-in function at last!)
With REPLACE it works!
This Quirky Update is the only way I know to use a table's values for a step-by-step replacement of many values you can maintain in a table dynamically:
Look at this:
DECLARE #ReplaceValues TABLE(this VARCHAR(100),[by] VARCHAR(100));
INSERT INTO #ReplaceValues VALUES('$',' Dollar'),('€',' Euro'),('abbr.','abbreviations');
DECLARE #SomeText VARCHAR(MAX)=
'This text is about 100 $ or 100 € and shows how to replace abbr.!';
SELECT #SomeText=REPLACE(#SomeText,this,[by]) FROM #ReplaceValues;
SELECT #SomeText;
The result
--This text is about 100 Dollar or 100 Euro and shows how to replace abbreviations!
In general, yes you can use the value from a column for any place in SQL Server's syntax where a value is expected (as opposed to where a name is expected, such as the first argument to DATEPART).
However, this is broken code - it appears to assume that each row will be evaluated in sequence and each row will be evaluated using values produced from previous rows. However, SQL Server only guarantees to perform one assignment (for the "last" row - however, with no ORDER BY clause, "last" is ill-defined):
If the SELECT statement returns more than one value, the variable is assigned the last value that is returned.
Whether it may appear to work is no guarantee that more than a single assignment will actually take place.
Replace accepts the table column, and in this case it will do exactly what you expect it to do. It will do iterations on #InputString variable and exclude all non numeric characters that appear in the NonNumeric table and in the #InputString variable.
Actually it will work with the table column and do a replace for each row in your table. But it only work because the #InputString variable is affected each time.
Maybe you could use a local temporary table to store your NonNumeric
Be carefull because you are returning a NVARCHAR value while #InputString is a VARCHAR.
A simple code to show you that the REPLACE can accept values from a table
CREATE TABLE dbo.Test
(
RowID INT IDENTITY(1,1),
Test VARCHAR(20)
)
GO
INSERT INTO dbo.Test VALUES ('James')
INSERT INTO dbo.Test VALUES ('John')
GO
ALTER FUNCTION [dbo].[fn_CleanNumeric]
(
#InputString VARCHAR(500),
#Test VARCHAR(500)
)
RETURNS TABLE
AS
RETURN(
SELECT
REPLACE(#InputString, n.Test, '') AS Test
FROM
dbo.Test n WHERE Test = #Test)
GO
SELECT * FROM [dbo].[fn_CleanNumeric] ('TestJohn','John')
Result
Test
--------
TestT
The SELECT takes a random value and will check for that string pattern in the variable #InputString, thus passing a #Test variable ensures to REPLACE the right string pattern

How to INSERT INTO table column with string/variable

This is the data I have pulled from powershell and inserted it into a #temptable:
Name : SULESRKMA
Location : Leisure Services - Technology Services
Shared : False
ShareName :
JobCountSinceLastReset : 0
PrinterState : 131072
Status : Degraded
Network : False
I'm while looping through the data and have stripped the values from the identifiers. I'd like to use these identifiers to insert the values into a table with identical Column names to the identifiers. So for example, I have a variable called #identifier = "Name" and a temp table #printers with a column name of Name. I'd like to do something like:
SELECT --select statement
INSERT INTO #printers(#identifier)
But This doesn't seem to work, unsurprisingly. Is there a way to accomplish this? (The #identifier variable will be changing to the other identifiers in the data throughout the course of the while loop.)
Any alternate suggestions that don't even involve using this sort of method are welcome. My ultimate goal is just to get this data as a row into a table.
(I'm currently using Microsoft SQL Server Management Studio if that matters)
First, it's unlikely you need to loop over anything in this situation. Think set based operations when you think about SQL.
INSERT INTO #temptable (Column1Name, Column2Name, Column3Name)
VALUES (#identifer, #anotherIdentifier, #someOtherIdentifier)
--optional clauses
WHERE Column1Name = 'some value' OR Column1Name = #someIdentifier
Or you can SELECT INTO
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier
INTO #temptable
It's important that you have a value in your SELECT INTO for each column in the table which you are trying to add the data to. So, for example, if there were 4 columns in #temptable and you only had 3 values to insert (columns 1, 2 , and 3) then you'd need to NULL column 4 or set it statically.
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
NULL
INTO #temptable
--or
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
'static value'
INTO #temptable
EDIT
If you want to use a varible to speciy the column that you want to insert into, you have to use dynamic sql. Here is an example:
if object_id ('tempdb..#tempTable') is not null drop table #tempTable
create table #tempTable (Column1Name int, Column2Name int, Column3Name int)
declare #columnName varchar(64) = 'Column1Name'
declare #sql varchar(max)
set #sql =
'insert into #tempTable (' + #columnName + ')
select 1'
exec(#sql)
select * from #tempTable

SQL Server doesn't use index while chekcing the value of input parameters [duplicate]

I will have a table
TABLE1
ID Name Country
1 Anna Singapore
2 Brad UK
3 Cassie US
declare #place varchar(20);
set #place='US';
select * from Table1 where country=#place;
what if the value is #place is null???
then, the select will not select anything..
what I want is to treat as there is no where statement for country. while if there's other where statements, they will work..
Any idea how to do that??
For this simple case in your question just use
IF ( #place IS NULL )
SELECT *
FROM table1
ELSE
SELECT *
FROM table1
WHERE country = #place
If your actual situation is more complex you could use
select *
from Table1
where #place is null or country=#place
option (recompile)
The reason for needing the recompile hint is to avoid having a single plan catering for both cases and doing an unnecessary scan in the event that you do supply an explicit value.
These, and other alternatives such as generating the query dynamically, are discussed in detail in the article Dynamic Search Conditions in T-SQL
like and = are equivalent in your situation because you are dealing with text (char, nchar, varchar, nvarchar) values.
Instead of
WHERE country = #place
try
WHERE country like #place
For the variable set try
Instead of
set #place='US'
Try
set #country = isnull('''US''','''%''')
To test this:
declare #country nvarchar(50)
set #country = isnull('''US''','''%''')
print #Country
set #country = isnull(NULL,'''%''')
print #Country
The extra quotes are necessary because in your example you are using explicit values - ' is an escape character and you need a single quote around each value to signify it is NOT a table column. If you were using the COLUMN_NAME you would simply use a single quote around the % character.
Depending on your SQL version you may have to use a different wildcard character.
This is fairly a fairly direct and linear solution, although there are risks associated with open variables.

Resources