Is it possible to replace multiple words in a string in sql without using multiple replace functions?
For example I have a string where I need to replace word 'POLYESTER' with 'POLY' , 'COTTON' with 'CTN', 'GRAPHIC' with 'GRPHC' etc in order to keep the string length at a max of say 30 without much loosing the readability of contents in it(can't use substring to limit chars since it can trim the end meaningful parts of string completely). So we decided to short some keywords like above.
Current query I have used :
SELECT
REPLACE(REPLACE('**Some string value **COTTON **Some string value ** POLYESTER', 'POLYESTER', 'POLY'), 'COTTON', 'CTN')
If I have 10 keywords like this, what will be the best way to achieve the result other than using multiple replace function. I am using SQL Server 2012.
considering sql server is your only instrument (not a c# or another application), as a workaroud; use a temp or persistent table to store replacement options.
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
CREATE TABLE #tmp (
fromText VARCHAR(16),
toText VARCHAR(16)
);
INSERT INTO #tmp (fromText, toText)
VALUES
('POLYESTER', 'POLY'),
('COTTON', 'CTN'),
('GRAPHIC', 'GRPHC')
DECLARE #someValue AS NVARCHAR(MAX) =
'**Some string value **COTTON **Some string value ** POLYESTER';
SELECT #someValue = REPLACE(#someValue, fromText, toText) FROM #tmp;
PRINT #someValue
and the result is:
**Some string value **CTN **Some string value ** POLY.
The answer of mehmetx is actually very nice.
If you need your replacement functionality on a regular basis, you could think about using a normal table instead of a temporary table.
But if you need this logic only once in a while, and performance is not much of an issue, you could avoid the additional replacements table altogether and use a table expression in the FROM clause instead. Something like this:
DECLARE #someValue AS NVARCHAR(MAX) = '**Some string value **COTTON **Some string value ** POLYESTER';
SELECT #someValue = REPLACE(#someValue, fromText, toText)
FROM
(VALUES
('POLYESTER', 'POLY'),
('COTTON', 'CTN'),
('GRAPHIC', 'GRPHC')
) AS S (fromText, toText);
EDIT:
I noticed, that this logic regrettably does not work as expected when used in an UPDATE statement to update existing data in a table.
For that purpose (if needed), I created a user-defined function that performs the replacement logic. I called it MultiReplace. And it does not use the replacement data from a temporary table, but from a "normal" table, which I called Replacements.
The following code demonstrates it. It uses a data table called MyData, which gets updated with all replacements in the Replacements table using the MultiReplace function:
IF OBJECT_ID('MultiReplace') IS NOT NULL
DROP FUNCTION MultiReplace;
IF OBJECT_ID('Replacements') IS NOT NULL
DROP TABLE Replacements;
IF OBJECT_ID('MyData') IS NOT NULL
DROP TABLE MyData;
GO
CREATE TABLE Replacements (
fromText VARCHAR(100),
toText VARCHAR(100)
);
CREATE TABLE MyData (
SomeValue VARCHAR(MAX)
)
GO
CREATE FUNCTION MultiReplace(#someValue AS VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
SELECT #someValue = REPLACE(#someValue, fromText, toText) FROM Replacements;
RETURN #someValue;
END;
GO
INSERT INTO MyData (SomeValue)
VALUES
('**Some string value **COTTON **Some string value ** POLYESTER');
INSERT INTO Replacements (fromText, toText)
VALUES
('POLYESTER', 'POLY'),
('COTTON', 'CTN'),
('GRAPHIC', 'GRPHC');
SELECT * FROM MyData;
UPDATE MyData SET SomeValue = dbo.MultiReplace(SomeValue)
SELECT * FROM MyData;
But perhaps using multiple REPLACE statements might be more straightforward after all?...
EDIT 2:
Based on the short conversation in the comments, I could propose a simpler solution that uses multiple REPLACE statements in a clearer way. I have only tested it on SQL Server 2019; I am not sure if it will work correctly on SQL Server 2012.
Again, I use a table called MyData for testing here. But there are no additional database objects anymore.
Regrettably, I did not get it to work with a temporary table containing the replacement values.
-- Preparations:
IF OBJECT_ID('MyData') IS NOT NULL
DROP TABLE MyData;
CREATE TABLE MyData (
SomeValue VARCHAR(MAX)
);
INSERT INTO MyData
VALUES
('**Some string value **COTTON **Some string value ** POLYESTER'),
('**Another string value **GRAPHIC **Another string value ** POLYESTER');
-- Actual work:
SELECT * FROM MyData; -- Show the state before updating
DECLARE #someValue VARCHAR(MAX);
UPDATE MyData
SET
#someValue = SomeValue,
#someValue = REPLACE(#someValue, 'POLYESTER', 'POLY'),
#someValue = REPLACE(#someValue, 'COTTON', 'CTN'),
#someValue = REPLACE(#someValue, 'GRAPHIC', 'GRPHC'),
SomeValue = #someValue;
SELECT * FROM MyData; -- Show the state after updating
I have to pass the multivalue parameter to a stored procedure. The datatype which is passing from C# code is string[].
This is my stored procedure
CREATE PROCEDURE spRecords
#Department VARCHAR(MAX) = NULL
AS
BEGIN
SELECT
ItemDetails,
Total,
Department
FROM
ItemRecords
WHERE
(Department.Name IN (#Department) OR #Department IS NULL)
END
I get the following error message
Cannot convert from string[] to string
I saw this stack overflow second answer to declare variable like #INFO_ARRAY ARRAY nvarchar(max). But I don't know how I should apply that in my case
Update
I don't want to change any code from C#. I am using one tool that will directly pass string[] array parameter like datasource
I am looking for a way to remove quotes from a hiveconf variable string, so that I can use it also as part of a table name:
Basicaly, I have something like
set sub_name = "123";
select ${hiveconf:sub_name} from table_${hiveconf:sub_name};
And when executing I need it to work like:
select "123" from table_123;
For that, I could run with something like:
set variable = "123";
set table_subname = 123;
select ${hiveconf:variable} from table_${hiveconf:table_subname};
Which would then work as
select "123" from table_123;
But is there some elegant way how to use just the one variable, once as a string and once as a part of the table name?
hive> create table table_abc as select 'X' as x;
OK
x
hive> set sub_name=abc;
hive> select "${hiveconf:sub_name}" from table_${hiveconf:sub_name};
OK
_c0
abc
I know function name TestOptionalParameter and parameter name number.
parameter is optional and has default value, which can change later
the function is
CREATE FUNCTION TestOptionalParameter
(
#number int = 1
)
RETURNS TABLE
AS
RETURN
(
SELECT #number * #number as sqr
)
how can I get value 1 from another function (or stored procedure) in the same database?
UPDATE
basically I don't need the result of function (I can get it with select * from TestOptionalParameter(default));
I'm trying to know what is default value (1 in my example) and save it into variable (something like declare x int = dbo.GetDefaultValue('TestOptionalParameter', '#number'))
so I need equivalent of c# reflection (Can I retrieve default value of parameter in method?)
Based on your comment reply I think you want call function in another function with the current parameter value pass.
So I think, this example might work for you.
CREATE FUNCTION TestOptionalParameter
(
#number int = 1
)
RETURNS TABLE
AS
RETURN
(
SELECT #number * #number as sqr
)
CREATE FUNCTION TestOptionalParameterNew
(
#number int = 1
)
RETURNS TABLE
AS
RETURN
(
SELECT #number * #number as total from [dbo].[TestOptionalParameter](#number)
)
select * from TestOptionalParameterNew(4)
The only way to get the parameter value seems to be to parse the ROUTINE_DEFINITION column of the information_schema.routines view as apparently the value isn't stored in any column, but rather evaluated from the definition at runtime.
If you know the parameter name in advance and the text in the procedure is well-formed then something like this could work. Note that in this example the substring returned is only 1 character long, so if the value can be longer you would have to extract a longer string.
SELECT
SUBSTRING
(
routine_definition,
PATINDEX('%#number int = %', ROUTINE_DEFINITION) + 14,
1
) ParamValue
FROM information_schema.routines
WHERE routine_type = 'function' AND
routine_name = 'TestOptionalParameter'
If you don't know the parameter names they can be found in the view referenced above, so it should be possible to find all default values by parsing the text definition, although it won't be easy.
You can use the below query to get the details about function
SELECT * FROM information_schema.routines WHERE routine_type='function' AND routine_name ='TestOptionalParameter'
I already have a function in SQL Server 2005 as:
ALTER function [dbo].[fCalculateEstimateDate] (#vWorkOrderID numeric)
Returns varchar(100) AS
Begin
<Function Body>
End
I want to modify this function to accept addition optional parameter #ToDate. I am going to add logic in function if #Todate Provided then do something else continue with existing code.
I modified the function as:
ALTER function [dbo].[fCalculateEstimateDate] (#vWorkOrderID numeric,#ToDate DateTime=null)
Returns varchar(100) AS
Begin
<Function Body>
End
Now I can call function as:
SELECT dbo.fCalculateEstimateDate(647,GETDATE())
But it gives error on following call:
SELECT dbo.fCalculateEstimateDate(647)
as
An insufficient number of arguments were supplied for the procedure or
function dbo.fCalculateEstimateDate.
which as per my understanding should not happen.
Am I missing anything?
From CREATE FUNCTION:
When a parameter of the function has a default value, the keyword DEFAULT must be specified when the function is called to retrieve the default value. This behavior is different from using parameters with default values in stored procedures in which omitting the parameter also implies the default value.
So you need to do:
SELECT dbo.fCalculateEstimateDate(647,DEFAULT)
The way to keep SELECT dbo.fCalculateEstimateDate(647) call working is:
ALTER function [dbo].[fCalculateEstimateDate] (#vWorkOrderID numeric)
Returns varchar(100) AS
Declare #Result varchar(100)
SELECT #Result = [dbo].[fCalculateEstimateDate_v2] (#vWorkOrderID,DEFAULT)
Return #Result
Begin
End
CREATE function [dbo].[fCalculateEstimateDate_v2] (#vWorkOrderID numeric,#ToDate DateTime=null)
Returns varchar(100) AS
Begin
<Function Body>
End
I have found the EXECUTE command as suggested here T-SQL - function with default parameters to work well. With this approach there is no 'DEFAULT' needed when calling the function, you just omit the parameter as you would with a stored procedure.