How to run CRUD in single procedure by using json?(T-SQL) - json

Procedure
ALTER PROCEDURE [dbo].[SpProductTsk]
(#json varchar(MAX))
AS
----insert---
BEGIN
DECLARE #SelectedProcedure varchar(max) = ''
IF #SelectedProcedure = 'SpProductIns'
BEGIN
INSERT INTO [dbo].[Product](ProductName, ProductCategory, InsertPersonId, InsertDate)
SELECT
p.productName, p.productCategory,
p.insertPersonId, GETDATE()
FROM
OPENJSON(#json)
WITH
(productName varchar(50) '$.ProductName',
productCategory varchar(50) '$.ProductCategory',
insertPersonId int '$.InsertPersonId',
insertDate datetime '$.InsertDate') AS p
----SELECT-----
IF #SelectedProcedure = 'SpProductSelect'
BEGIN
SELET p.productName, p.productCategory
FROM [dbo].[Product] AS p
FOR JSON PATH, ROOT('ProductDetails')
END
-----UPDATE-----
IF #SelectedProcedure = 'SpProductUpd'
BEGIN
DECLARE #ProductId int,
#ProductName varchar(50),
#ProductCategory varchar(50),
#InsertPersonId int
SELECT
#ProductId = p.productId,
#ProductName = p.productName,
#ProductCategory = p.productCategory,
#InsertPersonId = p.insertPersonId
FROM
OPENJSON (#Json)
WITH
(productId int '$.ProductId',
productName varchar(50) '$.ProductName',
productCategory varchar(50) '$.ProductCategory',
insertPersonId int '$.InsertPersonId') AS p
UPDATE [dbo].[Product]
SET productName = #ProductName,
productCategory = #ProductCategory,
insertPersonId = #InsertPersonId
WHERE ProductId = #ProductId
END
----Delete---
IF #SelectedProcedure = 'SpProductDel'
BEGIN
DECLARE #Id int
SELECT #Id = p.productId
FROM OPENJSON(#json)
WITH (productId int '$.ProductId') AS p
DELETE FROM [dbo].[Product]
WHERE ProductId = #Id
END
END
END
EXEC [dbo].[SpProductTsk] #json = '{
"SelectedProcedur":"SpProductIn",
"ProductName":"Mutton",
"ProductCategory":"Meat",
"InsertPersonId":"1",
"InsertDate":"" }'
SELECT * FROM product
Code compiles but shows 0 rows inserted

You would need to get the "SelectedProcedur" value from the json you pass into the stored procedure.
After to declare #SelectedProcedure set it to the "SelectedProcedur" value from the json you pass in.
DECLARE #SelectedProcedure VARCHAR(MAX) = '';
SET #SelectedProcedure = (
SELECT [value]
FROM [OPENJSON](#json)
WHERE [key] = 'SelectedProcedur'
);
You'll need to fix your if statements as well. All your code is inside the "IF #SelectedProcedure = 'SpProductIns'" block so none of the other if statements would ever get executed.
Before the line
----SELECT-----
add
END
and then remove one of the END at the bottom.

Related

Get statistics from MySQL json rows [duplicate]

I have a json object which has list of products under a bill. I want to write a mysql function for it which reads the data from the json and iterates over it one by one and inserts the same data to product and bill tables.
Here is my json object
{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":paid,"product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
Here I have a mysql function which reads the data from the JSON
CREATE DEFINER=`mydb`#`%` FUNCTION `raiseOrder`(dataObject Json)
RETURNS bigint(11)
BEGIN
DECLARE billNo BIGINT(11) DEFAULT NULL;
DECLARE customerName VARCHAR(64);
DECLARE date datetime DEFAULT NOW();
DECLARE total Float(12,2);
DECLARE taxamt Float(12,2);
DECLARE fixedCharges Float(12,2);
DECLARE products json;
DECLARE productId bigint(15) DEFAULT NULL;
DECLARE categoryId bigint(11);
DECLARE cost float;
DECLARE categoryName varchar(64);
DECLARE quantity int default 0;
DECLARE supplierId bigint(11);
DECLARE supplierName varchar(128);
SET billNo = (SELECT JSON_EXTRACT(dataObject, "$.billNo"));
SET customerName = (SELECT JSON_EXTRACT(dataObject, "$.customerName"));
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
RETURN 1;
END
Now with these lines
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
I get the inner products json and the id of the 0th product. But I want a way to iterate over the array of the products.
You can use a WHILE loop in conjunction with JSON_LENGTH to achieve this:
DECLARE json, products, product VARCHAR(4000);
DECLARE i INT DEFAULT 0;
SELECT '{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":"paid","product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
' INTO json;
SELECT json->"$.product" INTO products;
WHILE i < JSON_LENGTH(products) DO
SELECT JSON_EXTRACT(products,CONCAT('$[',i,']')) INTO product;
SELECT product;
SELECT i + 1 INTO i;
END WHILE;
You'll probably need to do more than simply 'SELECT product' though ;-)
NOTE: MySQL JSON functions were added in 5.7.8 so you'll need to check your MySQL version first.
Extension to this answer, and if you want to loop through the keys of json object, you can do this via this way
declare _keys int default 0;
declare i int default 0;
declare _current_key varchar(50) default '';
select JSON_KEYS(product) into _keys;
while i < JSON_LENGTH(_keys) do
select json_extract(json_unquote(_keys), concat('$[', i, ']')) into _current_key;
set i = i + 1;
end while;

Loop through JSON object in mysql function

I have a json object which has list of products under a bill. I want to write a mysql function for it which reads the data from the json and iterates over it one by one and inserts the same data to product and bill tables.
Here is my json object
{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":paid,"product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
Here I have a mysql function which reads the data from the JSON
CREATE DEFINER=`mydb`#`%` FUNCTION `raiseOrder`(dataObject Json)
RETURNS bigint(11)
BEGIN
DECLARE billNo BIGINT(11) DEFAULT NULL;
DECLARE customerName VARCHAR(64);
DECLARE date datetime DEFAULT NOW();
DECLARE total Float(12,2);
DECLARE taxamt Float(12,2);
DECLARE fixedCharges Float(12,2);
DECLARE products json;
DECLARE productId bigint(15) DEFAULT NULL;
DECLARE categoryId bigint(11);
DECLARE cost float;
DECLARE categoryName varchar(64);
DECLARE quantity int default 0;
DECLARE supplierId bigint(11);
DECLARE supplierName varchar(128);
SET billNo = (SELECT JSON_EXTRACT(dataObject, "$.billNo"));
SET customerName = (SELECT JSON_EXTRACT(dataObject, "$.customerName"));
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
RETURN 1;
END
Now with these lines
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
I get the inner products json and the id of the 0th product. But I want a way to iterate over the array of the products.
You can use a WHILE loop in conjunction with JSON_LENGTH to achieve this:
DECLARE json, products, product VARCHAR(4000);
DECLARE i INT DEFAULT 0;
SELECT '{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":"paid","product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
' INTO json;
SELECT json->"$.product" INTO products;
WHILE i < JSON_LENGTH(products) DO
SELECT JSON_EXTRACT(products,CONCAT('$[',i,']')) INTO product;
SELECT product;
SELECT i + 1 INTO i;
END WHILE;
You'll probably need to do more than simply 'SELECT product' though ;-)
NOTE: MySQL JSON functions were added in 5.7.8 so you'll need to check your MySQL version first.
Extension to this answer, and if you want to loop through the keys of json object, you can do this via this way
declare _keys int default 0;
declare i int default 0;
declare _current_key varchar(50) default '';
select JSON_KEYS(product) into _keys;
while i < JSON_LENGTH(_keys) do
select json_extract(json_unquote(_keys), concat('$[', i, ']')) into _current_key;
set i = i + 1;
end while;

Visual Studio 2010 Reporting Services - how to populate something when nothing is returned

I'm using a query with two parameters (#campaign,#resultcode) to populate a table with 3 columns ("Campaignname","Disposition","Count"), but when either one of those parameters don't exist in the database, nothing populates in the table. Is there a way to make it populate the two parameters with a count of 0? Also I have it set so that multiple parameters can be selected. I've tried IIF(IsNothing()..., IIF(***.value = null or ""). Still doesn't do what I want it to do. Some help?
Included code from comment response:
SELECT databasename, callresultdescription, count(*) as Count
FROM bpsql00.[histCallCenterStats].[dbo].[CallResults]
WHERE databasename IN(#campaign) AND callresultcode IN(#resultcode)
GROUP BY databasename, callresultdescription
The callresultdescription is AKA disposition
You could union them together:
--create table [CallResults] (databasename varchar(10),callresultdescription
varchar(10),myvalue int)
--insert into [CallResults]
--values ('a','AA',1),
--('b','BB',2),
--('c','CC',3)
--select * from [CallResults]
declare #campaign varchar(10)='d',#resultcode varchar(10)='dd' ;
SELECT databasename, callresultdescription,
count(1) as [Count]
FROM [CallResults]
WHERE databasename IN (#campaign)
AND callresultdescription IN (#resultcode)
GROUP BY databasename, callresultdescription
UNION
SELECT databasename=#campaign,
callresultdescription=#resultcode,
0 as [Count]
from [CallResults]
where databasename not IN (#campaign)
AND callresultdescription not IN (#resultcode)
You can accomplish this with an IF statement in the SQL query:
IF EXISTS (SELECT 1 FROM bpsql00.[histCallCenterStats].[dbo].[CallResults] WHERE databasename IN ( #campaign ) AND callresultcode IN ( #resultcode ))
SELECT databasename
, callresultdescription
, [Count] = COUNT(*)
FROM bpsql00.[histCallCenterStats].[dbo].[CallResults]
WHERE databasename IN ( #campaign )
AND callresultcode IN ( #resultcode )
GROUP BY databasename ,
callresultdescription;
ELSE
SELECT databasename = #campaign
, callresultdescription = #resultcode
, [Count] = 0
Edit per question in the comment:
It gets tricky when you need to return a multi-valued parameter. If you're on SQL 2016, you can use the new TSQL STRING_SPLIT function to split out their comma-separated selections. There are also splitter functions you can find on the interwebs for prior versions of SQL. The simplest solution, though, is to let the query return nothing and set the NoRowsMessage of the tablix to inform the client. You can use an expression like
="No records found in the selected campaigns (" & _
Parameters!campaign.Value & ") and result codes (" & _
Parameters!resultcode.Value & ")."
That gives the user a record of what was searched and that nothing was found to match their criteria.
So finally figured it out. I have concluded that the program is limited what I wanted to do. So... why not let SQL do it for me and I can just call a stored procedure. BINGO. I had to create a function as well. So for anyone who needs something like this.
Stored procedure I created:
alter procedure [dbo].[rs_Query]
#campaign varchar (100),
#resultcode varchar (100)
as
Begin
declare #var_campaign varchar(100)
declare #var_resultcode varchar(100)
declare #c table(ID int identity, databasename varchar(100))
declare #r table(ID int identity, callresultcode varchar(100))
insert into #c select element from dbo.func_split(#campaign, ',')
insert into #r select element from dbo.func_split(#resultcode,',')
declare #dbcnt int --count of campaigns selected
declare #crcnt int --count of dispositions selected
declare #crrow int --row id for campaigns selected
declare #dbrow int --row id for dispositions selected
declare #tempdbname varchar(50) --temp campaign name
declare #tempcr varchar(50) --temp call result name
declare #t table (databasename varchar(100), callresultdescription varchar (100), Count int)
declare #count int
select #dbcnt = count(*) from #c
select #crcnt = count(*) from #r
select #dbrow = 1
select #crrow = 1
while #dbcnt >= #dbrow
begin
set #tempdbname = (select databasename
from bpsql00.callcenteraux.dbo.DailyReportsCampaign
where databasename = (select databasename from #c where id = #dbrow))
set #crrow = 1
while #crcnt >= #crrow
begin
set #tempcr = (select CallResultDescription
from CallResultCode
where CallResultCode = (select CallResultCode from #r where id = #crrow));
if exists(select 1 from bpsql00.[histCallCenterStats].[dbo].[CallResults]
where CallResultCode = (select CallResultCode from #r where id = #crrow) and databasename = #tempdbname)
begin
select #count = count(*) from bpsql00.[histCallCenterStats].[dbo].[CallResults]
where CallResultCode = (select CallResultCode from #r where id = #crrow) and databasename = #tempdbname
insert into #t values(#tempdbname,#tempcr,#count)
end
else
begin
insert into #t values(#tempdbname,#tempcr,0)
end
set #crrow = #crrow + 1
end
set #dbrow = #dbrow + 1
end
select * from #t
end
And function I created:
ALTER FUNCTION [dbo].[func_Split]
(
#DelimitedString varchar(8000),
#Delimiter varchar(100)
)
RETURNS #tblArray TABLE
(
ElementID int IDENTITY(1,1), -- Array index
Element varchar(1000) -- Array element contents
)
AS
BEGIN
-- Local Variable Declarations
-- ---------------------------
DECLARE #Index smallint,
#Start smallint,
#DelSize smallint
SET #DelSize = LEN(#Delimiter + 'x') - 1
-- Loop through source string and add elements to destination table array
-- ----------------------------------------------------------------------
WHILE LEN(#DelimitedString) > 0
BEGIN
SET #Index = CHARINDEX(#Delimiter, #DelimitedString)
IF #Index = 0
BEGIN
INSERT INTO
#tblArray
(Element)
VALUES
(LTRIM(RTRIM(#DelimitedString)))
BREAK
END
ELSE
BEGIN
INSERT INTO
#tblArray
(Element)
VALUES
(LTRIM(RTRIM(SUBSTRING(#DelimitedString, 1,#Index - 1))))
SET #Start = #Index + #DelSize
SET #DelimitedString = SUBSTRING(#DelimitedString, #Start , LEN(#DelimitedString) - #Start + 1)
END
END
RETURN
END

Select UNION from multiple tables via variable

I have a query that selects from multiple tables using a join. I want to execute this query from different databases via a loop.
I have accomplished that via (simplified query):
DECLARE #intCounter int
SET #intCounter = 1
DECLARE #tblBedrijven TABLE (ID int identity(1,1),
CompanyName varchar(20),
DatabaseTable varchar(100))
INSERT INTO #tblBedrijven VALUES ('001-CureCare', '<TABLE/ DATABASE1> AUS'),
('002-Cleaning', '[global_nav5_prod].[dbo].<TABLE/ DATABASE2>] AUS')
DECLARE #strCompany varchar(20)
DECLARE #strTable varchar(100)
WHILE (#intCounter <= (SELECT MAX(ID) FROM #tblBedrijven))
BEGIN
SET #strTable = (SELECT DatabaseTable FROM #tblBedrijven
WHERE ID = #intCounter)
SET #strCompany = (SELECT CompanyName FROM #tblBedrijven
WHERE ID = #intCounter)
EXEC('SELECT ''' + #strCompany + ''' as Company,
AUS.[User],
AUS.[E-mail]
FROM' + #strTable)
SET #intCounter = #intCounter + 1
END
My problem is that the result generates 2 separate tables (for every loop). I want to union the results but have no clue how.
Any suggestions?
Thanks in advance.
Can't you use something like the below code where you append all the sqls with union and finally execute the sql once only without executing in a loop. I am not an expert in SQL Server but I have written many other similar stored procedures using other RDBMS. So please bear any syntax errors.
DECLARE #intCounter int
DECLARE #maxId int
SET #intCounter = 1
DECLARE #tblBedrijven TABLE (ID int identity(1,1),
CompanyName varchar(20),
DatabaseTable varchar(100))
INSERT INTO #tblBedrijven VALUES ('001-CureCare', '<TABLE/ DATABASE1> AUS'),
('002-Cleaning', '[global_nav5_prod].[dbo].<TABLE/ DATABASE2>] AUS')
DECLARE #strCompany varchar(20)
DECLARE #strTable varchar(100)
DECLARE #strSql varchar(5000)
SET #maxId = (SELECT MAX(ID) FROM #tblBedrijven)
WHILE (#intCounter <= #maxId)
BEGIN
SET #strTable = (SELECT DatabaseTable FROM #tblBedrijven
WHERE ID = #intCounter)
SET #strCompany = (SELECT CompanyName FROM #tblBedrijven
WHERE ID = #intCounter)
SET #strSql = #strSql + ('SELECT ''' + #strCompany + ''' as Company,
AUS.[User],
AUS.[E-mail]
FROM' + #strTable)
IF #intCounter < #maxId THEN
BEGIN
SET #strSql = #strSql + ' UNION '
END
SET #intCounter = #intCounter + 1
END
EXEC(#strSql)

Handling larger strings in Sql Server 2008

We have an stored procedure that we created so that user can write comma separated search tags in their software product's admin. So he can add comma-separated tags and in case if he wants to edit them, we read from the table all the tags, recreate them as comma-separated values (CSV) in stored procedure and returns that to the calling code. What happened recently, the user complained that he could not see the new CSVs he wrote. I looked into it and found out that the stored procedure is truncating the string when it reads values from database and creates CSV string. The string is of type nvarchar, and because its exceeding the max characters of 4000 limit, the values gets truncated. Any ideas on how to work out that problem.
Find my code underneath.
BEGIN
BEGIN
Declare #Synonyms Table
(
RowID int Identity(1,1),
SynonymID int,
[Synonym] nvarchar(4000)
);
SET NOCOUNT ON;
Insert #Synonyms(SynonymID, [Synonym])
Select distinct SynonymID, [Synonym] From RF_SearchSynonyms with(nolock) Where SearchTermID = #SearchTermID And ActiveInd = 1
If((Select COUNT(RowID) From #Synonyms) <> 0)
BEGIN
Declare #CurrentRow int = (Select MIN(RowID) From #Synonyms),
#TotalRows int = (Select MAX(RowID) From #Synonyms),
#Synonyms_CSV nvarchar(4000) = '';
WHILE #CurrentRow <= #TotalRows
BEGIN
Declare #TempSyn nvarchar(500);
Select #TempSyn = [Synonym] + ',' From #Synonyms Where RowID = #CurrentRow;
Set #Synonyms_CSV = #Synonyms_CSV + LTRIM(RTRIM(LOWER(#TempSyn)));
SET #CurrentRow = #CurrentRow + 1
END
END
Else
BEGIN
Set #Synonyms_CSV = '';
END
END
BEGIN
Declare #SKUs Table
(
RowID int Identity(1,1),
SkuID int,
SKU nvarchar(15)
);
SET NOCOUNT ON;
Insert #SKUs(SkuID, SKU)
Select distinct SkuID, SKU From RF_SearchSkus with(nolock) Where SearchTermID = #SearchTermID And ActiveInd = 1
If((Select COUNT(RowID) From #SKUs) <> 0)
BEGIN
Declare #CurrentRow1 int = (Select MIN(RowID) From #SKUs),
#TotalRows1 int = (Select MAX(RowID) From #SKUs),
#Skus_CSV nvarchar(4000) = '';
WHILE #CurrentRow1 <= #TotalRows1
BEGIN
Declare #TempSku nvarchar(15);
Select #TempSku = SKU + ',' From #SKUs Where RowID = #CurrentRow1;
Set #Skus_CSV = #Skus_CSV + LTRIM(RTRIM(#TempSku));
SET #CurrentRow1 = #CurrentRow1 + 1
END
END
Else
BEGIN
Set #Skus_CSV = '';
END
END
BEGIN
Declare #Combined varchar(8000),
#syn_len int = 0,
#sku_len int = 0;
Select #syn_len = LEN(#Synonyms_CSV);
Select #sku_len = LEN(#Skus_CSV);
Select #Combined = #Synonyms_CSV + '-_-' + #Skus_CSV;
Select #Synonyms_CSV + '-_-' + #Skus_CSV;
END
END
I can't use text and ntext as they do not play nice with concatenation operations.
Thanks.
How are your declaring the string parameter?
nvarchar(max)
supports up to 2^32-1 (2GB)
See this link.