Comparing two nvarchar in a function - sql

In a function I want to check whether passed value is equal to a predefined value (#ValX)
I have wrote following function:
ALTER Function IsNotInReview(#Val NVARCHAR(MAX))
RETURNS BIT
AS
BEGIN
DECLARE #ValX NVARCHAR(MAX)
SET #ValX = '
{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}
'
IF LTRIM(RTRIM(#Val)) = LTRIM(RTRIM(#ValX))
BEGIN
RETURN 1
END
ELSE
BEGIN
RETURN 0
END
RETURN 0
END
When I test call the function, I am always getting false value
SELECT dbo.IsNotInReview('
{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}
')--should return true
SELECT dbo.IsNotInReview('test')
UPDATE
I have updated my SP but still getting the same 'false' return value
ALTER Function IsNotInReview(#Val NVARCHAR(MAX))
RETURNS BIT
AS
BEGIN
DECLARE #ValX NVARCHAR(MAX)
SET #ValX = '
{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}
'
DECLARE #ReturnVal BIT
IF LTRIM(RTRIM(#Val)) = LTRIM(RTRIM(#ValX))
BEGIN
SET #ReturnVal = 1
END
ELSE
BEGIN
SET #ReturnVal = 0
END
RETURN #ReturnVal
END
SELECT dbo.IsNotInReview('{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}') --Return false which is unexpected

You are not comparing identical strings. Look at the indentation. I cannot imagine that this is what your intention is, i.e. comparing not only relevant content but also indentation.
A possible solution is to remove all white spaces, line breaks etc. in the string, while skipping over sections enclosed in double quotes.
Edit: Here is a little function which might be useful for you. It removes white spaces from your string while skipping quoted regions. Please test thoroughly, I only wrote it and testet it a bit (I have to go to work now)
create function RemoveWhiteSpaces (#String nvarchar(max))
returns nvarchar(max)
as
begin
declare #result nvarchar(max), #i int, #n int, #inQuotes bit,
declar #c0 nchar(1), #c nchar(1)
set #i=1
set #n=len(#string)
set #result=''
set #inQuotes=0
set #c='x'
while #i <= #n begin
set #c0=#c
set #c=substring(#string,#i,1)
if #c='"' and #c0 != '\'
set #inQuotes= 1 - #inQuotes
if #inQuotes = 1 or
(#inQuotes = 0 and #c not in (' ',char(13), char(10),char(8)))
set #result = #result + #c
set #i=#i+1
end
return #result
end

Related

Json input of a stored Procedure

I have a Stored Procedure with a JSON in input ,Is it possible to use the JSON as input for a stored procedure? how could i do that ?
CREATE PROCEDURE [warm].[stored _table]
(
#Json NVARCHAR(MAX)
)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN
WITH JsonToTable AS
(
SELECT * FROM OPENJSON (#Json) WITH (
[type] [nvarchar](100),
[source] [nvarchar](38),
[time] [nvarchar](28),
[ID] [varchar](50) '$.data.ID',
[RegionCode] [varchar](10)'$.data.RegionCode'
[DueDate] [datetime2](7)'$.data.DueDate',
[SchedulStartDate] [datetime2](7)'$.data.SchedulStartDate',
)
)
MERGE [warm].[table] AS TARGET
USING JsonToTable AS SOURCE
ON (TARGET.ID = SOURCE.ID)
WHEN MATCHED THEN
UPDATE SET
TARGET.[RegionCode] = (SOURCE.[RegionCode]
TARGET.[DueDate] = [dbo].[ufn_cast_string_to_date](SOURCE.[DueDate])
,TARGET.[SchedulStartDate] = [dbo].[ufn_cast_string_to_date](SOURCE.[SchedulStartDate])
WHEN NOT MATCHED THEN
INSERT
(
[SourceID]
,[ID]
,[RegionCode]
,[DueDate]
,[SchedulStartDate])
VALUES
(
1
,[ID]
,[RegionCode]
,[dbo].[ufn_cast_string_to_date](SOURCE.[DueDate])
,[dbo].[ufn_cast_string_to_date](SOURCE.[SchedulStartDate])
);
END
END TRY
END
I Want to execute it with the request below :
DECLARE #return_value int
EXEC #return_value = [warm].[usp_upsert_warm_table]
#Json = N'{
"type" : "table",
"source" : "informations",
"time" : "2018-04-05T17:31:00Z",
"id" : "A11-111-111",
"data" : {"
"ID":"123-56",
"RegionCode":"2",
"DueDate":"2020-13-14T10:54:00",
"SchedulStartDate":"2020-12-14T10:54:00"
}'}
I get this Message Error :
JSON text is not properly formatted. Unexpected character '.' is found at position 480.**
This is the Valid input :
DECLARE #return_value int
EXEC #return_value = [warm].[usp_upsert_warm_table]
#Json = N'
{
"type" : "table1",
"source" : "",
"id" : "A111-111-11",
"time" : "2020-12-14 10:54:00",
"data" :{
"ApplicationID":"INFORMATIONS",
"ID":"157faf1657c-100",
"RegionCode":"2",
"DueDate":"2020-12-14 10:54:00",
"SchedulStartDate":"2020-12-14 10:54:00"}'}
For my input date : 2020-12-14 10:54:00 i deleteed the T in the middle
for my S.P : I change the type of My variables from datetime To varchar :
CREATE PROCEDURE [warm].[usp_upsert_warm_table]
...
[ID] [varchar](50) '$.data.ID',
[RegionCode] [varchar](10)'$.data.RegionCode'
[DueDate] [varchar](40)'$.data.DueDate',
[SchedulStartDate] [varchar](10)'$.data.SchedulStartDate',
....

Replacing a string pattern - SQL Server

I have a VARCHAR Column called CompanyInformation that contains some Json data inside of it, here is a example of what is being stored inside of this column.
{
"tradeName": "example",
"corporateName": "example",
"phone": "example",
"nationalExpansions": [
{
"id": 0,
"nameFranchise": "example",
"phoneNumber": "example",
"mobileNumber": "example",
"email": "example#example.com.br"
},
{
"id": 0,
"nameFranchise": "example",
"phoneNumber": "example",
"mobileNumber": "example",
"email": "example"
},
What i have to do is replace all emails inside of this file to one specific email, i was trying to use the REPLACE function to do that, but i don`t know exactly how to do pattern matching in SQL.
UPDATE MyExampleTable SET CompanyInformation = REPLACE(CONVERT(VARCHAR(MAX), CompanyInformation), '"email": "%%"', '"email": "tests#gmail.com.br"')
But it doesn't work, the UPDATE gets executed, but he never replace the email information because he doesn't find any matching pattern.
After some research and thanks to the help of a teammate, we've managed to find a solution to this problem, so i will post here to help anyone with the same problem.
This is the script:
DECLARE #text VARCHAR(max)
DECLARE #start INT = 0
DECLARE #begin INT = 0
DECLARE #end INT = 0
DECLARE #Id INT
DECLARE curEmail CURSOR
FOR
SELECT Id, CompanyInformation
FROM MyExampleTable
--WHERE id = 1
OPEN curEmail
FETCH NEXT FROM curEmail INTO #Id, #text
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #start = CHARINDEX('"email":"', #text) + 9;
SET #begin = #start
WHILE 1 = 1
BEGIN
--print 'end='+cast(#end as varchar(4))
SELECT #start = CHARINDEX('"email":"', #text, #end) + 9;
IF #begin <= #start
SET #begin = #start
ELSE
BREAK
SELECT #end = CHARINDEX('"', #text, #start)
SET #text = STUFF(#text, #start, #end - #start, 'tests#gmail.com.br')
END
print #text
update MyExampleTable set CompanyInformation= #text where id =#id
FETCH NEXT FROM curEmail INTO #Id, #text
END
CLOSE curEmail
DEALLOCATE curEmail

SQL use return value of function as procedure parameter

Let's define:
create table cities
(
ID int identity,
name varchar(50) unique
)
create function getID (#name varchar(50)) returns int
begin
declare #id int
select #id=ID from cities where name=#name
return #id
end
create procedure addLine
#cityID int
as begin
...
end
Is it possible to execute a procedure with value returned by function, as follows?
exec addLine getID('Warsaw')
exec addLine dbo.getID('Warsaw')
exec addLine (select dbo.getID('Warsaw'))
I tried above and it did not help.
Microsoft says that this is not possible. You can not pass result of a function to procedure as a parameter:
[ { EXEC | EXECUTE } ]
{
...
[ [ #parameter = ] { value
| #variable [ OUTPUT ]
| [ DEFAULT ]
}
]
...
}
[;]
So, only constant values, variables and DEFAULT keyword are permitted.
2 possible ways of doing this are:
1: declare variable
declare #i int = dbo.getID('Warsaw')
exec addLine #i
2: use dynamic query
DECLARE #cmd NVARCHAR(MAX) = 'exec addLine ' + CAST(dbo.getID('Warsaw') AS NVARCHAR(MAX))
EXEC(#cmd)
This will "execute a procedure with value returned by function"
It just won't do it 'inline'
declare #id int
select #id = dbo.getID('Warsaw')
exec addLine #id

how use replace in exec statement in sql server 2008

I have a stored proc, say, "call_Me" with few parameters:
Declare #Greet varchar(100) = 'Hi ||User||'
Exec Call_Me 1,'something', #Greet --parameters: bit, string, string
during the call, I want to be able to replace the
||User||
bit with something else. normally, in a select statement, I would do this:
select 1, 'something', Replace(#Greet, '||User||', u.Username) from UserTable
which works fine, But today, for the first time, I am trying to use it in exec statement, the error says its expecting select, I tried adding select in every possible (and sensible) way but it just didnt seem to work out.
How can I use a replace during an execute statement call?
Many thanks in advance!
You'd need to format #Greet before passing it to the sproc:
Declare #Greet varchar(100) = 'Hi ||User||'
SELECT #Greet = Replace(#Greet, '||User||', u.Username)
FROM UserTable u
WHERE Id = 1
Exec Call_Me 1,'something', #Greet --parameters: bit, string, string
You can only use a literal or a variable reference in a procedure call:
[ { EXEC | EXECUTE } ]
{
[ #return_status= ]
{ module_name [ ;number ] | #module_name_var }
[ [ #parameter= ] { value
| #variable [ OUTPUT ]
| [ DEFAULT ]
}
]
[ ,...n ]
[ WITH RECOMPILE ]
}
[;]
Use this:
Declare #Greet varchar(100) = 'Hi ||User||'
Declare #param VARCHAR(100) = REPLACE(#Greet, '||User||', 'replacement')
Exec Call_Me 1,'something', #param
I am not sure if I understand correctly your problem, but maybe using cursor solves your problem:
DECLARE CURSOR users LOCAL FAST_FORWARD FOR
SELECT
username
FROM
usertable
OPEN
DECLARE #username NVARCHAR(50)
DECLARE #Greet VARCHAR(100) = 'Hi ||User||'
FETCH NEXT FROM users INTO #username
WHILE ##FETCH_STATUS = 0 BEGIN
EXEC Call_Me 1, 'something', REPLACE(#Greet, '||User||', #username)
FETCH NEXT FROM users INTO #username
END
CLOSE users
DEALLOCATE users
If you don't need to call it in loop you can try something like (this can be a new stored procedure):
DECLARE #username NVARCHAR(50)
DECLARE #Greet VARCHAR(100) = 'Hi ||User||'
SELECT
#username = username
FROM
usernames
WHERE
user_id = 1
IF ##ROWCOUNT = 1 BEGIN
EXEC Call_Me 1, 'something', REPLACE(#Greet, '||User||', #username)
END

How to get a distinct list of words used in all Field Records using MS SQL?

If I have a table field named 'description', what would be the SQL (using MS SQL) to get a list of records of all distinct words used in this field.
For example:
If the table contains the following for the 'description' field:
Record1 "The dog jumped over the fence."
Record2 "The giant tripped on the fence."
...
The SQL record output would be:
"The","giant","dog","jumped","tripped","on","over","fence"
I do not think you can do this with a SELECT. The best chance is to write a user defined function that returns a table with all the words and then do SELECT DISTINCT on it.
Disclaimer: Function dbo.Split is from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648
CREATE TABLE test
(
id int identity(1, 1) not null,
description varchar(50) not null
)
INSERT INTO test VALUES('The dog jumped over the fence')
INSERT INTO test VALUES('The giant tripped on the fence')
CREATE FUNCTION dbo.Split
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
CREATE FUNCTION dbo.SplitAll(#SplitOn nvarchar(5))
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
DECLARE My_Cursor CURSOR FOR SELECT Description FROM dbo.test
DECLARE #description varchar(50)
OPEN My_Cursor
FETCH NEXT FROM My_Cursor INTO #description
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #RtnValue
SELECT Data FROM dbo.Split(#description, #SplitOn)
FETCH NEXT FROM My_Cursor INTO #description
END
CLOSE My_Cursor
DEALLOCATE My_Cursor
RETURN
END
SELECT DISTINCT Data FROM dbo.SplitAll(N' ')
I just had a similar problem and tried using SQL CLR to solve it. Might be handy to someone
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Collections.Generic;
public partial class UserDefinedFunctions
{
private class SplitStrings : IEnumerable
{
private List<string> splits;
public SplitStrings(string toSplit, string splitOn)
{
splits = new List<string>();
// nothing, return empty list
if (string.IsNullOrEmpty(toSplit))
{
return;
}
// return one word
if (string.IsNullOrEmpty(splitOn))
{
splits.Add(toSplit);
return;
}
splits.AddRange(
toSplit.Split(new string[] { splitOn }, StringSplitOptions.RemoveEmptyEntries)
);
}
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return splits.GetEnumerator();
}
#endregion
}
[Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "readRow", TableDefinition = "word nvarchar(255)")]
public static IEnumerable fnc_clr_split_string(string toSplit, string splitOn)
{
return new SplitStrings(toSplit, splitOn);
}
public static void readRow(object inWord, out SqlString word)
{
string w = (string)inWord;
if (string.IsNullOrEmpty(w))
{
word = string.Empty;
return;
}
if (w.Length > 255)
{
w = w.Substring(0, 254);
}
word = w;
}
};
It is not the fastest approach but might be used by somebody for a small amount of data:
declare #tmp table(descr varchar(400))
insert into #tmp
select 'The dog jumped over the fence.'
union select 'The giant tripped on the fence.'
/* the actual doing starts here */
update #tmp
set descr = replace(descr, '.', '') --get rid of dots in the ends of sentences.
declare #xml xml
set #xml = '<c>' + replace(
(select ' ' + descr
from #tmp
for xml path('')
), ' ', '</c><c>') + '</c>'
;with
allWords as (
select section.Cols.value('.', 'varchar(250)') words
from #xml.nodes('/c') section(Cols)
)
select words
from allWords
where ltrim(rtrim(words)) <> ''
group by words
In SQL on it's own it would probably need to be a big stored procedure, but if you read all the records out to the scripting language of your choice, you can easily loop over them and split each out into arrays/hashes.
it'd be a messy stored procedure with a temp table and a SELECT DISTINCT at the end.
if you had the words already as records, you would use SELECT DISTINCT [WordsField] from [owner].[tablename]