How to print or select specific rows in SQL - sql

I want to print only the data that starts with a number from a SQL string column. Right now its printing complete string (see image). I only want row 2 and 4 as it contains the data starting with a number.
Here is the sql code:
DECLARE #string2 VARCHAR(MAX)
SET #string2 ='DOB;04 Mar 1199;passport;1234567'
DECLARE #SEP CHAR(1)
SET #SEP=';'
select #string2
SELECT value
FROM STRING_SPLIT(#string2, #sep)

You can try this query:-
SELECT * FROM TableName WHERE ColumnName regexp '^[0-9]+'
The above is MySQL specific.
You can use the below query on SQL Server:

You can use the value in the where clause.
So using the SUBSTRING and the ISNUMERIC functions should solve your problem.

You could extract the first 2 characters and check if they're NUMERIC
DECLARE #string2 VARCHAR(MAX)
DECLARE #SEP CHAR(1)
SET #string2 ='DOB;04 Mar 1199;passport;1234567'
SET #SEP=';'
SELECT [value] FROM
(
SELECT value
FROM STRING_SPLIT(#string2, #sep)
) a
WHERE IsNumeric(left([value],2)) = 1

you can write a query with using MySQL Regex Methods SELECT * FROM table_name WHERE COLUMN_NAME REGEXP '[0-9]'

Related

loop a variable delimited by comma and enter each item to each row of the table SQL

lets say I have the variable x, which is equal to: x='3,4,5,6,7'
Then i have a table #tmpTable with two columns (respID and Responses)
On my #tmpTable the respIDs for each row are null.
I want the ids of each row there to be the values on my x variable above. (for example, row 1's respID=1, row 2's respID=2.. and so on..)
how to do this in SQL?
You can achieve as below using SSMS:
declare #S varchar(20)
set #S = '1,2,3,4,5'
declare #tempTable as table (col1 varchar(max), col2 varchar(max))
While len(#s) > 0
begin
insert into #tempTable(col1) select left(#S, charindex(',', #S+',')-1)
set #S=stuff(#S, 1, charindex(',', #S+','), '')
end
select * from #tempTable
You can do something like this.
SELECT
Responses.value('(/x/#ID)[1]', 'int') AS [ID],
Responses
FROM YourTable
Sorry the image you had in your post has now disappeared so I don't remember the table name or the exact xml. Have a search on google for "tsql xml xpath".

How to split a comma separated data

I have a procedure and input is comma separated like '1,2,3'.
I would like to query like
SELECT * FROM PERSON WHERE PERSON_ID IN(1,2,3).
Please note that PERSON_ID is integer.
I've seen this type of question so often I posted a blog on it here.
Basically you have three options (to the best of my knowledge)
The LIKE version that Gordon Lindoff suggested.
Using a split function like so.
DECLARE #InList varchar(100)
SET #InList = '1,2,3,4'
SELECT MyTable.*
FROM MyTable
JOIN DelimitedSplit8K (#InList,',') SplitString
ON MyTable.Id = SplitString.Item
Or using dynamic SQL.
DECLARE #InList varchar(100)
SET #InList = '1,2,3,4'
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * ' +
'FROM MyTable ' +
'WHERE Id IN ('+#InList+') '
EXEC sp_executesql #sql
SearchList = ',' + inputSearchTerm + ','; /* e.g. inputSearchTerm is '1,2,3' */
SELECT * FROM PERSON WHERE CONTAINS(SearchList, ',' + cast(PERSON_ID as varchar) + ',');
Because contains seems like overkill (it is designed for fuzzy searching and uses a full text index), because charindex() is not standard SQL, and I abhor answers where varchar does not have length, let me give an alternative:
SELECT *
FROM PERSON
WHERE ','+#SearchList+',' like '%,'+cast(PERSON_ID as varchar(255))+',%';
The concatenation of commas for #SearchList makes sure that all values are surrounded by delimiters. These are then put around the particular value, to prevent 1 from matching 10.
Note that this will not be particularly efficient, because it will require a full table scan.
Here's a way of doing it using a recursive CTE:
declare #SearchList varchar(20)
set #SearchList= '1,2,3'
;with cte as
(select case charindex(',',#SearchList)
when 0 then cast(#SearchList as int)
else cast(left(#SearchList,charindex(',',#SearchList)-1) as int)
end searchVal,
case charindex(',',#SearchList)
when 0 then ''
else right(#SearchList,
len(#SearchList)-charindex(',',#SearchList) )
end remainStr
union all
select case charindex(',',remainStr)
when 0 then cast(remainStr as int)
else cast(left(remainStr,charindex(',',remainStr)-1) as int)
end searchVal,
case charindex(',',remainStr)
when 0 then ''
else right(remainStr,
len(remainStr)-charindex(',',remainStr) )
end remainStr
from cte
where remainStr > ''
)
select p.*
from cte
join person p on cte.searchVal = p.person_id
SQLFiddle here.

SQL take just the numeric values from a varchar

Say i have a few fields like the following:
abd738927
jaksm234234
hfk342
ndma0834
jon99322
Type: varchar.
How do I take just the numeric values from this to display:
738927
234234
342
0834
99322
Have tried substring however the data varies in length, and cast didnt work either due to being unable to convert, any ideas?
Here's the example with PATINDEX:
select SUBSTRING(fieldName, PATINDEX('%[0-9]%', fieldName), LEN(fieldName))
This assumes (1) the field WILL have a numeric, (2) the numerics are all grouped together, and (3) the numerics don't have any subsequent characters after them.
Extract only numbers (without using while loop) and check each and every character to see if it is a number and extract it
Declare #s varchar(100),#result varchar(100)
set #s='as4khd0939sdf78'
set #result=''
select
#result=#result+
case when number like '[0-9]' then number else '' end from
(
select substring(#s,number,1) as number from
(
select number from master..spt_values
where type='p' and number between 1 and len(#s)
) as t
) as t
select #result as only_numbers
DECLARE #NonNumeric varchar(1000) = 'RGI000Testing1000'
DECLARE #Index int
SET #Index = 0
while 1=1
begin
set #Index = patindex('%[^0-9]%',#NonNumeric)
if #Index <> 0
begin
SET #NonNumeric = replace(#NonNumeric,substring(#NonNumeric,#Index, 1), '')
end
else
break;
end
select #NonNumeric -- 0001000
Well if you don't want to create a function, you can just something like this:
cast(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(replace(replace(YOUR_COLUMN
,'A',''),'B',''),'C',''),'D',''),'E',''),'F',''),'G',''),'H',''),'I',''),'J','')
,'K',''),'L',''),'M',''),'N',''),'O',''),'P',''),'Q',''),'R',''),'S',''),'T','')
,'U',''),'V',''),'W',''),'X',''),'Y',''),'Z',''),'$',''),',',''),' ','') as float)
I think you're wanting VBA's Val() function. Easy enough to accomplish with IsNumeric()
create function Val
(
#text nvarchar(40)
)
returns float
as begin
-- emulate vba's val() function
declare #result float
declare #tmp varchar(40)
set #tmp = #text
while isnumeric(#tmp) = 0 and len(#tmp)>0 begin
set #tmp=left(#tmp,len(#tmp)-1)
end
set #result = cast(#tmp as float)
return #result
end
select substring(
'jaksm234234',
patindex('%[0-9]%','jaksm234234'),
LEN('jaksm234234')-patindex('%[0-9]%','jaksm234234')+2
)
input table
if you have data like above in the image, then use the below query
select field_3 from table where PATINDEX('%[ ~`!##$%^&*_()=+\|{};",<>/?a-z]%', field_3)=0
Results will be look like this
Result table
Extract only numbers from a string. Returns a string with all the numbers inside. Example: this1is2one345long6789number will return 123456789
CREATE FUNCTION [dbo].[GetOnlyNumbers] (#Temp VARCHAR(1000))
RETURNS VARCHAR (1000) AS BEGIN
DECLARE #KeepValues AS VARCHAR(50)
SET #KeepValues = '%[^0-9]%'
WHILE PATINDEX(#KeepValues, #Temp) > 0
SET #Temp = STUFF(#Temp, PATINDEX(#KeepValues, #Temp), 1, '')
RETURN #Temp
END
A right with patindex for the reverse string works also for those
SELECT [Column],
CAST(RIGHT([Column], PATINDEX('%[0-9][^0-9]%', REVERSE([Column])+' ')) AS INT) as [Num]
FROM (VALUES
('abd738927'),
('jaksm234234'),
('hfk342'),
('ndma0834'),
('jon99322'),
) val([Column])
Column
Num
abd738927
738927
jaksm234234
234234
hfk342
342
ndma0834
834
jon99322
99322

Define variable to use with IN operator (T-SQL)

I have a Transact-SQL query that uses the IN operator. Something like this:
select * from myTable where myColumn in (1,2,3,4)
Is there a way to define a variable to hold the entire list "(1,2,3,4)"? How should I define it?
declare #myList {data type}
set #myList = (1,2,3,4)
select * from myTable where myColumn in #myList
DECLARE #MyList TABLE (Value INT)
INSERT INTO #MyList VALUES (1)
INSERT INTO #MyList VALUES (2)
INSERT INTO #MyList VALUES (3)
INSERT INTO #MyList VALUES (4)
SELECT *
FROM MyTable
WHERE MyColumn IN (SELECT Value FROM #MyList)
DECLARE #mylist TABLE (Id int)
INSERT INTO #mylist
SELECT id FROM (VALUES (1),(2),(3),(4),(5)) AS tbl(id)
SELECT * FROM Mytable WHERE theColumn IN (select id from #mylist)
There are two ways to tackle dynamic csv lists for TSQL queries:
1) Using an inner select
SELECT * FROM myTable WHERE myColumn in (SELECT id FROM myIdTable WHERE id > 10)
2) Using dynamically concatenated TSQL
DECLARE #sql varchar(max)
declare #list varchar(256)
select #list = '1,2,3'
SELECT #sql = 'SELECT * FROM myTable WHERE myColumn in (' + #list + ')'
exec sp_executeSQL #sql
3) A possible third option is table variables. If you have SQl Server 2005 you can use a table variable. If your on Sql Server 2008 you can even pass whole table variables in as a parameter to stored procedures and use it in a join or as a subselect in the IN clause.
DECLARE #list TABLE (Id INT)
INSERT INTO #list(Id)
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
SELECT
*
FROM
myTable
JOIN #list l ON myTable.myColumn = l.Id
SELECT
*
FROM
myTable
WHERE
myColumn IN (SELECT Id FROM #list)
Use a function like this:
CREATE function [dbo].[list_to_table] (#list varchar(4000))
returns #tab table (item varchar(100))
begin
if CHARINDEX(',',#list) = 0 or CHARINDEX(',',#list) is null
begin
insert into #tab (item) values (#list);
return;
end
declare #c_pos int;
declare #n_pos int;
declare #l_pos int;
set #c_pos = 0;
set #n_pos = CHARINDEX(',',#list,#c_pos);
while #n_pos > 0
begin
insert into #tab (item) values (SUBSTRING(#list,#c_pos+1,#n_pos - #c_pos-1));
set #c_pos = #n_pos;
set #l_pos = #n_pos;
set #n_pos = CHARINDEX(',',#list,#c_pos+1);
end;
insert into #tab (item) values (SUBSTRING(#list,#l_pos+1,4000));
return;
end;
Instead of using like, you make an inner join with the table returned by the function:
select * from table_1 where id in ('a','b','c')
becomes
select * from table_1 a inner join [dbo].[list_to_table] ('a,b,c') b on (a.id = b.item)
In an unindexed 1M record table the second version took about half the time...
I know this is old now but TSQL => 2016, you can use STRING_SPLIT:
DECLARE #InList varchar(255) = 'This;Is;My;List';
WITH InList (Item) AS (
SELECT value FROM STRING_SPLIT(#InList, ';')
)
SELECT *
FROM [Table]
WHERE [Item] IN (SELECT Tag FROM InList)
Starting with SQL2017 you can use STRING_SPLIT and do this:
declare #myList nvarchar(MAX)
set #myList = '1,2,3,4'
select * from myTable where myColumn in (select value from STRING_SPLIT(#myList,','))
DECLARE #myList TABLE (Id BIGINT) INSERT INTO #myList(Id) VALUES (1),(2),(3),(4);
select * from myTable where myColumn in(select Id from #myList)
Please note that for long list or production systems it's not recommended to use this way as it may be much more slower than simple INoperator like someColumnName in (1,2,3,4) (tested using 8000+ items list)
slight improvement on #LukeH, there is no need to repeat the "INSERT INTO":
and #realPT's answer - no need to have the SELECT:
DECLARE #MyList TABLE (Value INT)
INSERT INTO #MyList VALUES (1),(2),(3),(4)
SELECT * FROM MyTable
WHERE MyColumn IN (SELECT Value FROM #MyList)
No, there is no such type. But there are some choices:
Dynamically generated queries (sp_executesql)
Temporary tables
Table-type variables (closest thing that there is to a list)
Create an XML string and then convert it to a table with the XML functions (really awkward and roundabout, unless you have an XML to start with)
None of these are really elegant, but that's the best there is.
If you want to do this without using a second table, you can do a LIKE comparison with a CAST:
DECLARE #myList varchar(15)
SET #myList = ',1,2,3,4,'
SELECT *
FROM myTable
WHERE #myList LIKE '%,' + CAST(myColumn AS varchar(15)) + ',%'
If the field you're comparing is already a string then you won't need to CAST.
Surrounding both the column match and each unique value in commas will ensure an exact match. Otherwise, a value of 1 would be found in a list containing ',4,2,15,'
As no one mentioned it before, starting from Sql Server 2016 you can also use json arrays and OPENJSON (Transact-SQL):
declare #filter nvarchar(max) = '[1,2]'
select *
from dbo.Test as t
where
exists (select * from openjson(#filter) as tt where tt.[value] = t.id)
You can test it in
sql fiddle demo
You can also cover more complicated cases with json easier - see Search list of values and range in SQL using WHERE IN clause with SQL variable?
This one uses PATINDEX to match ids from a table to a non-digit delimited integer list.
-- Given a string #myList containing character delimited integers
-- (supports any non digit delimiter)
DECLARE #myList VARCHAR(MAX) = '1,2,3,4,42'
SELECT * FROM [MyTable]
WHERE
-- When the Id is at the leftmost position
-- (nothing to its left and anything to its right after a non digit char)
PATINDEX(CAST([Id] AS VARCHAR)+'[^0-9]%', #myList)>0
OR
-- When the Id is at the rightmost position
-- (anything to its left before a non digit char and nothing to its right)
PATINDEX('%[^0-9]'+CAST([Id] AS VARCHAR), #myList)>0
OR
-- When the Id is between two delimiters
-- (anything to its left and right after two non digit chars)
PATINDEX('%[^0-9]'+CAST([Id] AS VARCHAR)+'[^0-9]%', #myList)>0
OR
-- When the Id is equal to the list
-- (if there is only one Id in the list)
CAST([Id] AS VARCHAR)=#myList
Notes:
when casting as varchar and not specifying byte size in parentheses the default length is 30
% (wildcard) will match any string of zero or more characters
^ (wildcard) not to match
[^0-9] will match any non digit character
PATINDEX is an SQL standard function that returns the position of a pattern in a string
DECLARE #StatusList varchar(MAX);
SET #StatusList='1,2,3,4';
DECLARE #Status SYS_INTEGERS;
INSERT INTO #Status
SELECT Value
FROM dbo.SYS_SPLITTOINTEGERS_FN(#StatusList, ',');
SELECT Value From #Status;
Most of these seem to focus on separating-out each INT into its own parenthetical, for example:
(1),(2),(3), and so on...
That isn't always convenient. Especially since, many times, you already start with a comma-separated list, for example:
(1,2,3,...) and so on...
In these situations, you may care to do something more like this:
DECLARE #ListOfIds TABLE (DocumentId INT);
INSERT INTO #ListOfIds
SELECT Id FROM [dbo].[Document] WHERE Id IN (206,235,255,257,267,365)
SELECT * FROM #ListOfIds
I like this method because, more often than not, I am trying to work with IDs that should already exist in a table.
My experience with a commonly proposed technique offered here,
SELECT * FROM Mytable WHERE myColumn IN (select id from #mylist)
is that it induces a major performance degradation if the primary data table (Mytable) includes a very large number of records. Presumably, that is because the IN operator’s list-subquery is re-executed for every record in the data table.
I’m not seeing any offered solution here that provides the same functional result by avoiding the IN operator entirely. The general problem isn’t a need for a parameterized IN operation, it’s a need for a parameterized inclusion constraint. My favored technique for that is to implement it using an (inner) join:
DECLARE #myList varchar(50) /* BEWARE: if too small, no error, just missing data! */
SET #myList = '1,2,3,4'
SELECT *
FROM myTable
JOIN STRING_SPLIT(#myList,',') MyList_Tbl
ON myColumn = MyList_Tbl.Value
It is so much faster because the generation of the constraint-list table (MyList_Tbl) is executed only once for the entire query execution. Typically, for large data sets, this technique executes at least five times faster than the functionally equivalent parameterized IN operator solutions, like those offered here.
I think you'll have to declare a string and then execute that SQL string.
Have a look at sp_executeSQL

Charindex in SQL doesn't give the desired result

I have a string which is an output from a function, for example: "1,3,16,..,..".
I used the following SQL query and ran it in the query builder in Visual Studio, and it didn't give me any syntax errors.
SELECT ItemID, Name, RelDate, Price, Status FROM item_k WHERE (ItemID = cast(charindex(',', #itemIDs) as int))
I gave 3,16 as the #itemID parameter values, but it didn't give the desired results.
Then I used the following SQL query (without charindex):
SELECT ItemID, Name, RelDate, Price, Status FROM item_k WHERE (ItemID = #itemIDs)
I gave 3 as the #itemID parameter value, and I got a result for it.
I also gave 16 (on a separate occasion) as the #itemID parameter value, and I got a result for it. I conclude that there are values for ItemID 3 & 16.
Why doesn't an SQL query with charindex give me any result?
I can't seem to figure out the issue here, please help.
Here's yet another solution. In my experience, when you have a list of ItemIds as a string of comma separated values, you need a split function. This is very useful to have.
With a split function, you can simply do an INNER JOIN with the results of calling the split function and passing the list of ItemIds and associated delimeter as follows:
DECLARE #ItemIDs varchar(100)
SET #ItemIDs = '1,3,16,22,34,35'
SELECT
ItemID, Name, RelDate, Price, Status
FROM item_k
INNER JOIN dbo.UTILfn_Split(#ItemIDs,',') itemIds
ON itemIds.Value = item_k.ItemID
While this may look complicated at first, it is the more elegant and maintainable solution. Here's the code for creating the dbo.UTILfn_Split function. You need to run this first:
IF EXISTS (SELECT * FROM sysobjects WHERE id =
object_id(N'[dbo].[UTILfn_Split]') AND xtype IN (N'FN', N'IF', N'TF'))
DROP FUNCTION [dbo].[UTILfn_Split]
GO
CREATE FUNCTION dbo.UTILfn_Split
(
#String nvarchar (4000),
#Delimiter nvarchar (10)
)
RETURNS #ValueTable TABLE ([Value] nvarchar(4000))
BEGIN
DECLARE #NextString nvarchar(4000)
DECLARE #Pos int
DECLARE #NextPos int
DECLARE #CommaCheck nvarchar(1)
--Initialize
SET #NextString = ''
SET #CommaCheck = RIGHT(#String,1)
--Check for trailing Comma, if not exists, INSERT
--if (#CommaCheck <> #Delimiter )
SET #String = #String + #Delimiter
--Get position of first Comma
SET #Pos = CHARINDEX(#Delimiter,#String)
SET #NextPos = 1
--Loop while there is still a comma in the String of levels
WHILE (#pos <> 0)
BEGIN
SET #NextString = SUBSTRING(#String,1,#Pos - 1)
INSERT INTO #ValueTable ( [Value]) Values (#NextString)
SET #String = SUBSTRING(#String,#pos +1,LEN(#String))
SET #NextPos = #Pos
SET #pos = CHARINDEX(#Delimiter,#String)
END
RETURN
END
CHARINDEX just returns the postition where the character is found within the string.
So when #ItemIDs is set to '3,16' then your WHERE clause...
WHERE (ItemID = CAST(CHARINDEX(',', #ItemIDs) AS INT))
...is equivalent to...
WHERE ItemID = 2
...because CHARINDEX returns 2 since the comma character is found at position 2 of the string '3,16'.
I'm guessing that (a) you don't have a row in your table where ItemID is 2, and (b) you don't really want the position of the comma to dictate which rows are returned.
You can create a query dynamically that uses the in operator:
declare #Sql varchar(1000)
set #Sql = 'select ItemID, Name, RelDate, Price, Status from item_k where ItemID in (' + #itemIDs + ')'
exec(#Sql)
Be careful with what you send into the procedure, though. As with any dynamic SQL, if the data comes from user input without validation, the procedure is wide open for SQL injection.
Edit:
This is what happens in the query:
First we declare a variable to hold the dynamic query. This is just a varchar variable that is large enough.
In the variable we put the #itemIDs variable between two strings to form the query. The comma separated values is put between the parentheses of the in operator to form an expression similar to: where ItemID in (1,3,16)
Finally the exec command executes the query in the variable.
Try
SELECT ItemID, Name, RelDate, Price, Status FROM item_k WHERE ItemID in (#itemIDs)