StoredprocedureinMSSQLtoMySQL - mysql

I have a stored procedure in MSSQl, i would like to write it int My sql,
Any help or sugegstions please.I can not get to use XML function in Mysql.
stored proc:
ALTER PROCEDURE uspGetProductDetailsCSV (
#sku NVARCHAR(MAX)
)
AS
BEGIN
-
SELECT T.C.value('.', 'NVARCHAR(100)') AS [SKU]
INTO #tblPersons
FROM (SELECT CAST ('<Name>' + REPLACE (#sku, ',', '</Name><Name>')
+ '</Name>' AS XML) AS [Products]) AS A
CROSS APPLY Products.nodes('/Name') as T(C)
SELECT *
FROM ProductInformation Pr
WHERE EXISTS (SELECT Name FROM #tblPersons tmp WHERE tmp.SKU
= case when len(tmp.SKU) = 11 then Product_No+Colour_Code+Size_Code
when len(tmp.SKU) = 8 then Product_No+Colour_Code
when len(tmp.sku) = 6 then Product_No end)
DROP TABLE #tblPersons
END
Edit: I could not write XML part of stored proc, as i have pasted same code in Mysql, it doesnt create stored proc
Error: >can not cast as XML<

I dont believe XML is a valid type in MySql. Try just leaving it as a VARCHAR.
So, just remove the cast...I also think you will have to use CONCAT instead of + and change the [] around columns to ticks.
So Instead of:
FROM (SELECT CAST ('<Name>' + REPLACE (#sku, ',', '</Name><Name>')
+ '</Name>' AS XML) AS [Products]) AS A
TRY:
FROM (SELECT CONCAT('<Name>' , REPLACE(#sku, ',', '</Name><Name>'),
'</Name>') AS `Products`) AS A

Related

T-SQL How can I query a column with incorrect JSON?

I've been asked to create a VIEW off a table that includes a varchar(MAX) column containing a JSON string. Unfortunately, some of the entries contain double quotes that aren't escaped.
Example (invalid in Notes):
{"Eligible":"true","Reason":"","Notes":"Left message for employee to "call me"","EDate":"08/16/2021"}
I don't have access to correct wherever this is being inserted so I just have to work with the data as is.
So in my view I need to find a way to escape those double quotes.
I'm pulling the data like so:
JSON_VALUE(JsonData, '$.Notes') as Notes
However, I get the following error:
JSON text is not properly formatted. Unexpected character '"' is found at position 102.
I can't do a simple replace on the whole field because that would create invalid JSON also.
I tried JSON_MODIFY but run into the problem of getting the notes field to replace itself.
JSON_MODIFY(JsonData, '$.Notes', REPLACE(JSON_VALUE(JsonData, '$.Notes'), '"', '\"'))
Maybe I'm missing something obvious, but I can't figure out how to handle this. Is there a way to escape those double quotes in my query?
So this is incredibly hacky and there are probably several examples that could break it as is, but if you absolutely can't fix your source data output or simply flag bad JSON for manual adjustment, this may be the route you need to take and further flesh out.
Based on your example and a couple extras I have thrown in, with the help of a custom string splitting table valued function that maintains sort order, you can achieve the output as follows:
Query
declare #t table (JsonData nvarchar(max));
insert into #t values('{"Eligible":true,"Reason":"","Notes":"Left message for employee to "call me"","EDate":"08/16/2021","Test": "999","Another Test":"Value with " character"}');
with q as
(
select t.JsonData
,s.rn
,case when right(trim(lag(s.item,1) over (order by s.rn)),1) in('{',':',',')
then '"'
else ''
end -- Do we need a starting double quote?
+ s.item -- Value from the split text
+ case when right(trim(lead(s.item,1) over (order by s.rn)),1) not in('}',':',',')
and right(trim(s.item),1) not in('{','}',':',',')
then '\"'
else ''
end -- Do we need an escaped double quote?
+ case when left(trim(lead(s.item,1) over (order by s.rn)),1) in('}',':',',')
then '"'
else ''
end -- Do we need an ending double quote?
as Quoted
from #t as t
cross apply dbo.fn_StringSplit4k(t.JsonData,'"',null) as s -- By splitting on " characters, we know where they all are even though they are removed, so we can add them back in as required based on the remaining text
)
,j as
(
select JsonData
,string_agg(Quoted,'') within group (order by rn) as JsonFixed
from q
group by JsonData
)
select json_value(JsonFixed, '$.Eligible') as Eligible
,json_value(JsonFixed, '$.Reason') as Reason
,json_value(JsonFixed, '$.Notes') as Notes
,json_value(JsonFixed, '$.EDate') as EDate
,json_value(JsonFixed, '$.Test') as Test
,json_value(JsonFixed, '$."Another Test"') as AnotherTest
from j;
Output
Eligible
Reason
Notes
EDate
Test
AnotherTest
true
Left message for employee to "call me"
08/16/2021
999
Value with " character
String Splitter
create function [dbo].[fn_StringSplit4k]
(
#str nvarchar(4000) = ' ' -- String to split.
,#delimiter as nvarchar(1) = ',' -- Delimiting value to split on.
,#num as int = null -- Which value to return.
)
returns table
as
return
-- Start tally table with 10 rows.
with n(n) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1)
-- Select the same number of rows as characters in #str as incremental row numbers.
-- Cross joins increase exponentially to a max possible 10,000 rows to cover largest #str length.
,t(t) as (select top (select len(isnull(#str,'')) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4)
-- Return the position of every value that follows the specified delimiter.
,s(s) as (select 1 union all select t+1 from t where substring(isnull(#str,''),t,1) = #delimiter)
-- Return the start and length of every value, to use in the SUBSTRING function.
-- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string.
,l(s,l) as (select s,isnull(nullif(charindex(#delimiter,isnull(#str,''),s),0)-s,4000) from s)
select rn
,item
from(select row_number() over(order by s) as rn
,substring(#str,s,l) as item
from l
) a
where rn = #num
or #num is null;
I would like to suggest a stored procedure along these lines:
CREATE FUNCTION dbo.clearJSon(#v nvarchar(max)) RETURNS nvarchar(max)
AS
BEGIN
DECLARE #i AS int
DECLARE #security int
SET #i=PATINDEX('%[^{:,]"[^,:}]%',#v)
SET #security=0 -- just to prevent an endless loop
WHILE #i>0 and #security<100
BEGIN
SET #v = LEFT(#v,#i)+''''+SUBSTRING(#v,#i+2,len(#v))
SET #i=PATINDEX('%[^{:,]"[^,:}]%',#v)
SET #security = #security+1
END
RETURN #v
END
which returns
{"Eligible":"true","Reason":"","Notes":"Left message for employee to 'call me'","EDate":"08/16/2021"} as the result of dbo.clearJSon(JsonData)
I have to admit though, that the above code would fail, if the unescaped quotes would be followed by one of ,:} or if it would trail one of {:,

Update/Delete JSON array value in SQL Server

I have a json array in my table. It contains an array. I can create, append or make my array NULL. Inside my stored procedure but I don't see any way to pop value from array. Apparently JSON_Modify may have solution as you can update key as well as Single value but how can I use it to modify my array?
--My Array
Declare #json = '{"array":[123,456]}'
Desired results after update:
'{"array":[123]}'
Please note that array contain int values. Which are my sub department id. All values are (supposed to be) unique.
You could use:
DECLARE #json NVARCHAR(MAX) = '{"array":[123,456]}';
WITH cte AS (
SELECT *, MAX([key]) OVER() AS m_key
FROM OPENJSON(#json, '$.array') s
)
SELECT JSON_QUERY('[' + IIF(MAX(m_key) = 0, '', STRING_AGG(value,',')
WITHIN GROUP (ORDER BY [key])) + ']','$') AS array
FROM cte
WHERE [key] != m_key OR m_key = 0
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER;
Output:
{"array":[123]}
DBFiddle Demo SQL Server 2017
As I was in hurry I solved my problem following way, but I would really recommend not to use it. Please see answer above by #lad2025.
DECLARE #json VARCHAR(MAX)
=(SELECT jsonDept
FROM tblEmployee
WHERE tblEmployeeID = #empid)
DECLARE #newjson VARCHAR(MAX)= (
SELECT LEFT(subdept, LEN(subdept)-1)
FROM (
SELECT Distinct value + ', ' FROM OPENJSON(#json,'$.array') Where value <> #subdeptid
FOR XML PATH ('')
) t (subdept))
UPDATE tblEmployee SET jsonDept = '{"array":['+ #newjson +']}' WHERE tblEmployeeID = #empid

SSRS issue with using dynamic fields in SP

I have a SP like this:
ALTER PROCEDURE [dbo].[ReportGateWay]
(
#ISO bigint= 0,
#Gateway bigint= 0
)
AS
BEGIN
DECLARE #SQL nvarchar(max)
SET #SQL= 'SELECT * FROM
(
SELECT DISTINCT I.DBAName [ISOName], BG.GatewayName
FROM Iso I
LEFT OUTER JOIN BusinessGateway BG
ON I.GatewayName = BG.MerchantBusinessGatewayId AND I.IsActive = 1 and BG.IsActive = 1
WHERE ('+CAST(#ISO AS varchar(10))+' = 0 OR I.IsoId = '+ CAST(#ISO AS varchar(10)) +')
AND ('+CAST(#Gateway AS varchar(10))+' = 0 OR BG.MerchantBusinessGatewayId = '+ CAST(#Gateway AS varchar(10)) +')
) AS tb1
PIVOT
(
Count(GatewayName) for GatewayName in ('+ SUBSTRING((SELECT ',[' + BG.GatewayName + ']' FROM BusinessGateway BG
WHERE #Gateway = 0 OR BG.MerchantBusinessGatewayId = #Gateway
FOR XML PATH('')), 2, 200000 ) + ')
) AS pvt
ORDER BY pvt.ISOName'
EXECUTE (#SQL)
END
I need to invoke this in SSRS. The problem is that when on creating dataset for this, I get an error which read:
You must have atleast one field for your dataset
What can be done in this case?
You have this error message because SSRS cannot infer your schema from the query.
You could declare manually your fields in DataSet Properties => Fields:
Field Name, Field Source
ISOName, ISOName
Gateway1, Gateway1
Gateway2, Gateway2
EDIT
If you really want to have dynamic columns and can't define static column names, you could try a trick like this.
The idea is to create a function returning an Arraylist containing Column headers and values.
Why are you not executing the Procedure by creating a dataset of query type "Stored Procedure"?
By doing this you will be able to see the fields getting returned from the SP in your dataset.
You can also pass the parameter values to the SP by creating the report parameters.
Edit:
How to pass parameter to SP in SSRS:
Say you have sp as below:
create procedure [dbo].[TestProcpk] #value varchar(20)
as
select * from testProc where value = #value
You have to create parameters with same name as above i.e. #value.
I have below data in testProc:
ID|Value
1|xxx
2|yyy
3|zzz
If I run the report with parameter value of xxx, I will get 1|xxx only.
Also, You don't have to specify anything after selecting the SP from drop down.
How you are not able to pass param value to SP?

splitting a row in sql with different information in sql server [duplicate]

How to split a string in SQL Server.
Example:
Input string: stack over flow
Result:
stack
over
flow
if you can't use table value parameters, see: "Arrays and Lists in SQL Server 2008 Using Table-Valued Parameters" by Erland Sommarskog , then there are many ways to split string in SQL Server. This article covers the PROs and CONs of just about every method:
"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog
You need to create a split function. This is how a split function can be used:
SELECT
*
FROM YourTable y
INNER JOIN dbo.yourSplitFunction(#Parameter) s ON y.ID=s.Value
I prefer the number table approach to split a string in TSQL but there are numerous ways to split strings in SQL Server, see the previous link, which explains the PROs and CONs of each.
For the Numbers Table method to work, you need to do this one time table setup, which will create a table Numbers that contains rows from 1 to 10,000:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Once the Numbers table is set up, create this split function:
CREATE FUNCTION [dbo].[FN_ListToTable]
(
#SplitOn char(1) --REQUIRED, the character to split the #List string on
,#List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(#SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = #SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
You can now easily split a CSV string into a table and join on it:
select * from dbo.FN_ListToTable(' ','stack over flow')
OUTPUT:
ListValue
-------------------
stack
over
flow
(3 row(s) affected)
A common set-based solution to this kind of problem is to use a numbers table.
The following solution uses a simple recursive CTE to generate the numbers table on the fly - if you need to work with longer strings, this should be replaced with a static numbers table.
DECLARE #vch_string varchar(max)
DECLARE #chr_delim char(1)
SET #chr_delim = ' '
SET #vch_string = 'stack over flow'
;WITH nums_cte
AS
(
SELECT 1 AS n
UNION ALL
SELECT n+1 FROM nums_cte
WHERE n < len(#vch_string)
)
SELECT n - LEN(REPLACE(LEFT(s,n),#chr_delim,'')) + 1 AS pos
,SUBSTRING(s,n,CHARINDEX(#chr_delim, s + #chr_delim,n) -n) as ELEMENT
FROM (SELECT #vch_string as s) AS D
JOIN nums_cte
ON n <= LEN(s)
AND SUBSTRING(#chr_delim + s,n,1) = #chr_delim
OPTION (MAXRECURSION 0);
I know this question was for SQL Server 2008 but things evolve so starting with SQL Server 2016 you can do this
DECLARE #string varchar(100) = 'Richard, Mike, Mark'
SELECT value FROM string_split(#string, ',')
CREATE FUNCTION [dbo].[Split]
(
#List varchar(max),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(max)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
Create Above Function And Execute Belowe Query To Get Your Result.
Select * From Dbo.Split('Stack Over Flow',' ')
Suggestion : use delimiter for get split value. it's better. (for ex. 'Stack,Over,Flow')
Hard. Really hard - Strin Manipulation and SQL... BAD combination. C# / .NET for a stored procedure is a way, could return a table defined type (table) with one item per row.

SQL Server: Split operation

How to split a string in SQL Server.
Example:
Input string: stack over flow
Result:
stack
over
flow
if you can't use table value parameters, see: "Arrays and Lists in SQL Server 2008 Using Table-Valued Parameters" by Erland Sommarskog , then there are many ways to split string in SQL Server. This article covers the PROs and CONs of just about every method:
"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog
You need to create a split function. This is how a split function can be used:
SELECT
*
FROM YourTable y
INNER JOIN dbo.yourSplitFunction(#Parameter) s ON y.ID=s.Value
I prefer the number table approach to split a string in TSQL but there are numerous ways to split strings in SQL Server, see the previous link, which explains the PROs and CONs of each.
For the Numbers Table method to work, you need to do this one time table setup, which will create a table Numbers that contains rows from 1 to 10,000:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Once the Numbers table is set up, create this split function:
CREATE FUNCTION [dbo].[FN_ListToTable]
(
#SplitOn char(1) --REQUIRED, the character to split the #List string on
,#List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(#SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = #SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
You can now easily split a CSV string into a table and join on it:
select * from dbo.FN_ListToTable(' ','stack over flow')
OUTPUT:
ListValue
-------------------
stack
over
flow
(3 row(s) affected)
A common set-based solution to this kind of problem is to use a numbers table.
The following solution uses a simple recursive CTE to generate the numbers table on the fly - if you need to work with longer strings, this should be replaced with a static numbers table.
DECLARE #vch_string varchar(max)
DECLARE #chr_delim char(1)
SET #chr_delim = ' '
SET #vch_string = 'stack over flow'
;WITH nums_cte
AS
(
SELECT 1 AS n
UNION ALL
SELECT n+1 FROM nums_cte
WHERE n < len(#vch_string)
)
SELECT n - LEN(REPLACE(LEFT(s,n),#chr_delim,'')) + 1 AS pos
,SUBSTRING(s,n,CHARINDEX(#chr_delim, s + #chr_delim,n) -n) as ELEMENT
FROM (SELECT #vch_string as s) AS D
JOIN nums_cte
ON n <= LEN(s)
AND SUBSTRING(#chr_delim + s,n,1) = #chr_delim
OPTION (MAXRECURSION 0);
I know this question was for SQL Server 2008 but things evolve so starting with SQL Server 2016 you can do this
DECLARE #string varchar(100) = 'Richard, Mike, Mark'
SELECT value FROM string_split(#string, ',')
CREATE FUNCTION [dbo].[Split]
(
#List varchar(max),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(max)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
Create Above Function And Execute Belowe Query To Get Your Result.
Select * From Dbo.Split('Stack Over Flow',' ')
Suggestion : use delimiter for get split value. it's better. (for ex. 'Stack,Over,Flow')
Hard. Really hard - Strin Manipulation and SQL... BAD combination. C# / .NET for a stored procedure is a way, could return a table defined type (table) with one item per row.