Incorrect syntax while parsing JSON with OPENJSON - json

This is my SP, I am trying to parse this and the error
Incorrect syntax near '$.Role'
was shown.
The JSON is stored in a tables's column. What am I doing wrong?
CREATE PROCEDURE [dbo].[sp_GetKeyPersonRoleMinMax]
#SectionID INT,
#ProposalID INT
AS
SET NOCOUNT ON
Declare #FldKPRoleRequirementsList NVARCHAR(MAX)
Declare #FldName varchar(50)
DEclare #FldIncl varchar(50)
Declare #FldRequired varchar(50)
Declare #FldLabel varchar(max)
Declare #FldList varchar(max)
CREATE Table #RoleMinMaxTemp
(
ID INT IDENTITY(1, 1) ,
Role nvarchar(1000),
MinRoleCount INT,
MaxRoleCount INT
)
Declare Fld_Cursor Cursor For
SELECT FldName, FldIncl, FldRequired, FldLabel,FldList from tblFld where FldParent = 1367 AND FldName like 'FldKPRoleRequirementsList%'
SET NOCOUNT ON
Open Fld_Cursor
WHILE (##Fetch_Status = 0)
BEGIN
if (#FldName = 'FldKPRoleRequirementsList')
BEGIN
SET #FldKPRoleRequirementsList = #FldList
END
FETCH next from Fld_Cursor into #FldName, #FldIncl, #FldRequired, #FldLabel,#FldList
END
Close Fld_Cursor
Deallocate Fld_Cursor
IF(#FldKPRoleRequirementsList IS NOT NULL and Len(#FldKPRoleRequirementsList) >0)
BEGIN
INSERT INTO #RoleMinMaxTemp
SELECT *
FROM OPENJSON(#FldKPRoleRequirementsList,'$.FldRole')
WITH (
Role nvarchar(1000) '$.Role',
MinRoleCount INT '$.MinRoleCount',
MaxRoleCount INT '$.MaxRoleCount'
);
END;
What is the reason for this error? I am using SQL Server 2016.

Try changing you compactibility of SQL SERVER to 130. Your must be below that.
ALTER DATABASE <DatabaseName> SET COMPATIBILITY_LEVEL = 130
Use this script to change it.

Related

What seems to be the error here in the below code?

Error Code: 2014 Commands out of sync; you can't run this command now
Platform- My SQL Workbench
DELIMITER//
DROP PROCEDURE IF EXISTS must_watch_movies;
CREATE PROCEDURE
must_watch_movies ()
BEGIN DECLARE mTitle
VARCHAR (45);
DECLARE mDistributor VARCHAR (45);
DECLARE mRelease datetime;
DECLARE result VARCHAR (1000);
DECLARE no_records INTEGER DEFAULT FALSE;
DECLARE cursor_movies CURSOR FOR
SELECT title, Distributor, year (release_date)
FROM movies WHERE gross > 200000000 ORDER BY title;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET SET no_records = TRUE;
OPEN cursor_movies;
WHILE no_records = FALSE DO
FETCH cursor_movies INTO mTitle, mDistributor, mRelease;
SET result =
CONCAT ("'", mTitle, "','" mDistributor, "','" mRelease, "|");
END WHILE;
CLOSE cursor_movies;
SELECT result AS "Output";
END//
DELIMITER;
CALL must_watch_movies();
The declared values match the datatypes for actual column values in the table.
like mTitle and title are the same type
You have some errors in your code
A double SET when you decalre a handler
You have to concat result if you want all movies.
The out put must be some what more complicated, but i leave that to you
CREATE TABLE movies (title varchar(10),Distributor varchar(19), release_date date,gross BIGINT)
INSERT INTO movies VALUES('text1','text2', NOW(),200000001),('text3','text4', NOW(),200000001),('text5','text6', NOW(),200000001)
CREATE PROCEDURE
must_watch_movies ()
BEGIN DECLARE mTitle
VARCHAR (45);
DECLARE mDistributor VARCHAR (45);
DECLARE mRelease INT;
DECLARE result VARCHAR (1000) DEFAULT "";
DECLARE no_records INTEGER DEFAULT FALSE;
DECLARE cursor_movies CURSOR FOR
SELECT title, Distributor, year (release_date)
FROM movies WHERE gross > 200000000 ORDER BY title;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_records = TRUE;
OPEN cursor_movies;
WHILE no_records = FALSE DO
FETCH cursor_movies INTO mTitle, mDistributor, mRelease;
SET result = CONCAT (result,"'", mTitle, "','", mDistributor, "','", mRelease, "|");
END WHILE;
CLOSE cursor_movies;
SELECT result AS "Output";
END
CALL must_watch_movies()
| Output |
| :--------------------------------------------------------------------------------------- |
| 'text1','text2','2021|'text3','text4','2021|'text5','text6','2021|'text5','text6','2021| |
✓
db<>fiddle here

MySQL - Using SELECT INTO statement inside cursor in stored procedure

I am writing stored procedure in MySQL database using cursor to iterate on records. I am able to fetch records inside variables specified in FETCH statement, but when I use SELECT inside cursor, I am not able to store result in variables. I know its possible but can't find out why its not working in below MySQL code.
CREATE DEFINER=`root`#`localhost` PROCEDURE `add_monthly_leave_entitlement`
(IN `emp` INT(10), OUT `experience` INT(10), OUT `entitlement` DECIMAL(10,4)) DETERMINISTIC
BEGIN
DECLARE emp_no INT(10);
DECLARE current_month_exp INT(10);
DECLARE previous_month_end_exp INT(10);
DECLARE emp_status INT(10);
DECLARE done INT DEFAULT FALSE;
DECLARE monthly_entitlement decimal(8,4) DEFAULT 0;
DECLARE emp_cursor CURSOR FOR
SELECT e.`emp_number` AS emp_no,
TIMESTAMPDIFF( YEAR, e.`joined_date` , NOW( ) ) AS month_start_exp,
TIMESTAMPDIFF( YEAR, e.`joined_date`, LAST_DAY(NOW()- INTERVAL 1 MONTH) ) AS last_month_end_exp, e.`emp_status` AS emp_status
FROM `hs_hr_employee` AS e
WHERE e.`termination_id` is null AND e.`emp_number`=emp;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN emp_cursor;
read_loop : LOOP
FETCH emp_cursor INTO emp_no, current_month_exp, previous_month_end_exp, emp_status;
IF done THEN
LEAVE read_loop;
END IF;
/*Monthly entitlement as per experience*/
SELECT `monthly_entitlement` INTO monthly_entitlement
FROM `ohrm_leave_entitlement_conf`
WHERE `year_completion` = IF(previous_month_end_exp >4 , 5, previous_month_end_exp)
AND `leave_type_id` = 4;
SET experience = previous_month_end_exp;
SET entitlement = monthly_entitlement;
END LOOP;
CLOSE emp_cursor;
END
Not able to get value inside monthly_entitlement or entitlement, the value is always 0.0000.
I tried to run monthly entitlement query in separate procedure, it returns correct value. I have match data types of table column and variables.
Can somebody help me to understand what is wrong here ?
Avoid naming local variables as columns name, see Chapter 2 Restrictions on Stored Programs :: Name Conflicts within Stored Routines. Try changing the following:
...
-- DECLARE monthly_entitlement decimal(8,4) DEFAULT 0;
DECLARE _monthly_entitlement decimal(8,4) DEFAULT 0;
...
/*Monthly entitlement as per experience*/
-- SELECT `monthly_entitlement` INTO monthly_entitlement
SELECT `monthly_entitlement` INTO _monthly_entitlement
...
-- SET entitlement = monthly_entitlement;
SET entitlement = _monthly_entitlement;
...
As suggested by others the Name of the local variable and the column name should be different, So here the changes
CREATE DEFINER=`root`#`localhost` PROCEDURE `add_monthly_leave_entitlement`
(IN `emp` INT(10), OUT `experience` INT(10), OUT `entitlement` DECIMAL(10,4)) DETERMINISTIC
BEGIN
DECLARE v_emp_no INT(10);
DECLARE v_current_month_exp INT(10);
DECLARE v_previous_month_end_exp INT(10);
DECLARE v_emp_status INT(10);
DECLARE done INT DEFAULT FALSE;
DECLARE v_monthly_entitlement decimal(8,4) DEFAULT 0;
DECLARE emp_cursor CURSOR FOR
SELECT e.`emp_number` AS emp_no,
TIMESTAMPDIFF( YEAR, e.`joined_date` , NOW( ) ) AS month_start_exp,
TIMESTAMPDIFF( YEAR, e.`joined_date`, LAST_DAY(NOW()- INTERVAL 1 MONTH) ) AS last_month_end_exp, e.`emp_status` AS emp_status
FROM `hs_hr_employee` AS e
WHERE e.`termination_id` is null AND e.`emp_number`=emp;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN emp_cursor;
read_loop : LOOP
FETCH emp_cursor INTO v_emp_no, v_current_month_exp, v_previous_month_end_exp, v_emp_status;
IF done THEN
LEAVE read_loop;
END IF;
/*Monthly entitlement as per experience*/
SELECT `monthly_entitlement` INTO v_monthly_entitlement
FROM `ohrm_leave_entitlement_conf`
WHERE `year_completion` = IF(v_previous_month_end_exp >4 , 5, v_previous_month_end_exp)
AND `leave_type_id` = 4;
SET experience = v_previous_month_end_exp;
SET entitlement = v_monthly_entitlement;
END LOOP;
CLOSE emp_cursor;
END

Sorting integers in a string with TSQL

I am trying to sort a string such as '3,9,6' to '3,6,9' with TSQL. My approach was extracting the characters from the string, casting them as integers and putting them into a #temptable using a primary key for sorting. For this I created this procedure:
create proc sortstring(#string varchar(50))
as
declare #limit int = len(#string)
declare #counter int = 1
declare #temps char
create table #temptable (tempstring varchar(30) primary key)
while #counter<=#limit
begin
set #temps = SUBSTRING(#string,#counter,1)
if(#temps!=',')
insert into #temptable values (CAST(#temps as int))
set #counter= #counter+1
end
After this process, I was thinking to extract the integers from #temptable with a while loop to create the sorted string format '3,6'9'. But I think my whole approach is not performance efficient.
Any suggestions?
Below method should be a bit better than the while loop
declare #string varchar(255) = '3,9,6,0,5,12,88,15,23,45,77,88,125,1'
declare #TableList table (tmpStr int)
DECLARE #XML XML
SET #XML = '<root><csv>' + replace(#string, ',', '</csv><csv>') + '</csv></root>'
INSERT #TableList
SELECT replace(Word.value('.', 'integer'), CHAR(10), '')
FROM #XML.nodes('/root/csv') AS WordList(Word)
select * from #TableList order by 1
go
IF OBJECT_ID('tempdb.dbo.#TableList') IS NOT NULL
DROP TABLE #TableList
create table #TableList (tmpStr int)
declare #string varchar(255) = '3,9,6,0,5,12,88,15,23,45,77,88,125,1'
SET #string = 'SELECT ' + REPLACE(#string,',',' UNION ALL SELECT ')
SET #string='INSERT INTO #TableList (tmpStr) ' + #string
EXEC( #string)
SELECT * FROM #TableList ORDER BY tmpStr
Its not a conventional approach but it runs fast.

Default nvarchar parameter not respected

I have a stored procedure in SQL Server 2008 R2 with the following parameter values declared:
#UN nvarchar(30),
#SN nvarchar(8),
#GG uniqueidentifier,
#Ss irnapp.SymbolTableType READONLY,
#SD date,
#ED date,
#IR nvarchar(1),
#ID nvarchar(1),
#NR int = NULL,
#GP nvarchar(1) = N'N'
It was my intention that if the #GP value is not supplied, then it should be given a value of N'N'. However, the procedure only returns the expected results when I explicitly pass in N'N' for #GP.
I've attempted searching for examples of SQL stored procedures with default parameter values, but the only examples I've found for nvarchar are defaults of NULL, which is not feasible for my application.
Would anyone know if the above is a legal default parameter declaration?
UPDATE:
Thanks Aaron for the quick response. I was hoping this would be a simple catch, as the code is quite lengthy. That said, here goes:
BEGIN TRY
DECLARE #GI int;
EXEC irn.GetGroupID #UN, #SN, #GG, #GI OUT;
DECLARE #CUID int;
IF #GP = N'Y'
BEGIN
SELECT #CUID = UserID
FROM Users
WHERE Uname = #UN
AND SNum = #SN;
END;
DECLARE #NoteIDs irn.NoteIDTableType;
INSERT INTO #NIDs (NO, NID)
SELECT *
FROM GetNIDs(#GI, #Ss, #SD, #ED, #IR, #ID, #NR, #GP, #CUID);
EXEC GetNsByNIDs #NIDs, N'N';
END TRY
BEGIN CATCH
EXEC irn.CreateProcedureErrorLog
EXEC irn.RaiseProcedureError
END CATCH;
ALTER FUNCTION [i].[GetNIDs] (
#GID int,
#Ss SymbolTableType READONLY,
#SD date,
#ED date,
#IR nvarchar(1),
#ID nvarchar(1),
#NR int,
#GP nvarchar(1) = N'N',
#CUID int = NULL)
RETURNS #TopOrderedMatchingNote TABLE (
NO int NOT NULL PRIMARY KEY,
NID int NOT NULL UNIQUE)
AS
BEGIN
INSERT INTO #MN (NID)
SELECT NID
FROM N
WHERE GID = #GID
AND ND >= #FDate
AND ND <= #TDate
AND IP = #GP
AND ((IP = N'Y' AND CUID = #CUID) OR (IP = N'N'))
AND IsDeleted = CASE #IncludeDeleted
WHEN N'N' THEN N'N'
ELSE IsDeleted
END;
END;
...snip...
Hope this is helpful and thanks again
Yes, your default parameter declaration example is valid and legal. Here is a quick repro:
USE tempdb;
GO
CREATE PROCEDURE dbo.splunge
#GP nvarchar(1) = N'N'
AS
BEGIN
SET NOCOUNT ON;
SELECT COALESCE(#GP, N'Y');
END
GO
EXEC dbo.splunge;
EXEC dbo.splunge #GP = N'Y';
Results:
----
N
----
Y
If you're having problems getting this to work, you'll need to post more of your code to demonstrate what that means.

how to use openrowset to execute a stored procedure with parameters

I'm creating a stored procedure which gets some parameters and in turn these parameters are sent to another stored procedure which I'm calling from openrowset but I'm getting some syntax errors.
CREATE PROCEDURE UpdatePrevFYConfigData
-- Add the parameters for the stored procedure here
#startDate datetime,
#endDate datetime,
#productGroup varchar(8000) = 'All',
#projectType varchar(500) = 'All',
#businessUnit nvarchar(50) = 'All',
#developmentLocation nvarchar(100) = 'All'
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #start varchar(50)
declare #end varchar(50)
set #start = cast(#startDate as varchar(40))
set #end = cast(#endDate as varchar(40))
-- Insert statements for procedure here
select round(avg(a.DeviationDeadline),2) as DeviationDeadline,
round(avg(a.DeviationDefinition),2) as DeviationDefinition,
round(avg(a.DeviationRDCosts),2) as DeviationRDCosts,
round(avg(a.FunctionsAdded) + avg(a.FunctionsDeleted),2) as NotRealizedFuncs,
round(avg(a.DeviationPM2000Aufwand),2) as DeviationPM200Aufwand,
round(avg(b.Defect),2) as Defect
into #tempTable
from openrowset('SQLNCLI',
'Server=.\sqlexpress;Trusted_Connection=yes;',
'SET NOCOUNT ON;SET FMTONLY OFF;EXEC [BSC_DB].dbo.SelectScorecardGraphData
'''+#start+''',
'''+#end+''',
'''+#productGroup+''',
'''+#projectType+''',
''1'',
''0'',
''All'',
''Current'',
'''+#businessUnit+''',
'''+#developmentLocation+'''
') as a,
openrowset('SQLNCLI', 'Server=.\sqlexpress;Trusted_Connection=yes;', 'SET NOCOUNT ON;SET FMTONLY OFF;EXEC [BSC_DB].dbo.GetSPCDefectDistributionData
'''+cast(#startDate as varchar(40))+''',
'''+cast(#endDate as varchar(40))+''',
''Defect'',
'''+#projectType+''',
'''+#productGroup+''',
'''+#businessUnit+''',
'''+#developmentLocation+'''') as b
update dbo.EA_ProcessScorecard_Config_Tbl
set EPC_Deviation = case EPC_Metric
when 'PM200' then (select DeviationDefinition from #tempTable)
when 'PM300' then (select DeviationDeadline from #tempTable)
when 'Cost' then (select DeviationRDCosts from #tempTable)
when 'PM150' then (select DeviationPM200Aufwand from #tempTable)
when 'Defect' then (select Defect from #tempTable)
when 'Funcs' then (select NotRealizedFuncs from #tempTable)
END
where EPC_Description = 'PrevFY' and EPC_FYYear = '0'
drop table #tempTable
END
GO
I'm not able to create it and I get the error message:
Msg 102, Level 15, State 1, Procedure UpdatePrevFYConfigData,
Line 38 Incorrect syntax near '+'.
... but if I use hard coded values for the parameters it works!!
Please help!
Both OPENROWSET and OPENDATASOURCE should be used only for accessing external data for, let's say, quick and dirty solutions, or when it is not possible to configure a permanent linked server. These functions do not provide all of the functionality available from a linked server.
The arguments of OPENROWSET and OPENDATASOURCE do not support variables. They have to be specified as string-literal. If variables need to be passed in as arguments to these functions, a query string containing these variables can be constructed dynamically and executed using the EXEC statement.
Similar to (not syntax checked)
DECLARE #sqlCommand varchar(1000)
SET #sqlCommand = 'SELECT *
FROM OPENROWSET(''SQLNCLI'',''server=.\sqlexpress;Trusted_Connection=yes'',''SET NOCOUNT ON;SET FMTONLY OFF;EXEC [BSC_DB].dbo.SelectScorecardGraphData ''''' + cast(#param1 as varchar(10)) + ''''',''' + cast(#param2 as varchar(n)) ''')'
EXEC #sqlCommand
And so on...
Hope that helps. Kind regards,
Stefan
-- FOR USING OPENROWSETS
EXEC sp_configure 'Ad Hoc Distributed Queries'
,1
RECONFIGURE
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'INSERT INTO #TABLESIZESYEAR SELECT NULL AS [TABLE NAME], * FROM OPENROWSET
(''SQLOLEDB'',''Server=(local);TRUSTED_CONNECTION=YES;'',''set fmtonly off EXEC one.[dbo].[InvestigateDataGrowthByYearAndClient] #pDATECOLUMN =' + #YEARCOLUMN + ' ,
#pTABLENAME = ' + #TABLENAME + ' WITH RESULT SETS(
([YEAR NAME] NVARCHAR(5) NULL
, [NUMBER OF ROWS] CHAR(11)
, [RESERVED SPACE] VARCHAR(18)
, [DATA SPACE] VARCHAR(18)
, [INDEX SIZE] VARCHAR(18)
, [UNUSED SPACE] VARCHAR(18) )
)
;'') '
DECLARE #ParmDefinition NVARCHAR(500) = '#pDATECOLUMN NVARCHAR(20)
,#YEARCOLUMN NVARCHAR(20)
,#pTABLENAME NVARCHAR(60)';
EXECUTE sp_executesql #sql
,#ParmDefinition
,#YEARCOLUMN = #YEARCOLUMN
,#pDATECOLUMN = #YEARCOLUMN
,#pTABLENAME = #TABLENAME