t-sql replace on text field - sql-server

I have hit a classic problem of needing to do a string replace on a text field in an sql 2000 database. This could either be an update over a whole column or a single field I'm not fussy.
I have found a few examples of how to use updatetext to achieve it but they tend to be in stored procedures, does anyone know of a similar thing that is wrapped into a function so I can use it like I would usually use Replace(). The problem with the Replace() function for anyone who isn't aware is that it doesn't support text fields.
Edit: I realised I could probably get away with varchar(8000) so have swapped the fields to this type which fixes the issue. I never found a true solution.

Here is the sample query to update table with text column using REPLACE function. Hope this is useful for you.
UPDATE <Table> set textcolumn=
REPLACE(SUBSTRING(textcolumn,1,DATALENGTH(textcolumn)),'findtext','replacetext')
WHERE <Condition>

I am afraid you cannot do it within a function
When you try to declare a function like:
create function dbo.textReplace(
#inText as text)
returns text
as
begin
return 'a' -- just dummy code
end
You will get the following error:
The text data type is invalid for return values.
In other words you could not write a simple equivalent of REPLACE function for the text data type

This is my code snippet for this scenario:
DECLARE #oldtext varchar(1000)
DECLARE #newtext varchar(1000)
DECLARE #textlen int
DECLARE #ptr binary(16)
DECLARE #pos int
DECLARE #id uniqueidentifier
SET #oldtext = 'oldtext'
SET #newtext = 'newtext'
SET #textlen = LEN(#oldtext)
DECLARE mycursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT [UniqueID]
,TEXTPTR([Text])
,CHARINDEX(#oldtext, [Text]) - 1
FROM [dbo].[myTable]
WHERE [Text] LIKE '%' + #oldtext +'%'
OPEN mycursor
FETCH NEXT FROM mycursor into #id, #ptr, #pos
WHILE ##fetch_status = 0
BEGIN
UPDATETEXT [dbo].[myTable].Text #ptr #pos #textlen #newtext
FETCH NEXT FROM mycursor into #id, #ptr, #pos
END
CLOSE mycursor
DEALLOCATE mycursor

You would have to cast the text field to a varchar(8000) or nvarchar(4000) if you are replacing over an ntext field.
MyField = REPLACE(CAST(MyField as VARCHAR(4000)), "string1", "string2")
This ofcourse will only work if you can guarantee the content in the field is <= 4000/8000 characters in length.

You can also use the SUBSTRING() function, which returns a varchar when passed a text value.
For instance:
MyVarchar = SUBSTRING(myTextField, 1, DATALENGTH(myTextField))
If you're populating a varchar with a specific length, you can truncate to fit:
MyVarchar100 = SUBSTRING(myTextField, 1, 100)

Related

T-SQL stored procedure: in while loop inside cursor only insert the first row from collection

I have a problem with this stored procedure.
Parameters from my application are well defined, but in this procedure, when I am trying to insert a row into table Image, it insert only the first row from #xmlImages and I sent two values. I appreciate any help!
CREATE PROCEDURE sp_AddExplanationAndImage
#Text NVARCHAR(MAX) = NULL,
#ID INT = 0
#ListOfImages NVARCHAR(MAX) = NULL
AS
BEGIN
INSERT INTO dbo.Explanation (ID, Text)
VALUES (#ID, #Text)
DECLARE #xmlImages xml
SET #xmlImages = CAST(#ListOfImages AS xml)
DECLARE #ImageExtension NVARCHAR(MAX)
DECLARE #Name NVARCHAR(MAX)
DECLARE #Content VARBINARY(MAX)
IF (#ListOfImages IS NOT NULL)
BEGIN
DECLARE cursor cursor for--local fast_forward for
SELECT
s.x.value('(Image/Extension)[1]', 'nvarchar(max)'),
s.x.value('(Image/Name)[1]', 'nvarchar(max)'),
s.x.value('(Image/Content)[1]', 'varbinary(max)')
FROM
#xmlImages.nodes('Images') AS s(x)
OPEN CURSOR
FETCH NEXT FROM cursor INTO #ImageExtension, #Name, #Content
WHILE ##FETCH_STATUS = 0
BEGIN
IF ##fetch_status <> 0
BREAK
INSERT INTO dbo.Image (Extension, Name, Content)
SELECT #ImageExtension, #Name, #Content
FETCH NEXT FROM cursorSlike INTO #ImageExtension, #Name, #Content
END
CLOSE cursor
DEALLOCATE cursor
END
The fetch next from inside the WHILE block does not reference the cursor that you're looping through. You named your cursor cursor (I recommend using a more descriptive name BTW) but you're fetching next from cursorSlike.
But I'm not sure you need the loop in the first place (in general, you should avoid loops in SQL Server unless there's no other way to accomplish the task). I haven't done a lot with XML in SQL Server but have you tried this?
INSERT INTO dbo.Image(Extension,Name,Content)
SELECT
s.x.value('(Image/Extension)[1]','nvarchar(max)'),
s.x.value('(Image/Name)[1]','nvarchar(max)'),
s.x.value('(Image/Content)[1]','varbinary(max)')
FROM #xmlImages.nodes('Images')AS s(x)
According to your sample data. you need to get Images/Image nodes. And you dont need to use cursor.
INSERT INTO dbo.Image(Extension,Name,Content)
SELECT
s.x.value('(Extension)[1]','nvarchar(max)'),
s.x.value('(Name)[1]','nvarchar(max)'),
s.x.value('(Content)[1]','nvarchar(max)')
FROM #xmlImages.nodes('Images/Image')AS s(x)

How to check numeric value in sql?

Here is my code. I want only numeric character. If it is other than numeric, should not print.
Here #msg is substring of one of string,which dynamically created.So I can not change type of #msg to int.It can be ',,3' or '4,,,',etc.Sometime #msg contain comma,so I want to check for numeric.Isnumeric() consider comma as numeric.I gives 1 as result.How to handle it?
Declare #msg varchar(5)
set #msg = ',5'
if(isnumeric(#msg) = 1)
begin
print 'Numeric'
-- logic
end
IsNumeric certainly has idiosyncrasies. They are well discussed in the community. See here for some discussion seesimple talk.
What you actually need to do is not quite clear between the questions and comments, but you might get by with something as simple as checking to make sure there isn't a comma either:
DECLARE #msg VARCHAR(5)
SET #msg = ',5'
IF IsNumeric(#msg) = 1 AND CharIndex(',',#msg,1) = 0
BEGIN
PRINT 'Numeric'
-- logic
END
For more ideas on how to do a better IsNumeric see similar questions like efficient-isnumeric-replacements-on-sql-server.
I think you just want to validate that your variable contains only numeric value or not. use the query..
declare #ClientID varchar(100)
declare #filename varchar(1000)
set #filename = '3081PDShivamCSS_MDaily.Dat'
set #ClientID = substring('3081PDShivamCSS_MDaily.Dat', 1,4)
If #ClientID Not LIKE '%[^0-9]%'
Print Numeric

Issue converting varchar to INT in sql server

I have seen this question all over stackoverflow, but it seems that there are a wide number of solutions tailored to the situation. It seems I have a unique situation as far as I can tell. I am running this sql statement
use IST_CA_2_Batch_Conversion
GO
--T-SQL script to populate the Match type column
declare #MatchType varchar(16),
#PK varchar(500),
#CAReturnCode VARCHAR(255),
#CAErrorCodes VARCHAR(255)
declare cursor1 cursor fast_forward for
select
["Ref#"],
["Return Code"],
["Error Codes"]
from CACodes2MatchType
open cursor1
fetch next from cursor1 into #PK,#CAReturnCode,#CAErrorCodes
while ##fetch_status = 0
begin
set #MatchType = dbo.GetMatchType(#CAReturnCode,#CAErrorCodes)
update CACodes2MatchType
set [Match Type] = #MatchType
where ["Ref#"] = #PK
fetch next from cursor1 into #PK,#CAReturnCode,#CAErrorCodes
end
close cursor1
deallocate cursor1
It will fail at
set #MatchType = dbo.GetMatchType(#CAReturnCode,#CAErrorCodes)
Here is the beginning code for the GetMatchType function:
-- Batch submitted through debugger:
SQLQuery14.sql|6|0|C:\Users\b01642a\AppData\Local\Temp\~vs1C8E.sql
CREATE FUNCTION [dbo].[GetMatchType](#CAReturnCode VARCHAR(255), #CAErrorCodes
VARCHAR(255))
RETURNS VARCHAR(16)
BEGIN
DECLARE #MatchType VARCHAR(16);
DECLARE #errorCodes TABLE(Pos INT, Code CHAR(2));
DECLARE #country INT; -- 1 is US, 2 is Canada
DECLARE #numMinorChanges INT;
DECLARE #numMajorChanges INT;
DECLARE #numSingleCodes INT;
DECLARE #returnCode INT;
DECLARE #verified VARCHAR(16);
DECLARE #goodFull VARCHAR(16);
DECLARE #tentativeFull VARCHAR(16);
DECLARE #poorFull VARCHAR(16);
DECLARE #multipleMatch VARCHAR(16);
DECLARE #unmatched VARCHAR(16);
SET #verified = 'Verified';
SET #goodFull = 'Good Full';
SET #tentativeFull = 'Tentative Full';
SET #poorFull = 'Poor Full';
SET #multipleMatch = 'Multiple Match';
SET #unmatched = 'Unmatched';
SET #returnCode = CAST(#CAReturnCode AS INT);
I will get the error: Msg 245, Level 16, State 1, Line 21
Conversion failed when converting the varchar value '"1"' to data type int.
This error occurs at the last line of the code segment I have shown:
SET #returnCode = CAST(#CAReturnCode AS INT);
This is code that was written by a colleague and supposedly had worked for him. I have had to troubleshoot some errors but I cannot debug this one. I understand alot of people will create a dbo.split function? I don't know if this option will help me in this scenario. I have tried setting #returnCode to a varchar and getting rid of the CAST on #CAReturnCode. As a result, the debugger will make it past that line but raises issues with the rest of the code. I am assuming there is an issue with how I am casting #CAReturnCode? Any help would be much appreciated.
The problem is that #CAReturnCode contains non-numeric characters.
-- Msg 245, Level 16, State 1, Line 21 Conversion failed when converting the varchar value '"1"' to data type int.
See, the outer single quotes are the error message's formatting, but the inner double quotes are in the #CAReturnCode value. So the solution here is to ensure that the variable contains only numeric characters prior to converting. If double quotes are the only possibility, you can do a quick and dirty fix like this:
set #returnCode = cast(replace(#CAReturnCode, '"', '') as int)
If there are more possibilities, you could do multiple REPLACE calls, or you could build a better character-trimming function that will remove all the characters you specify at once yourself.

Cursor not looping correctly

I have a cursor that I want to loop through a staging table, and merge each record into another table.
I cant get this cursor just to loop through the records and return a count.
DECLARE #curCatalogID int
DECLARE #curNomenclature varchar(200)
DECLARE #curMainCategory varchar(200)
DECLARE #curSubCategory varchar(200)
DECLARE #curManufacturer varchar(200)
DECLARE #curModelNo varchar(200)
DECLARE #curPrice varchar(200)
DECLARE #curProductDesc varchar(2000)
DECLARE #curImage varchar(200)
DECLARE #curPDFName varchar(200)
DECLARE #curInventory varchar(200)
DECLARE #curBatchID int
DECLARE #curAuditID int
DECLARE #nCnt int
SET #nCnt = 0
DECLARE import_loop CURSOR FOR
SELECT * FROM tblCatalogStaging
OPEN import_loop
FETCH NEXT FROM import_loop
INTO #curCatalogID,
#curNomenclature,
#curMainCategory,
#curSubCategory,
#curManufacturer,
#curModelNo,
#curPrice,
#curProductDesc,
#curImage,
#curPDFName,
#curInventory,
#curBatchID,
#curAuditID
WHILE ##FETCH_STATUS = 0
BEGIN
SET #nCnt = ##ROWCOUNT;
FETCH NEXT FROM import_loop
INTO #curCatalogID,
#curNomenclature,
#curMainCategory,
#curSubCategory,
#curManufacturer,
#curModelNo,
#curPrice,
#curProductDesc,
#curImage,
#curPDFName,
#curInventory,
#curBatchID,
#curAuditID
END
CLOSE import_loop
DEALLOCATE import_loop
SELECT #nCnt
It should just return 1 value of 2036 ( number of rows in the staging table ) but im getting back like 2036 rows affected, 4072 rows affected, etc etc
I'm not so sure ##ROWCOUNT is meant to be used inside a CURSOR.
You might have better luck with:
DECLARE #nCnt INT
SET #nCnt = 0
...
SET #nCnt = #nCnt + 1;
Note: A TRIGGER is probably the right place to be doing this validation on row insert/update. Unless you really only want the validation to happen sometimes. (Also, it's SQL errors you'll be raising, not exceptions)
i m not sure if its as simple as this but do you just want:
select count (*) FROM tblCatalogStaging
##Rowcount provides the number of rows that were affected by the last statemenet to be executed. I do not think this is what you want, and I would agree with ebyrob about just using a counter variable.
But that is if you really need to do this in a cursor. AS marc_s suggest, you may want to rework your actual procedure so that it is using sets. If that is not possible and you need to, as you said in your response, deal with exceptions in your loop, you may want to look at Phil Factors recent article on that topic.

substring or rtrim

i have a field called LastWebpage, in the Field it stores the webpage .asp pagename
I have to write a script where i just need to take the jl_AssessmentDirect.asp name instead of 4000_1_jl_AssessmentDirect.asp. How do i get rid of 4000_1_. Please help.
Thanks.
Here are a couple of ways to do this, I assume the data is not always the same, this is just to show you how the functions work
right or replace is my preferred method
DECLARE #v VARCHAR(100)
SELECT #v = '4000_1_jl_AssessmentDirect.asp'
SELECT REPLACE(#v,'4000_1_','')
or
DECLARE #v VARCHAR(100)
SELECT #v = '4000_1_jl_AssessmentDirect.asp'
DECLARE #r VARCHAR(100)
SELECT #r ='4000_1_'
--if you have spaces RTRIM and LTRIM everything
SELECT RIGHT(#v,LEN(#v) -LEN(#r))
If stuff changes, you can dump it in variables
DECLARE #v VARCHAR(100)
SELECT #v = '4000_1_jl_AssessmentDirect.asp'
DECLARE #r VARCHAR(100)
SELECT #r ='4000_1_'
SELECT REPLACE(#v,#r,'')
Ideally you want to update such columns to only have the URL and nothing else
"It depends"
If always "4000_1_", use REPLACE as per SQLMenace's answer.
If a fixed length of any string, use SUBSTRING. No need to work out LENGTH first
SUBSTRING(MyValue, 8, 8000)
If the right hand side is fixed length and the unwanted part is variable length, use RIGHT
If both sides are variable, you'll need something like
SUBSTRING(MyValue, PATINDEX('%[_]1[_]%', MyValue) + 3, 8000)
Edit:
If you always want "jl"...
SUBSTRING(MyValue, PATINDEX('%jl%', MyValue), 8000)
Besides all the suggestions here already you can use stuff.
declare #s varchar(100)
set #s = '4000_1_jl_AssessmentDirect.asp'
select stuff(#s, 1, 7, '')
Remove characters before jl
declare #s varchar(100)
set #s = '4000_1_jl_AssessmentDirect.asp'
select stuff(#s, 1, charindex('jl', #s)-1, '')

Resources