SQL Server - Replace - sql-server

What's the problem with my query, it doesn't work
DECLARE #_old nvarchar = '#35_D'
DECLARE #_new nvarchar = '#Dima'
UPDATE ShoppingComment SET Commnet =Replace(Commnet,#_old,#_new)
It doesn't show error, but query isn't replace, but when I use it without DECLARE , it works fine

Datatype length is missing in your code.
From MSDN
When n is not specified in a data definition or variable declaration
statement, the default length is 1.
So only the first character will be assigned to the variable
DECLARE #_old nvarchar(50) = '#35_D' --here
DECLARE #_new nvarchar(50) = '#Dima' --here
UPDATE ShoppingComment SET Commnet =Replace(Commnet,#_old,#_new)

Related

SQL Server: get column value from string column name, assign value to variable

In SQL Server in a stored procedure, I want to get the value in a column of a single-row table given the column name, and assign that value to a variable. The column name may be different every time (I use T-SQL to interrogate the schema at run time).
The example given below is as minimal as I can make it, the important thing is that you cannot assume that the column name will always be entity_client, it could be anything at all, though (due to interrogation of INFORMATION SCHEMA) we will have the value assigned to the variable #entity_column_name.
Example preparation SQL:
IF OBJECT_ID('tempdb..#foo') IS NOT NULL
BEGIN;
DROP TABLE #foo;
END;
CREATE TABLE #foo
(
id INT,
entity_client NVARCHAR(255)
);
INSERT INTO #foo VALUES (1, 'clientcode|client_number');
DECLARE #entity_column_name NVARCHAR(255) = 'entity_client';
DECLARE #entity_column_value NVARCHAR(255);
I have tried the following:
SELECT TOP 1 #entity_column_name = [#entity_column_value]
FROM #foo;
...which generates an error
Invalid column name '#entity_column_value'
I have also tried:
EXEC('SELECT TOP 1 #entity_column_value = [' + #entity_column_name + '] FROM #foo;');
which generates another error
Must declare the scalar variable "#entity_column_value"
The following works, but unfortunately the column name is hard-coded - I wanted to be able to vary the column name:
SELECT TOP 1 #entity_column_value = [entity_client]
FROM #foo;
Yes, I have looked on SO and found the following questions, but they do not provide an answer where the value is assigned to a variable, in both cases the SELECT output is simply dumped to screen:
Get column value from string column name sql
Get column value from dynamically achieved column name
This will actually work but you need to declare the output variable:
DECLARE #entity_column_name NVARCHAR(255) = 'entity_client';
DECLARE #entity_column_value NVARCHAR(255);
DECLARE #tsql NVARCHAR(1000) = 'SELECT TOP 1 #entity_column_value = [' + #entity_column_name + '] FROM #foo;'
EXEC sp_executesql #tsql, N'#entity_column_value NVARCHAR(255) OUTPUT',
#entity_column_value OUTPUT;

how to use declare variable in select query in stored procedure using sql server

Hello I want to concate two things one is string and other is int variable. Now, these thing I want to store in one variable and use that variable in select query as a into type to create a temptable in stored procedure using sql server.
Here is my query
USE [FlightExamSoftware]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- For Storing Question in Temp table
-- EXEC [GetQuestionListPerSubjectRatioWise] 1,11
ALTER PROCEDURE [dbo].[GetQuestionListPerSubjectRatioWise]
#SubjectID INT,
#NumberOfQue INT,
#UserID int
AS
BEGIN
DECLARE #strQuery VARCHAR(MAX);
DECLARE #PerChapQue INT;
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID;
SELECT #PerChapQue = COUNT(appQueID)/#NumberOfQue FROM tblQuestion WHERE appQueSubID=#SubjectID
SELECT COUNT(appQueID)/#PerChapQue ChapwiseQue
,CASE WHEN COUNT(appQueID)>=#PerChapQue THEN COUNT(appQueID)/#PerChapQue ELSE 1 END ChapWiseQuePlusOne
,appQueChapID into #tempTable
FROM tblQuestion
WHERE appQueSubID=#SubjectID
GROUP BY appQueChapID
END
Now, I am talking about these line
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID;
In these line two things are concate one is string and other is int. And store in varchar variable.
And use in following select query i.e.
SELECT COUNT(appQueID)/#PerChapQue ChapwiseQue
,CASE WHEN COUNT(appQueID)>=#PerChapQue THEN COUNT(appQueID)/#PerChapQue ELSE 1 END ChapWiseQuePlusOne
,appQueChapID into #tempTable
FROM tblQuestion
WHERE appQueSubID=#SubjectID
GROUP BY appQueChapID
END
Now, in these query I want to create a temptable named #tempTable.
But, in these line it showing error i.e. Incorrect syntax near '#tempTable'.
Confuse that where is the syntax is wrong.
Thank You.
There are a number of things wrong with your code.
When concatenating an int to a string, you must first cast the int to varchar. Otherwise, SQL Server will try to implicitly convert the string to int, that will result with an error.
So this: DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID; should become this:
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + CAST(#UserID AS VARCHAR(11)); (you need 11 chars to be able to fit the minimum value of int: -2,147,483,648)
You can't use select...into with a table variable.
You can only use it for actual tables (temporary or regular).
your #tempTable isn't even a table variable (not that it will help with a select...into).
Even if you would use select...into the correct way, unless you are going to use a global temporary table (and that doesn't come without it's risks), Unless your stored procedure uses this temporary table later on, it will be useless, since temporary tables are bound to scope.
Taking all of that into consideration I'm not sure what output you are actually looking for. If you could edit your question to include the desired output of your stored procedure as well as some sample data as DDL+DML, it would be easier to help you write better code.
Hope this Dynamic Query helps you:
Try like this:
USE [FlightExamSoftware]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- For Storing Question in Temp table
-- EXEC [GetQuestionListPerSubjectRatioWise] 1,11
ALTER PROCEDURE [dbo].[GetQuestionListPerSubjectRatioWise]
#SubjectID INT,
#NumberOfQue INT,
#UserID int
AS
BEGIN
DECLARE #strQuery VARCHAR(MAX);
DECLARE #PerChapQue INT;
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + CAST(#UserID AS VARCHAR);
SELECT #PerChapQue = COUNT(appQueID)/#NumberOfQue FROM tblQuestion WHERE appQueSubID=#SubjectID
SET #strQuery='
SELECT COUNT(appQueID)/'+CAST(#PerChapQue AS VARCHAR)+' ChapwiseQue
,CASE WHEN COUNT(appQueID)>='+CAST(#PerChapQue AS VARCHAR)+' THEN COUNT(appQueID)/'+CAST(#PerChapQue AS VARCHAR)+' ELSE 1 END ChapWiseQuePlusOne
,appQueChapID
INTO '+#tempTable+'
FROM tblQuestion
WHERE appQueSubID='+CAST(#SubjectID AS VARCHAR)+'
GROUP BY appQueChapID
/*.................................
And you have to use the temp table inside the String only
.................................*/
'
EXEC (#strQuery)
END

Return length of NVARCHAR or VARCHAR variable definition

I've declared a variable in a stored procedure:
DECLARE #CurrentChunk NVARCHAR(250)
I would like to use the length of the variable, i.e. 250, later in my sp for computational purposes, and I want to keep my code as dry as possible.
Here's my code (assume #Narrative is a param to the SP):
DECLARE #ChunkSizeCharacters INT,
#NumChunks INT,
#LoopIndex INT,
#CurrentChunk NVARCHAR(250)
SET #ChunkSizeCharacters = 250 -- HERE'S WHERE I WANT THE LENGTH OF #CurrentChunk
SET #NumChunks = CEILING((LEN(#Narrative) * 1.0)/#ChunkSizeCharacters)
SET #LoopIndex = 0;
WHILE (#LoopIndex < #NumChunks)
BEGIN
SET #CurrentChunk = SUBSTRING(#Narrative,
((#LoopIndex * #ChunkSizeCharacters) + 1), #ChunkSizeCharacters)
INSERT INTO [dbo].[Chunks] ([Chunk]) VALUES (#CurrentChunk)
SET #LoopIndex = #LoopIndex + 1
END
Is there a way to ascertain the length of an NVARCHAR or VARCHAR variable definition (please read carefully -- I'm not looking for LEN())?
It seems the MaxLength variant property returns the value you're looking for.
DECLARE #Banana varchar(255) = 'This banana'
SELECT SQL_VARIANT_PROPERTY(#Banana, 'MaxLength')
Returns 255.
If you don't mind overwriting the variable (and if you do, you can assign it to a temp NVARCHAR(MAX)):
SELECT #CurrentChunk = REPLICATE(0, 8000);
SELECT #ChunkSizeCharacters = LEN(#CurrentChunk);
This trick does not and cannot work for NVARCHAR(MAX), but that's presumably no problem, given it's enormous maximum size.
Unfortunately T-SQL has nothing in the way of metadata properties for variables. Even determining the type of an expression is a chore.
Interestingly, the value returned by that SELECT SQL_VARIANT_PROPERTY statement doesn't select into a plain, predefined variable. In the end, I used:
DECLARE #Text VARCHAR(400), #TextLen INT
SELECT #TextLen = CAST(SQL_VARIANT_PROPERTY(ISNULL(#Text, ''), 'MaxLength') AS INT)
Works like a charm for me!

Parameterizing XPath for modify() in SQL Server XML Processing

Just like the title suggests, I'm trying to parameterize the XPath for a modify() method for an XML data column in SQL Server, but running into some problems.
So far I have:
DECLARE #newVal varchar(50)
DECLARE #xmlQuery varchar(50)
SELECT #newVal = 'features'
SELECT #xmlQuery = 'settings/resources/type/text()'
UPDATE [dbo].[Users]
SET [SettingsXml].modify('
replace value of (sql:variable("#xmlQuery"))[1]
with sql:variable("#newVal")')
WHERE UserId = 1
with the following XML Structure:
<settings>
...
<resources>
<type> ... </type>
...
</resources>
...
</settings>
which is then generating this error:
XQuery [dbo.Users.NewSettingsXml.modify()]: The target of 'replace' must be at most one node, found 'xs:string ?'
Now I realize that the modify method must not be capable of accepting a string as a path, but is there a way to accomplish this short of using dynamic SQL?
Oh, by the way, I'm using SQL Server 2008 Standard 64-bit, but any queries I write need to be compatible back to 2005 Standard.
Thanks!
In case anyone was interested, I came up with a pretty decent solution myself using a dynamic query:
DECLARE #newVal nvarchar(max)
DECLARE #xmlQuery nvarchar(max)
DECLARE #id int
SET #newVal = 'foo'
SET #xmlQuery = '/root/node/leaf/text()'
SET #id = 1
DECLARE #query nvarchar(max)
SET #query = '
UPDATE [Table]
SET [XmlColumn].modify(''
replace value of (' + #xmlQuery + '))[1]
with sql:variable("#newVal")'')
WHERE Id = #id'
EXEC sp_executesql #query,
N'#newVal nvarchar(max) #id int',
#newVal, #id
Using this, the only unsafe part of the dynamic query is the xPath, which, in my case, is controlled entirely by my code and so shouldn't be exploitable.
The best I could figure out was this:
declare #Q1 varchar(50)
declare #Q2 varchar(50)
declare #Q3 varchar(50)
set #Q1 = 'settings'
set #Q2 = 'resources'
set #Q3 = 'type'
UPDATE [dbo].[Users]
SET [SettingsXml].modify('
replace value of (for $n1 in /*,
$n2 in $n1/*,
$n3 in $n2/*
where $n1[local-name(.) = sql:variable("#Q1")] and
$n2[local-name(.) = sql:variable("#Q2")] and
$n3[local-name(.) = sql:variable("#Q3")]
return $n3/text())[1]
with sql:variable("#newVal")')
WHERE UserId = 1
Node names are parameters but the level/number of nodes is sadly not.
Here is the solution we found for parameterizing both the property name to be replaced and the new value. It needs a specific xpath, and the parameter name can be an sql variable or table column.
SET Bundle.modify
(
'replace value of(//config-entry-metadata/parameter-name[text() = sql:column("BTC.Name")]/../..//value/text())[1] with sql:column("BTC.Value") '
)
This is the hard coded x path: //config-entry-metadata/parameter-name ... /../..//value/text()
The name of the parameter is dynamic: [text() = sql:column("BTC.Name")]
The new value is also dynamic: with sql:column("BTC.Value")

Search an replace text in column for Column Type Text SQL Server

What I need is to search for a string in a specific column (datatype: text) of a table and replace it with another text.
For example
Id | Text
-----------------------------
1 this is test
2 that is testosterone
If I chose to replace test with quiz, results should be
this is quiz
that is quizosterone
What I've tried so far?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[SearchAndReplace]
(
#FindString NVARCHAR(100)
,#ReplaceString NVARCHAR(100)
)
AS
BEGIN
SET NOCOUNT ON
SELECT CONTENT_ID as id, CONTENT_TEXT, textptr(CONTENT_TEXT) as ptr, datalength(CONTENT_TEXT) as lng
INTO #newtable6 FROM HTML_CONTENTS
DECLARE #COUNTER INT = 0
DECLARE #TextPointer VARBINARY(16)
DECLARE #DeleteLength INT
DECLARE #OffSet INT
SELECT #TextPointer = TEXTPTR(CONTENT_TEXT)
FROM #newtable6
SET #DeleteLength = LEN(#FindString)
SET #OffSet = 0
SET #FindString = '%' + #FindString + '%'
WHILE (SELECT COUNT(*)
FROM #newtable6
WHERE PATINDEX(#FindString, CONTENT_TEXT) <> 0) > 0
BEGIN
SELECT #OffSet = PATINDEX(#FindString, CONTENT_TEXT) - 1
FROM #newtable6
WHERE PATINDEX(#FindString, CONTENT_TEXT) <> 0
UPDATETEXT #newtable6.CONTENT_TEXT
#TextPointer
#OffSet
#DeleteLength
#ReplaceString
SET #COUNTER = #COUNTER + 1
END
select #COUNTER,* from #newtable6
drop table #newtable6
SET NOCOUNT OFF
I get the error:
Msg 7116, Level 16, State 4, Procedure SearchAndReplace, Line 31
Offset 1900 is not in the range of available LOB data.
The statement has been terminated.
Thank you
If you can't change your column types permanently, you can cast them on the fly:
ALTER PROC [dbo].[SearchAndReplace]
(#FindString VARCHAR(100),
#ReplaceString VARCHAR(100) )
AS
BEGIN
UPDATE dbo.HTML_CONTENTS
SET CONTENT_TEXT = cast (REPLACE(cast (CONTEXT_TEXT as varchar(max)), #FindString, #ReplaceString) as TEXT)
END
The datatype TEXT is deprecated and should not be used anymore - exactly because it's clunky and doesn't support all the usual string manipulation methods.
From the MSDN docs on text, ntext, image:
ntext, text, and image data types will
be removed in a future version of
MicrosoftSQL Server. Avoid using these
data types in new development work,
and plan to modify applications that
currently use them. Use nvarchar(max),
varchar(max), and varbinary(max)
instead.
My recommendation: convert that column to VARCHAR(MAX) and you should be fine after that!
ALTER TABLE dbo.HTML_CONTENTS
ALTER COLUMN CONTEXT_TEXT VARCHAR(MAX)
That should do it.
When your column is VARCHAR(MAX), then your stored procedures becomes totally simple:
ALTER PROC [dbo].[SearchAndReplace]
(#FindString VARCHAR(100),
#ReplaceString VARCHAR(100) )
AS
BEGIN
UPDATE dbo.HTML_CONTENTS
SET CONTENT_TEXT = REPLACE(CONTEXT_TEXT, #FindString, #ReplaceString)
END
Two observations on the side:
it would be helpful to have a WHERE clause in your stored proc, in order not to update the whole table (unless that's what you really need to do)
you're using TEXT in your table, yet your stored procedure parameters are of type NVARCHAR - try to stick to one set - either TEXT/VARCHAR(MAX) and regular VARCHAR(100) parameters, or then use all Unicode strings: NTEXT/NVARCHAR(MAX) and NVARCHAR(100). Constantly mixing those non-Unicode and Unicode strings is a mess and causes lots of conversions and unnecessary overhead

Resources