I am struggling to substring and get the values in SQL.
I am having a JSON String like the following:
DECLARE #string varchar(max)= '[{"CustomFieldId":18,"FieldName":"ABCD","FieldType":"freeText","FieldValue":null,"Details":null,"Value":null,"RelationTable":null,"Isisible":true,"IsAdmin":false,"CreatedDate":null,"ModifiedDate":null,"LoggedInUser":"TESTUSER"},{"CustomFieldId":19,"FieldName":"Workdomain","FieldType":"freeText","FieldValue":null,"Details":null,"Value":null,"RelationTable":null,"IsVisible":true,"IsAdmin":false,"CreatedDate":null,"ModifiedDate":null,"LoggedInUser":"149645"},{"CustomFieldId":20,"FieldName":"TEST1234","FieldType":"freeText","FieldValue":"Sometest","Details":null,"Value":null,"RelationTable":null,"IsVisible":false,"IsAdmin":false,"CreatedDate":null,"ModifiedDate":null,"_listlovFields":[],"org4Values":[],"LoggedInUser":"TESTUSER"}]'
or it can also be like this:
DECLARE #string varchar(max) = '[{"CustomFieldId":20,"FieldName":"TEST1234","FieldType":"freeText","FieldValue":"Sometest","Details":null,"Value":null,"RelationTable":null,"IsVisible":false,"IsAdmin":false,"CreatedDate":null,"ModifiedDate":null,"LoggedInUser":"TESTUSER"}]'
Now from any one of them I need to get the 'FieldValue' of a particular 'CustomFieldId' with a particular 'FieldName' and where the FieldValue starts with a particular string.
Like, I am going to get these:
declare #propName varchar(max) = 'Test1234',
#customFieldId varchar(max) = 20,
#value varchar(max) = 'Some'
So, in this particular case, I need to get the FieldValue of customfield with CustomFieldId:"20", FieldName":"TEST1234" and where FieldValue starts with 'Some'.
The output simply needs be the string 'Sometest' as this is the FieldValue of CustomFieldId:"20"
Any help in this would be highly appreciated.
this is quite easy to solve when you install regex functions on your sql server. I've included the link where you can find them.
https://www.simple-talk.com/sql/t-sql-programming/clr-assembly-regex-functions-for-sql-server-by-example/
declare #CustomFieldId nvarchar(50)= '20'
declare #FieldName nvarchar(50) = 'TEST1234'
declare #FieldValueStartsWith nvarchar(50) = 'Some'
declare #input nvarchar(500)
select #input = '[{"CustomFieldId":20,"FieldName":"TEST1234","FieldType":"freeText","FieldValue":"Sometest","Details":null,"Value":null,"RelationTable":null,"IsVisible":false,"IsAdmin":false,"CreatedDate":null,"ModifiedDate":null,"LoggedInUser":"TESTUSER"}]'
declare #result nvarchar(500)
declare #expression nvarchar(200) = '.*"CustomFieldId":' + #CustomFieldId + ',"FieldName":"' + #FieldName + '".*"FieldValue":("' + #FieldValueStartsWith + '\w+").*'
select #result = dbo.RegExReplaceX(#expression,#input,'$1',dbo.RegExOptionEnumeration(0,0,0,0,1,0,0,0,0)) -- OPTION = FOR CASE SENSITIVE
if #result = #input SELECT NULL ELSE SELECT #RESULT
This is what I tried and got an error
Msg 137, Level 15, State 1, Line 1
Must declare the scalar variable "#MAXCount"
Code:
DECLARE #TempTable NVARCHAR(MAX)
DECLARE #MAXCount VARCHAR(10)
DECLARE #MINCount VARCHAR(10)
DECLARE #SQLSelect NVARCHAR(MAX)
SET #TempTable = 'Test_'+CONVERT(VARCHAR(10),##SPID)
SET #SQLSelect = 'SELECT #MAXCount = MAX(RowID), #MINCount = MIN(RowID) FROM Work_Tables.dbo.'+#TempTable+' (NOLOCK)'
EXEC SP_EXECUTESQL #SQLSelect
You have to pass variables as OUTPUT parameters:
DECLARE #TempTable NVARCHAR(MAX) = 'Test_'+ '1'; -- CONVERT(VARCHAR(10),##SPID)
DECLARE #MAXCount VARCHAR(10);
DECLARE #MINCount VARCHAR(10);
DECLARE #SQLSelect NVARCHAR(MAX);
SET #SQLSelect = 'SELECT #MAXCount = MAX(RowID), #MINCount = MIN(RowID) FROM dbo.'
+#TempTable+' (NOLOCK)';
EXEC dbo.SP_EXECUTESQL #SQLSelect
,N'#MAXCount VARCHAR(10) OUTPUT, #MinCount VARCHAR(10) OUTPUT'
,#MAXCount OUTPUT
,#MINCount OUTPUT;
SELECT #MAXCount, #MINCount;
LiveDemo
Notes:
It looks like poor design to create table per SPID. Related: SELECT * FROM sales + #yymm
Table name should has SYSNAME datatype, you could add QUOTENAME for additional protection against SQL Injection
Concatenating SQL query could be error-prone, you could use REPLACE
NOLOCK could lead to uncommited reads.
Something like:
DECLARE #MAXCount VARCHAR(10)
,#MINCount VARCHAR(10);
DECLARE #SQLSelect NVARCHAR(MAX) =
N'SELECT #MAXCount = MAX(RowID), #MINCount = MIN(RowID)
FROM <table_name> WITH (NOLOCK)';
DECLARE #TempTable SYSNAME = QUOTENAME('Test_'+ '1'); -- CONVERT(VARCHAR(10),##SPID)
SET #SQLSelect = REPLACE(#SQLSelect, '<table_name>', #TempTable);
EXEC dbo.SP_EXECUTESQL #SQLSelect
,N'#MAXCount VARCHAR(10) OUTPUT, #MinCount VARCHAR(10) OUTPUT'
,#MAXCount OUTPUT
,#MINCount OUTPUT;
SELECT #MAXCount, #MINCount;
I have one complex query in SQL which is taking long time, i.e. more than 1 min, to produce the results due to Row_Number() in SQL. I am unable to find a better option in place of that. Below is my SQL query.
Declare #AgreementNumber nvarchar(500)
Declare #SerialNo nvarchar(100)
Declare #EmailId nvarchar(1000)
Declare #CountryId nvarchar(10)
Declare #SaleType tinyint
Declare #CompanyName nvarchar(255)
Declare #PONo numeric(18,0)
Declare #Status tinyint
Declare #POCDeliveryType nvarchar(10)
Declare #FromDate datetime
Declare #ToDate datetime
Declare #CurrentPage numeric
Declare #PageSize numeric
Declare #FileId numeric(18,0)
Declare #PurchaseOrg nvarchar(4)
set #AgreementNumber =''
set #SerialNo =''
set #EmailId =''
set #CountryId ='0014'
set #SaleType=0
set #CompanyName =''
set #PONo= 0
set #Status =0
set #POCDeliveryType =''
set #FromDate =''
set #ToDate =''
set #CurrentPage =1
set #PageSize =100000
set #FileId =0
set #PurchaseOrg =''
----For Paging---------------------------------------------------------------------
Declare #TotalRecord numeric
Declare #StartRow numeric
Declare #EndRow numeric
Set #StartRow=(#PageSize * (#CurrentPage-1)) + 1
Set #EndRow=(#PageSize * (#CurrentPage))
-----------------------------------------------------------------------------------
Select #TotalRecord=Count(*)
From OrderHeader OH inner join OrderLine OL on OH.OrderID=OL.OrderId
Where (OH.CountryId=#CountryId or ISNULL(#CountryId,'')='') and
(OH.PurchaseOrg=#PurchaseOrg or ISNULL(#PurchaseOrg,'')='') and
(SaleType=#SaleType or ISNULL(#SaleType,0)=0) and
(CompanyName like '%'+ isnull(#CompanyName,'') + '%'or isnull(#CompanyName,'')='')and
(PurchaseOrderNo = #PONo or isnull(#PONo,0)=0)and
(OL.Status=#Status or ISNULL(#Status,0)=0) and
(POCDeliveryPreference=#POCDeliveryType or ISNULL(#POCDeliveryType,'')='') and
((CONVERT(VARCHAR(12),OH.Created,112)>=CONVERT(VARCHAR(12),#FromDate,112))or (Isnull(#FromDate,'')=''))and
(CONVERT(VARCHAR(12),OH.Created,112)<=CONVERT(VARCHAR(12),#ToDate,112)or (Isnull(#ToDate,'')='')) and
(OL.SerialNumber like '%'+#SerialNo+'%' or ISNULL(#SerialNo,'') ='') and
(OL.AgreementNumber like '%'+#AgreementNumber+'%' or ISNULL(#AgreementNumber,'') ='') and
(OH.EmailAddress like '%'+#EmailId+'%' or ISNULL(#EmailId,'') ='') and
(OH.FileId=#FileId or isnull(#FileId,0)=0)
Select *, #TotalRecord as TotalRecord From
(
**Select ROW_NUMBER() OVER
(
Order By OH.Created Desc
)as Row**,OH.OrderID,ISNULL(CustomerId,'') as CustomerId,ISNULL(OH.CountryId,'') as CountryId,SaleType,HwPurchaseDate,ISNULL(AddressLine1,'') as
AddressLine1,ISNULL(AddressLine2,'') as AddressLine2,ISNULL(City,'') as City,ISNULL([State],'') as [State],ISNULL(Zip,'') as Zip,
ISNULL(County,'') as County,ISNULL(CompanyName,'') as CompanyName,ISNULL(EmailAddress,'') as EmailId,ISNULL(FirstName,'') as FirstName,
ISNULL(LastName,'') as LastName,ISNULL(PrimaryPhone,'') as Phone,ISNULL(PurchaseOrderNo,0) as POno,ISNULL(OL.[Status],0) as [Status],POCDeliveryPreference,
POCLanguage,CustPOReference,ISNULL(CurrencyCode,'') as CurrencyCode,TransactionId,ISNULL(OH.DeliveryStatus,0) as DeliveryStatus,
isnull(IPAddress,'') as IPAddress, ISNULL(InTouchSessionId,'') as InTouchSessionId, ISNULL(InTouchUserId,'') as InTouchUserId,
ISNULL(SourceSystem,0) as SourceSystem,SalesOrderDate,OH.Created,isnull(OL.SerialNumber,'') as SerialNumber,ISNULL(OL.AgreementNumber,'') as AgreementNumber,
ISNULL(OL.PurchaseOrderNoLineLevel,'') as PurchaseOrderNoLineLevel,ISNULL(OL.ProductName,'') as ProductName,ISNULL(OL.OrderQty,0) as OrderQty,
ISNULL(OL.ManufPartNo,'') as ManufPartNo,isnull(OL.VendorStatus,'') as VendorStatus, isnull(OL.StatusRemark, '') as StatusRemark
From OrderHeader OH inner join OrderLine OL on OH.OrderID=OL.OrderId
Where (OH.CountryId=#CountryId or ISNULL(#CountryId,'')='') and
(OH.PurchaseOrg=#PurchaseOrg or ISNULL(#PurchaseOrg,'')='') and
(SaleType=#SaleType or ISNULL(#SaleType,0)=0) and
(CompanyName like '%'+ isnull(#CompanyName,'') + '%'or isnull(#CompanyName,'')='')and
(PurchaseOrderNo = #PONo or isnull(#PONo,0)=0)and
(OL.Status=#Status or ISNULL(#Status,0)=0) and
(POCDeliveryPreference=#POCDeliveryType or ISNULL(#POCDeliveryType,'')='') and
((CONVERT(VARCHAR(12),OH.Created,112)>=CONVERT(VARCHAR(12),#FromDate,112))or (Isnull(#FromDate,'')=''))and
(CONVERT(VARCHAR(12),OH.Created,112)<=CONVERT(VARCHAR(12),#ToDate,112)or (Isnull(#ToDate,'')='')) and
(OL.SerialNumber like '%'+#SerialNo+'%' or ISNULL(#SerialNo,'') ='') and
(OL.AgreementNumber like '%'+#AgreementNumber+'%' or ISNULL(#AgreementNumber,'') ='') and
(OH.EmailAddress like '%'+#EmailId+'%' or ISNULL(#EmailId,'') ='') and
(OH.FileId=#FileId or isnull(#FileId,0)=0)
)
as RowResults
Where Row between #StartRow AND #EndRow
I have highlighted that part which is taking so long time.
OH.CountryId = #CountryId or ISNULL(#CountryId, '') = '')
Generally these sorts of things should be avoided. It prevents SQL Server from performing an index seek and instead performs an index scan. Can you use dynamic SQL instead and include in the where OH.CountryId = #CountryId only when its specified?
Replace
((CONVERT(VARCHAR(12),OH.Created,112)>=CONVERT(VARCHAR(12),#FromDate,112))
(CONVERT(VARCHAR(12),OH.Created,112)<=CONVERT(VARCHAR(12),#ToDate,112)
by Cast(OH.Created as date)>=Cast(#FromDate as date)
Cast(OH.Created as date)<=Cast(#FromDate as date)
the convert creating a plan that is not the best.
There are lots of issue in query itself
(1) Using same query twice
(2) trying to catch all query(inefficiently ) that can produce horrible plan
(3) Using predicate like OH.EmailAddress like '%'+#EmailId+'%'
(4) inefficient paging
Declare #AgreementNumber nvarchar(500)
Declare #SerialNo nvarchar(100)
Declare #EmailId nvarchar(1000)
Declare #CountryId nvarchar(10)
Declare #SaleType tinyint
Declare #CompanyName nvarchar(255)
Declare #PONo numeric(18,0)
Declare #Status tinyint
Declare #POCDeliveryType nvarchar(10)
Declare #FromDate datetime
Declare #ToDate datetime
Declare #CurrentPage numeric
Declare #PageSize numeric
Declare #FileId numeric(18,0)
Declare #PurchaseOrg nvarchar(4)
set #AgreementNumber =''
set #SerialNo =''
set #EmailId =''
set #CountryId ='0014'
set #SaleType=0
set #CompanyName =''
set #PONo= 0
set #Status =0
set #POCDeliveryType =''
set #FromDate =''
set #ToDate =''
set #CurrentPage =1
set #PageSize =100000
set #FileId =0
set #PurchaseOrg =''
----For Paging---------------------------------------------------------------------
Declare #TotalRecord numeric
Declare #StartRow numeric
Declare #EndRow numeric
Set #StartRow=(#PageSize * (#CurrentPage-1)) + 1
Set #EndRow=(#PageSize * (#CurrentPage))
-----------------------------------------------------------------------------------
--Select #TotalRecord=Count(*)
--From OrderHeader OH inner join OrderLine OL on OH.OrderID=OL.OrderId
--Where (OH.CountryId=#CountryId or ISNULL(#CountryId,'')='') and
--(OH.PurchaseOrg=#PurchaseOrg or ISNULL(#PurchaseOrg,'')='') and
-- (SaleType=#SaleType or ISNULL(#SaleType,0)=0) and
-- (CompanyName like '%'+ isnull(#CompanyName,'') + '%'or isnull(#CompanyName,'')='')and
-- (PurchaseOrderNo = #PONo or isnull(#PONo,0)=0)and
-- (OL.Status=#Status or ISNULL(#Status,0)=0) and
-- (POCDeliveryPreference=#POCDeliveryType or ISNULL(#POCDeliveryType,'')='') and
-- ((CONVERT(VARCHAR(12),OH.Created,112)>=CONVERT(VARCHAR(12),#FromDate,112))or (Isnull(#FromDate,'')=''))and
-- (CONVERT(VARCHAR(12),OH.Created,112)<=CONVERT(VARCHAR(12),#ToDate,112)or (Isnull(#ToDate,'')='')) and
-- (OL.SerialNumber like '%'+#SerialNo+'%' or ISNULL(#SerialNo,'') ='') and
-- (OL.AgreementNumber like '%'+#AgreementNumber+'%' or ISNULL(#AgreementNumber,'') ='') and
-- (OH.EmailAddress like '%'+#EmailId+'%' or ISNULL(#EmailId,'') ='') and
-- (OH.FileId=#FileId or isnull(#FileId,0)=0)
With RowResults as
(
Select ROW_NUMBER() OVER
(
Order By OH.Created Desc
)as Row ,OH.OrderID,ISNULL(CustomerId,'') as CustomerId,ISNULL(OH.CountryId,'') as CountryId,SaleType,HwPurchaseDate,ISNULL(AddressLine1,'') as
AddressLine1,ISNULL(AddressLine2,'') as AddressLine2,ISNULL(City,'') as City,ISNULL([State],'') as [State],ISNULL(Zip,'') as Zip,
ISNULL(County,'') as County,ISNULL(CompanyName,'') as CompanyName,ISNULL(EmailAddress,'') as EmailId,ISNULL(FirstName,'') as FirstName,
ISNULL(LastName,'') as LastName,ISNULL(PrimaryPhone,'') as Phone,ISNULL(PurchaseOrderNo,0) as POno,ISNULL(OL.[Status],0) as [Status],POCDeliveryPreference,
POCLanguage,CustPOReference,ISNULL(CurrencyCode,'') as CurrencyCode,TransactionId,ISNULL(OH.DeliveryStatus,0) as DeliveryStatus,
isnull(IPAddress,'') as IPAddress, ISNULL(InTouchSessionId,'') as InTouchSessionId, ISNULL(InTouchUserId,'') as InTouchUserId,
ISNULL(SourceSystem,0) as SourceSystem,SalesOrderDate,OH.Created,isnull(OL.SerialNumber,'') as SerialNumber,ISNULL(OL.AgreementNumber,'') as AgreementNumber,
ISNULL(OL.PurchaseOrderNoLineLevel,'') as PurchaseOrderNoLineLevel,ISNULL(OL.ProductName,'') as ProductName,ISNULL(OL.OrderQty,0) as OrderQty,
ISNULL(OL.ManufPartNo,'') as ManufPartNo,isnull(OL.VendorStatus,'') as VendorStatus, isnull(OL.StatusRemark, '') as StatusRemark
From OrderHeader OH inner join OrderLine OL on OH.OrderID=OL.OrderId
Where (OH.CountryId=#CountryId or ISNULL(#CountryId,'')='') and
(OH.PurchaseOrg=#PurchaseOrg or ISNULL(#PurchaseOrg,'')='') and
(SaleType=#SaleType or ISNULL(#SaleType,0)=0) and
(CompanyName like '%'+ isnull(#CompanyName,'') + '%'or isnull(#CompanyName,'')='')and
(PurchaseOrderNo = #PONo or isnull(#PONo,0)=0)and
(OL.Status=#Status or ISNULL(#Status,0)=0) and
(POCDeliveryPreference=#POCDeliveryType or ISNULL(#POCDeliveryType,'')='') and
((CONVERT(VARCHAR(12),OH.Created,112)>=CONVERT(VARCHAR(12),#FromDate,112))or (Isnull(#FromDate,'')=''))and
(CONVERT(VARCHAR(12),OH.Created,112)<=CONVERT(VARCHAR(12),#ToDate,112)or (Isnull(#ToDate,'')='')) and
(OL.SerialNumber like '%'+#SerialNo+'%' or ISNULL(#SerialNo,'') ='') and
(OL.AgreementNumber like '%'+#AgreementNumber+'%' or ISNULL(#AgreementNumber,'') ='') and
(OH.EmailAddress like '%'+#EmailId+'%' or ISNULL(#EmailId,'') ='') and
(OH.FileId=#FileId or isnull(#FileId,0)=0)
)
Select max (Row) , * FRom RowResults
Where Row between #StartRow AND #EndRow
option (recompile)
-- quick fix only
-- --if using SQL SERVER 2012
-- OFFSET #StartRow ROWS
--FETCH NEXT #EndRow -#StartRow ROWS ONLY
--if ans still not gaining performance we wold like to see actual exection plan
--(1) Using same query twice DONE
--(2) trying to catch all query(inefficiently ) that can produce horrible plan DONE by option recompile (still you need to understand this use dynamic query if you are not exposed to sql injection)
--(3) Using predicate like OH.EmailAddress like '%'+#EmailId+'%' -- you need to adress this
--(4) inefficient paging -- fetch next is quite fast that row_num .
just have a general question today. I am trying to store the result in a variable however it's not working. I am not trying to do anything fancy rather a simple task. See below:
declare #prizeid bigint;
declare #today datetime;
declare #dayOfMonth int;
declare #year int;
declare #month int;
select #today = getdate();
select #dayOfMonth = Day(#today);
select #year = Year(#today);
select #month = Month(#today);
if #month = 1
begin
select #month = 12
select #year = #year - 1
end
else select #month = #month - 1;
declare #sqlQuery varchar(250);
declare #quantityForSnapShot bigint;
declare #filename varchar(25);
set #prizeid=31
set #filename = 'Prizes_' + REPLACE(STR(#month, 2, 0), ' ', '0') + '_' + ltrim(str(#year));
select #sqlQuery = 'select Quantity from ' + #filename +
' where PrizeID=' + convert(varchar,#prizeid)
EXEC #quantityForSnapShot=#sqlQuery
print #quantityForSnapShot
All I really want is to retreive the Quantity and store it in the var #quantityForSnapShot.
:-)
declare #prizeid bigint;
declare #today datetime;
declare #dayOfMonth int;
declare #year int;
declare #month int;
select #today = getdate();
select #dayOfMonth = Day(#today);
select #year = Year(#today);
select #month = Month(#today);
if (#month = 1)
begin
select #month = 12
select #year = #year - 1
end
else
begin
select #month = #month - 1;
end
declare #sqlQuery nvarchar(MAX); --<-- to be on safe side
declare #quantityForSnapShot bigint;
declare #filename varchar(25);
set #prizeid=31
set #filename = 'Prizes_' + REPLACE(STR(#month, 2, 0), ' ', '0') + '_' + ltrim(str(#year));
select #sqlQuery = N' select #quantityForSnapShot = Quantity ' +
N' from ' + QUOTENAME(#filename) +
N' where PrizeID = #prizeid'
EXECUTE sp_executesql #sqlQuery
,N'#prizeid bigint, #quantityForSnapShot bigint OUTPUT'
,#prizeid , #quantityForSnapShot OUTPUT
SELECT #quantityForSnapShot
You are trying to call this Dynamic sql as it were a stored procedure with a return value. You will need to use an OUTPUT parameter to retrieve the value of #quantityForSnapShot variable from your dynamic sql.
Also I have used QUOTENAME Function to put square brackets [] around the table name, to tell sql server explicitly that it is an object name. A good practice to get in as it can protect you from Sql injection attack.
Also use system stored procedure sp_executesql to execute dynamic sql.
Try This..
Begin Tran
declare #prizeid bigint;
declare #today datetime;
select #today = getdate();
declare #dayOfMonth int;
select #dayOfMonth = Day(#today);
declare #year int;
select #year = Year(#today);
declare #month int;
select #month = Month(#today);
if #month = 1
begin
select #month = 12
select #year = #year - 1
end
else select #month = #month - 1;
declare #sqlQuery varchar(250);
declare #quantityForSnapShot bigint;
declare #filename varchar(25);
set #prizeid=31
set #filename = 'Prizes_' + REPLACE(STR(#month, 2, 0), ' ', '0') + '_' + ltrim(str(#year));
select #sqlQuery = 'select Quantity from ' + #filename +
' where PrizeID=' + convert(varchar,#prizeid)
Set #quantityForSnapShot = #sqlQuery
Create Table #tmp ( Quantity bigint)
INSERT INTO #tmp (Quantity)
EXEC (#sqlQuery)
Set #quantityForSnapShot = (Select Quantity From #tmp)
Select #quantityForSnapShot
print #quantityForSnapShot
Rollback Tran