Conversion Failed String to Integer in SQL - sql-server

I have stored the OrganisationIds 1 ,2 in #String variables.i want to convert it into Integer.Can anyone please help?
Below is my code..
DECLARE #RowCount INT
Declare #String varchar(100)
declare #OrganizationIds int
SELECT #RowCount = COUNT(*) FROM #RawData
WHILE (#RowCount>0)
BEGIN
set #String=convert(varchar,#OrganizationIds)+','
If (#RowCount>0)
Begin
PRINT 'Loop Sequence : ' + convert(varchar,#RowCount) + ' '
set #OrganizationIds = (SELECT OrgId FROM #RawData WHERE ROWID = #RowCount)
PRINT 'Orgid Inside Loop:' + Convert(varchar,#OrganizationIds)
End
Set #RowCount = #RowCount-1
Set #OrganizationIds = convert(varchar,#OrganizationIds)
PRINT 'Orgid Outside Loop:'+ convert(varchar,#OrganizationIds)
set #String=#String + Convert(varchar,#OrganizationIds)
END
PRINT 'String Value Outside Loop: ' + #String
Declare #TempData Table
(
OrganizationID int
)
insert into #TempData(OrganizationID)
EXEC GetFormsData_Organization #String

I believe you have to use the CAST function instead of convert. Try if that solves the problem.

Related

T-SQL dynamic sql within while loop

I would like to use T-SQL while loop to get var_1, var_2, var_3 individually at each loop. But, it returns error message "Must declare the scalar variable "#var_1","#var_2","#var_3". Could please help me out. Thank you. I attached my code below:
declare #var_1 varchar(max)
set #var_1 = 'abcdef'
declare #var_2 varchar(max)
set #var_2 = 'ghijk'
declare #var_3 varchar(max)
set #var_3 = 'lmnopq'
declare #counter tinyint
set #counter = 1
declare #termName varchar(max)
while #counter<=3
begin
set #termName = '#var_' + CONVERT(varchar(10), #counter)
print #termName
declare #sql_code varchar(max)
set #sql_code = '
print '+ #termName+';
'
print #sql_code
exec (#sql_code)
set #counter = #counter + 1
end
When you use EXEC with a string, the command is carried out in a new session, so variables cannot be used pass arguments or get results. However, you could create a temporary table, put the arguments in it and use this table inside the dynamic statement:
create table #T (val_1 varchar(10), val_2 varchar(10), val_3 varchar(10));
insert into #T values ('abcef', 'ghijk', 'lmnopq');
declare #counter tinyint
set #counter = 1
while #counter<=3
begin
declare #sql_code varchar(max)
set #sql_code = '
declare #v varchar(10);
select #v = val_' + CONVERT(varchar(10), #counter) + ' FROM #T;
print #v;
'
print #sql_code
exec (#sql_code)
set #counter = #counter + 1
end

Convert a SQL function into a stored procedure

I am having trouble converting an UDF into a stored procedure.
Here is what I've got: this is the stored procedure that calls the function (I am using it to search for and remove all UNICODE characters that are not between 32 and 126):
ALTER PROCEDURE [dbo].[spRemoveUNICODE]
#FieldList varchar(250) = '',
#Multiple int = 0,
#TableName varchar(100) = ''
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL VARCHAR(MAX), #counter INT = 0
IF #Multiple > 0
BEGIN
DECLARE #Field VARCHAR(100)
SELECT splitdata
INTO #TempValue
FROM dbo.fnSplitString(#FieldList,',')
WHILE (SELECT COUNT(*) FROM #TempValue) >= 1
BEGIN
DECLARE #Column VARCHAR(100) = (SELECT TOP 1 splitdata FROM #TempValue)
SET #SQL = 'UPDATE ' + #TableName + ' SET ' + #Column + ' = dbo.RemoveNonASCII(' + #Column + ')'
EXEC (#SQL)
--print #SQL
SET #counter = #counter + 1
PRINT #column + ' was checked for ' + #counter + ' rows.'
DELETE FROM #TempValue
WHERE splitdata = #Column
END
END
ELSE IF #Multiple = 0
BEGIN
SET #SQL = 'UPDATE ' + #TableName + ' SET ' + #FieldList + ' = dbo.RemoveNonASCII(' + #FieldList + ')'
EXEC (#SQL)
--print #SQL
SET #counter = #counter + 1
PRINT #column + ' was checked for ' + #counter + ' rows.'
END
END
And here is the UDF that I created to help with the update (RemoveNonASCII):
ALTER FUNCTION [dbo].[RemoveNonASCII]
(#nstring nvarchar(max))
RETURNS varchar(max)
AS
BEGIN
-- Variables
DECLARE #Result varchar(max) = '',#nchar nvarchar(1), #position int
-- T-SQL statements to compute the return value
set #position = 1
while #position <= LEN(#nstring)
BEGIN
set #nchar = SUBSTRING(#nstring, #position, 1)
if UNICODE(#nchar) between 32 and 127
set #Result = #Result + #nchar
set #position = #position + 1
set #Result = REPLACE(#Result,'))','')
set #Result = REPLACE(#Result,'?','')
END
if (#Result = '')
set #Result = null
-- Return the result
RETURN #Result
END
I've been trying to convert it into a stored procedure. I want to track how many rows actually get updated when this is run. Right now it just says that all rows, however many I run this on, are updated. I want to know if say only half of them had bad characters. The stored procedure is already set up so that it tells me which column it is looking at, I want to include how many rows were updated. Here is what I've tried so far:
DECLARE #Result varchar(max) = '',#nchar nvarchar(1), #position int, #nstring nvarchar(max), #counter int = 0, #CountRows int = 0, #Length int
--select Notes from #Temp where Notes is not null order by Notes OFFSET #counter ROWS FETCH NEXT 1 ROWS ONLY
set #nstring = (select Notes from #Temp where Notes is not null order by Notes OFFSET #counter ROWS FETCH NEXT 1 ROWS ONLY)
set #Length = LEN(#nstring)
if #Length = 0 set #Length = 1
-- Add the T-SQL statements to compute the return value here
set #position = 1
while #position <= #Length
BEGIN
print #counter
print #CountRows
select #nstring
set #nchar = SUBSTRING(#nstring, #position, 1)
if UNICODE(#nchar) between 32 and 127
begin
print unicode(#nchar)
set #Result = #Result + #nchar
set #counter = #counter + 1
end
if UNICODE(#nchar) not between 32 and 127
begin
set #CountRows = #CountRows + 1
end
set #position = #position + 1
END
print 'Rows found with invalid UNICODE: ' + convert(varchar,#CountRows)
Right now I'm purposely creating a temp table and adding a bunch of notes and then adding in a bunch of invalid characters.
I created a list of 700+ Notes and then updated 2 of them with some invalid characters (outside the 32 - 127). There are a few that are null and a few that are not null, but that doesn't have anything in them. What happens is that I get 0 updates.
Rows found with invalid UNICODE: 0
Though it does see that the UNICODE for the one that it pulls is 32.
Obviously I'm missing something I just don't see what it is.
Here is a set based solution to handle your bulk replacements. Instead of a slow scalar function this is utilizing an inline table valued function. These are far faster than their scalar ancestors. I am using a tally table here. I keep this as a view on my system like this.
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
If you are interested about tally tables here is an excellent article on the topic. http://www.sqlservercentral.com/articles/T-SQL/62867/
create function RemoveNonASCII
(
#SearchVal nvarchar(max)
) returns table as
RETURN
with MyValues as
(
select substring(#SearchVal, N, 1) as MyChar
, t.N
from cteTally t
where N <= len(#SearchVal)
and UNICODE(substring(#SearchVal, N, 1)) between 32 and 127
)
select distinct MyResult = STUFF((select MyChar + ''
from MyValues mv2
order by mv2.N
--for xml path('')), 1, 0, '')
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'), 1, 0, '')
from MyValues mv
;
Now instead of being forced to call this every single row you can utilize cross apply. The performance benefit of just this portion of your original question should be pretty huge.
I also eluded to your string splitter also being a potential performance issue. Here is an excellent article with a number of very fast set based string splitters. http://sqlperformance.com/2012/07/t-sql-queries/split-strings
The last step here would be eliminate the first loop in your procedure. This can be done also but I am not entirely certain what your code is doing there. I will look closer and see what I can find out. In the meantime parse through this and feel free to ask questions about any parts you don't understand.
Here is what I've got working based on the great help from Sean Lange:
How I call the Stored Procedure:
exec spRemoveUNICODE #FieldList='Notes,Notes2,Notes3,Notes4,Notes5',#Multiple=1,#TableName='#Temp'
The #Temp table is created:
create table #Temp (ID int,Notes nvarchar(Max),Notes2 nvarchar(max),Notes3 nvarchar(max),Notes4 nvarchar(max),Notes5 nvarchar(max))
Then I fill it with comments from 5 fields from a couple of different tables that range in length from NULL to blank (but not null) to 5000 characters.
I then insert some random characters like this:
update #Temp
set Notes2 = SUBSTRING(Notes2,1,LEN(Notes2)/2) + N'￿㹊潮Ņ᯸ࢹᖈư㹨ƶ槹鎤⻄ƺ綐ڌ⸀ƺ삸)䀤ƍ샄)Ņᛡ鎤ꗘᖃᒨ쬵Ğᘍ鎤ᐜᏰ>֔υ赸Ƹ쳰డ촜)鉀௿촜)쮜)Ἡ屰山舰霡ࣆ 耏Аం畠Ư놐ᓜતᏛ֔Ꮫ֨Ꮫ꯼ᓜƒ 邰఍厰ఆ邰఍드)抉鎤듄)繟Ĺ띨)᯸ࢹ䮸ࣉ᯸ࢹ䮸ࣉ샰)ԌƏ￿

Conversion failed when converting the varchar value ',1,2,3' to data type int

This error results when attempting to use a comma delimited parameter in an IN condition
I'm passing a varchar parameter to a stored procedure that looks like this
,1,2,3
And I want to find out if it contains 1 (it doesn't always contain 1)
What's the easiest way to do that in TSQL ?
declare #Nums varchar(max)=',1,2,3'
if 1 in (#Nums) -- conversion error
BEGIN
select * from TestTable
END
You will need to use LIKE to see if the string contains the character 1. Note this will also match 12 or any string with the character '1' in it.
declare #Nums varchar(max)=',1,2,3'
if #Nums LIKE '%1%'
BEGIN
select * from TestTable
END
If you need to match the full number:
CREATE FUNCTION [dbo].[Split_String]
(
#ItemList NVARCHAR(4000),
#delimiter CHAR(1)
)
RETURNS #IDTable TABLE (Item VARCHAR(50))
AS
BEGIN
DECLARE #tempItemList NVARCHAR(4000)
SET #tempItemList = #ItemList
DECLARE #i INT
DECLARE #Item NVARCHAR(4000)
SET #tempItemList = REPLACE (#tempItemList, ' ', '')
SET #i = CHARINDEX(#delimiter, #tempItemList)
WHILE (LEN(#tempItemList) > 0)
BEGIN
IF #i = 0
SET #Item = #tempItemList
ELSE
SET #Item = LEFT(#tempItemList, #i - 1)
INSERT INTO #IDTable(Item) VALUES(#Item)
IF #i = 0
SET #tempItemList = ''
ELSE
SET #tempItemList = RIGHT(#tempItemList, LEN(#tempItemList) - #i)
SET #i = CHARINDEX(#delimiter, #tempItemList)
END
RETURN
END
DECLARE #Nums VARCHAR(MAX) = ',1,2,3'
DECLARE #NumberTable TABLE (item INT)
INSERT INTO #NumberTable
SELECT TRY_CAST(Item AS INT)
FROM dbo.Split_String(#Nums, ',')
IF (SELECT 1 FROM #NumberTable WHERE item = 1) = 1
BEGIN
select * from TestTable
END
You can use CHARINDEX.
declare #Nums varchar(max)=',1,2,3'
IF CHARINDEX(',1,', #Nums+',') > 0
BEGIN
select * from TestTable
END

Transform text in SQL Server

I am trying to create a dynamic query in SQL Server.
Input: #value= abc,def,en,
Output: MAX(abc) as abc, MAX(def) as def, MAX(en) as en
My efforts so far took me no where.
With CONVERT() and REPLACE() I achieved a bit but finding it difficult. Need help!
Try this:
declare #value varchar(50) = 'abc,def,en'
declare #result varchar(100) = ''
select #result = replace(#value,'abc', 'MAX(''abc'') as abc')
select #result = replace(#result,'def', 'MAX(''def'') as def')
select #result = replace(#result,'en', 'MAX(''en'') as en')
select #result
You can also do the replacements in one line by nesting the expressions.
EDIT: If you have variable values in #value, you can take the below approach:
Use a splitter function to get the individual values in the string as a list. You can take a look at this article for implementations.
Insert this list to a temp table.
Update the temp table as shown above.
Concatenate the values into a single string using STUFF like so:
select stuff((select ',' + val from #temp for xml path('')),1,1,'')
Try this:
DECLARE #Value VARCHAR(200) = 'abc,def,en'
DECLARE #Template VARCHAR(100) = 'MAX(''##'') as ##'
DECLARE #Result VARCHAR(1000) = ''
DECLARE #Data VARCHAR(100) = ''
WHILE LEN(#Value) > 0
BEGIN
SET #Data = REPLACE(LEFT(#Value, ISNULL(NULLIF(CHARINDEX(',', #Value),0), LEN(#Value))),',','')
SET #Result = #Result + REPLACE(#Template, '##', #Data)
IF CHARINDEX(',', #Value) > 0
BEGIN
SET #Result = #Result + ','
SET #Value = REPLACE(#Value,#Data + ',','')
END
ELSE
SET #Value = REPLACE(#Value,#Data,'')
END
SELECT #Result
Have a look at SQL User Defined Function to Parse a Delimited String
So you can do like
Declare #Value varchar(200) = 'abc,def,en'
Declare #Item varchar(20) = null
declare #Str varchar(1000)=''
WHILE LEN(#Value) > 0
BEGIN
IF PATINDEX('%,%',#Value) > 0
BEGIN
SET #Item = SUBSTRING(#Value, 0, PATINDEX('%,%',#Value))
-- SELECT #Item
IF(LEN(#Str)>0)
SET #Str = #Str + ', SELECT MAX('+#Item+') as ' +#Item
ELSE
SET#Str = #Str + ' SELECT MAX('+#Item+') as ' +#Item
SET #Value = SUBSTRING(#Value, LEN(#Item + ',') + 1, LEN(#Value))
END
ELSE
BEGIN
SET #Item = #Value
SET #Value = NULL
SET #Str = #Str + 'SELECT MAX('+#Item+') as ' + #Item
END
END
select #Str
See the fiddle sample here

Replace every 2nd instance of character in string with TSQL

I have a field that contains a string of lat/long co-ordinates that define a geofence (polygon). Each is seperated by a comma.
eg: 'lat,long,lat,long,lat,long'
eg: 148.341158,-21.500773,148.341406,-21.504989,148.375136,-21.513174,148.401674,-21.535247,148.418044,-21.532767,148.408867,-21.511685,148.414075,-21.508461,148.36968,-21.432567,148.349094,-21.438768,148.346862,-21.480187,148.341158,-21.500773,
I'd like to use this with the geography type in MSSQL (http://msdn.microsoft.com/en-us/library/bb933971.aspx)
DECLARE #g geography;
SET #g = geography::STPolyFromText('POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))', 4326);
SELECT #g.ToString();
This seems to require: 'lat long, lat long, lat long' ie: no comma between the pair.
I can't change the source data, as it's used by a vendor program. I need to manipulate the string to remove every 1 out of 2 commas, or failing that, get regex working in TSQL
You could use a numbers table (a very handy tool for many purposes, by the way) to find the positions of all the commas, then, using only the odd position numbers, replace the corresponding commas with spaces in a single SELECT statement. Here's what I am talking about:
WITH CTE AS (
SELECT number, rn = ROW_NUMBER() OVER (ORDER BY number)
FROM master.dbo.spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND LEN(#coords)
AND SUBSTRING(#coords, number, 1) = ','
)
SELECT
#coords = STUFF(#coords, number, 1, ' ')
FROM CTE
WHERE rn % 2 = 1
;
In the above query, the numbers table's "part" is "played" by a subset of system table master.dbo.spt_values. The CTE calculates the positions of all the commas in the #coords string, returning the results as a row set. The main SELECT is used an assignment statement. It takes every number in the CTE set and removes the character at the corresponding position in #coords, replacing it with a space character (all with the help of the STUFF function).
You can use this SQL Fiddle demo to play with the query.
This ended up my Solution:
DECLARE #WorkingCoordList VARCHAR(max) = 'some lat,long,lat,long string'
DECLARE #Processed INT = 0
DECLARE #CommaLoc INT
DECLARE #Count INT = 0
WHILE #Processed = 0
BEGIN
SET #CommaLoc = PATINDEX('%,%', #WorkingCoordList)
IF #Count % 2 = 0
BEGIN
SET #WorkingCoordList = STUFF(#WorkingCoordList, #CommaLoc, 1, ' ') --Convert comma to space
END
ELSE
BEGIN
SET #WorkingCoordList = STUFF(#WorkingCoordList, #CommaLoc, 1, '#') -- Convert comma to hash
END
IF #CommaLoc = LEN(#WorkingCoordList)
BEGIN
SET #WorkingCoordList = LEFT(#WorkingCoordList, LEN(#WorkingCoordList) - 1) -- trim trailing ,
SET #WorkingCoordList = RTRIM(LTRIM(REPLACE(#WorkingCoordList, '#', ', '))) -- Convert all the hashes to commas
SET #Processed = 1
END
SET #Count = #Count + 1
END
END
You could roll your own parser like the following. It uses the commas in the string to find all of the lattitude/ longitude values. It concatenates all the values together using the pattern: lat long, lat long, ...
declare #list varchar(max)
declare #result varchar(max)
declare #word varchar(max)
declare #splitOn varchar(1)
declare #wpos int
declare #cpos int
declare #wordCount int
select #list = '148.341158,-21.500773,148.341406,-21.504989,148.375136,-21.513174,148.401674,-21.535247,148.418044,-21.532767,148.408867,-21.511685,148.414075,-21.508461,148.36968,-21.432567,148.349094,-21.438768,148.346862,-21.480187,148.341158,-21.500773,'
select #splitOn = ','
select #result = ''
select #cpos = 0
select #wpos = 1
select #wordCount = 1
while (#cpos <= len(#list))
begin
select #cpos = charindex(#splitOn, #List, #cpos)
if (#cpos < 1) select #cpos = len(#list) + 1
select #word = substring(#list, #wpos, #cpos - #wpos)
select #result = #result + ' ' + #word
if ((#wordCount % 2) = 0 and (#cpos < len(#list))) select #result = #result + ','
select #cpos = #cpos + 1
select #wpos = #cpos
select #wordCount = #wordCount + 1
end
select #result as result
Which produces the following string:
148.341158 -21.500773, 148.341406 -21.504989, 148.375136 -21.513174, 148.401674 -21.535247, 148.418044 -21.532767, 148.408867 -21.511685, 148.414075 -21.508461, 148.36968 -21.432567, 148.349094 -21.438768, 148.346862 -21.480187, 148.341158 -21.500773
I don't know how your regex works but if you preprocess the string with a regex, it might work with a global search and replace like this:
find: ,([^,]*(?:,|$))
replace: '$1' ie. space plus capture group 1
Thanks for the code :-)
I had a slightly different scenario however created a function using "chue x" code to add a character '#' at every 3rd ';'
/*** My select query ***/
SELECT dbo.fn_AddEveryNthItem(a.MyString, ';','#', 3) AS Expr1
FROM dbo.MyTable as a
Function is below
/*** Function to add character for every nth item ***/
Create function dbo.fn_AddEveryNthItem(#list varchar(1000), #splitOn varchar(1), #addChar varchar(1), #EveryNthItem int)
RETURNS VARCHAR(1000)
AS
BEGIN
declare #word varchar(max)
declare #result varchar(max) = ''
declare #wpos int = 1
declare #cpos int = 0
declare #wordCount int =1
while (#cpos <= len(#list))
begin
select #cpos = charindex(#splitOn, #List, #cpos)
if (#cpos < 1) select #cpos = len(#list) + 1
select #word = substring(#list, #wpos, #cpos - #wpos)
select #result = #result + #splitOn + #word
if ((#wordCount % #EveryNthItem) = 0 and (#cpos < len(#list))) select #result = #result + #addChar
select #cpos = #cpos + 1
select #wpos = #cpos
select #wordCount = #wordCount + 1
end
Return #result
end

Resources