Loop the select statement in sql server stored procedure - sql

I created a store procedure shown below
CREATE PROCEDURE [dbo].[sp_rptlabelPrint] --'HKOHBLAE11/0007' ,'','HKO'
(
#Code varchar(25),
#Format int=0 ,
#Branch varchar(25)=''
)
AS
SELECT
HB.HB_cCode as HBCode,
HB.MB_cCode as MBCode,
PO.PO_cShortName as Dest,
PS.PO_cShortName as Source
FROM
SHI_HOUSEBLHDR HB
left join SHI_PORTS PO on HB.PO_cDischargePortCode = PO.PO_cCode
left join SHI_PORTS PS on HB.PO_cLoadPortCode = PS.PO_cCode
where HB.HB_cCode=#Code and HB.br_ccode=#Branch
Here it reurns a single row.
But i need to pass a integer value to parameter #Format and if it set to 2 the select statement must execute 2 times and returns the two rows. If its set 4 it returns 4 times of the same row. is it possible to loop the select statement and return the rows

You can use a temp table to store and return the result
ALTER PROCEDURE [dbo].[sp_rptlabelPrint]
(
#Code varchar(25),
#Format int=0 ,
#Branch varchar(25)=''
)
AS
CREATE TABLE #MyTempTable(HBCode VARCHAR(25),MBCode VARCHAR(25),Dest VARCHAR(25),Source VARCHAR(25))
WHILE (#Format < 4)
BEGIN
insert INTO #MyTempTable
SELECT
HB.HB_cCode as HBCode,
HB.MB_cCode as MBCode,
PO.PO_cShortName as Dest,
PS.PO_cShortName as Source
FROM
SHI_HOUSEBLHDR HB
left join SHI_PORTS PO on HB.PO_cDischargePortCode = PO.PO_cCode
left join SHI_PORTS PS on HB.PO_cLoadPortCode = PS.PO_cCode
where HB.HB_cCode=#Code and HB.br_ccode=#Branch
Set #Format = #Format + 1
END
SELECT * FROM #MyTempTable

Write as:
CREATE PROCEDURE [dbo].[sp_rptlabelPrint] --'HKOHBLAE11/0007' ,'','HKO'
(
#Code varchar(25),
#Format int=0 ,
#Branch varchar(25)=''
)
AS
SELECT
HB_cCode as HBCode,
MB_cCode as MBCode,
PO_cShortName as Dest,
PO_cShortName as Source
FROM
(
SELECT
HB.HB_cCode as HBCode,
HB.MB_cCode as MBCode,
PO.PO_cShortName as Dest,
PS.PO_cShortName as Source
FROM
SHI_HOUSEBLHDR HB
left join SHI_PORTS PO on HB.PO_cDischargePortCode = PO.PO_cCode
left join SHI_PORTS PS on HB.PO_cLoadPortCode = PS.PO_cCode
where HB.HB_cCode=#Code and HB.br_ccode=#Branch
)T
Cross JOIN
(
SELECT TOP ( #Format ) ROW_NUMBER()
OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS x(n) ;

Related

Insert if not exists doesn't work. I have 20000 records in JSON file. I want to do insert/update into table from json table accordingly using SP

I want to update/insert records from Json table ( which has 5000 records) to another table .
when I run for first time Insert works fine and when I update ,it updates accordingly.
But when I ran again the same file with additional records it doesn't insert the records.
can someone help me with this ?
Below is my code
ALTER PROCEDURE [dbo].[load_consultation_data]
#consultation_json NVARCHAR(MAX)
-- Add the parameters for the stored procedure here
AS
BEGIN
SET NOCOUNT ON;
DECLARE #JSON VARCHAR(MAX)
SET #JSON = #consultation_json
DECLARE #jsontable table
(
customerID NVARCHAR(50),
clinicID NVARCHAR(50),
birdId NVARCHAR(80),
consultationId NVARCHAR(80),
employeeName NVARCHAR(150),
totalPrice MONEY,
row_num int
)
/* Importing nested Json data */
INSERT INTO #jsontable
SELECT customer.customerID AS customerID
,customer.clinicID AS clinicID
,consultation.birdId AS birdId
,consultation.consultationId AS consultationId
,consultation.employeeName AS employeeName
,consultation.totalPrice AS totalPrice
,ROW_NUMBER() OVER (ORDER BY consultationId ) row_num
FROM OPENJSON (#JSON, '$')
WITH (customerID VARCHAR(50) '$.customerID',
clinicID VARCHAR(50) '$.clinic.clinicID') as customer
CROSS APPLY openjson(#json,'$.clinic.consultation')
WITH(
birdId NVARCHAR(80),
consultationId NVARCHAR(80),
employeeName NVARCHAR(150),
totalPrice MONEY
) as consultation
INNER JOIN dbo.clinic AS clinic_tab ON clinic_tab.external_id = customer.clinicID
INNER JOIN dbo.bird AS bird_tab ON bird_tab.external_bird_id = consultation.birdId
/** If consultation record doesn't exists then do insert else update **/
IF NOT EXISTS
(
SELECT 1
FROM dbo.consultation AS con
INNER JOIN dbo.bird AS al ON con.external_bird_id = al.external_bird_id AND al.clinic_id = con.clinic_id
INNER JOIN dbo.clinic AS pr ON con.clinic_id = pr.id
INNER JOIN #jsontable AS rjson ON rjson.consultationId = con.external_consultation_id
WHERE con.external_consultation_id = rjson.consultationId
AND pr.external_id = rjson.clinicID
AND al.external_bird_id = rjson.birdId )
BEGIN
/** Insert recored into consultation table **/
INSERT INTO dbo.[consultation]
(
[external_consultation_id]
,[external_bird_id]
,[clinic_id]
,[bird_id]
,[employee_name]
,[total_price]
)
SELECT rjson.consultationId AS [external_consultation_id]
,rjson.[birdId] AS [external_bird_id]
,bird_tab.clinic_id AS [clinic_id]
,bird_tab.[id] AS [bird_id]
,rjson.employeeName AS [employee_name]
,rjson.totalPrice AS [total_price]
FROM #jsontable as rjson
INNER JOIN dbo.bird AS bird_tab on bird_tab.external_bird_id = rjson.birdId
INNER JOIN dbo.clinic AS clinic_tab on clinic_tab.external_id = rjson.clinicID
WHERE rjson.consultationId = rjson.consultationId --#consultationID
and bird_tab.clinic_id = clinic_tab.id
END
ELSE
BEGIN
/* Update Records into consultation table */
UPDATE dbo.[consultation] SET
[external_bird_id] = rjson.[birdId]
,[clinic_id] = al.clinic_id
,[bird_id] = al.[id]
,[employee_name] = rjson.employeeName
,[total_price] = rjson.totalPrice
FROM dbo.consultation AS con
INNER JOIN dbo.bird AS al ON con.external_bird_id = al.external_bird_id AND al.clinic_id = con.clinic_id
INNER JOIN dbo.clinic AS pr ON con.clinic_id = pr.id
INNER JOIN #jsontable AS rjson ON rjson.consultationId = con.external_consultation_id
WHERE con.external_consultation_id = rjson.consultationId
AND pr.external_id = rjson.clinicID
AND al.external_bird_id = rjson.birdId
END
END

Avoid function in where clause,due to that its causing performance issue?

Whenever I'm executing the procedure I got performance issue, where do I need to change the procedure to increase the performance?
I have called table function in where clause I need to optimize this procedure without using string.
CREATE PROC proc_productwise_report #cmp_id VARCHAR(max), #unitcode VARCHAR(max), #gr_code VARCHAR(max), #store_code VARCHAR(max), #from_dt VARCHAR(20), #to_dt VARCHAR(20)
AS
BEGIN
SELECT sh.cmp_id, d.unitcode, d.store_code, st.item_code AS product, d.item_code, im.item_desc, SUM(charge_qty) AS challan_qty
FROM ps_invenstatic sh
INNER JOIN ps_invenstaticdet st ON sh.cmp_id = st.cmp_id
AND sh.sys_no_id = st.sys_no_id
AND sh.doc_id = st.doc_id
AND sys_doc_type = 'PSCH'
INNER JOIN ps_invenissu h ON sh.cmp_id = h.cmp_id
AND sh.doc_type = h.ref_doc_type
AND sh.doc_no = h.ref_doc_no
AND h.prod_code = st.item_code
INNER JOIN ps_invenissudet d ON h.cmp_id = d.cmp_id
AND h.sys_no_id = d.sys_no_id
AND h.doc_id = d.doc_id
INNER JOIN ps_itemmas im ON sh.cmp_id = im.cmp_id
AND im.item_code = d.item_code
WHERE sh.cmp_id IN (
SELECT *
FROM utilfn_split(#cmp_id, ',')
)
AND d.unitcode IN (
SELECT *
FROM utilfn_split(#unitcode, ',')
)
AND im.gr_code IN (
SELECT *
FROM utilfn_split(#gr_code, ',')
)
AND d.store_code IN (
SELECT *
FROM utilfn_split(#store_code, ',')
)
AND h.doc_dt BETWEEN convert(DATETIME, #from_dt, 103)
AND convert(DATETIME, #to_dt, 103)
AND sh.Stat_Code <> 'CA'
GROUP BY sh.cmp_id, d.unitcode, d.store_code, st.item_code, d.item_code, im.item_desc
END
I need to avoid function in where clause and resolve the performance issue.
You can build temporary tables in your stored procedure with the result of the SPLIT and INNER JOIN those temporary tables in your main query.
CREATE PROC proc_productwise_report #cmp_id VARCHAR(max), #unitcode VARCHAR(max),
#gr_code VARCHAR(max), #store_code VARCHAR(max), #from_dt VARCHAR(20), #to_dt VARCHAR(20)
AS
BEGIN
SELECT *
INTO #cmp_ids
FROM utilfn_split(#cmp_id, ',');
SELECT *
INTO #unitcodes
FROM utilfn_split(#unitcode, ',');
SELECT *
INTO #gr_codes
FROM utilfn_split(#gr_code, ',');
SELECT *
INTO #store_codes
FROM utilfn_split(#store_code, ',');
SELECT
sh.cmp_id
, d.unitcode
, d.store_code
, st.item_code AS product
, d.item_code
, im.item_desc
, SUM(charge_qty) AS challan_qty
FROM ps_invenstatic sh
INNER JOIN ps_invenstaticdet st
ON sh.cmp_id = st.cmp_id
AND sh.sys_no_id = st.sys_no_id
AND sh.doc_id = st.doc_id
AND sys_doc_type = 'PSCH'
INNER JOIN ps_invenissu h
ON sh.cmp_id = h.cmp_id
AND sh.doc_type = h.ref_doc_type
AND sh.doc_no = h.ref_doc_no
AND h.prod_code = st.item_code
INNER JOIN ps_invenissudet d
ON h.cmp_id = d.cmp_id
AND h.sys_no_id = d.sys_no_id
AND h.doc_id = d.doc_id
INNER JOIN ps_itemmas im
ON sh.cmp_id = im.cmp_id
AND im.item_code = d.item_code
INNER JOIN #cmp_ids tci on sh.cmp_id = tci.[value]
INNER JOIN #unitcodes tuc on d.unitcode = tuc.[value]
INNER JOIN #gr_codes tgr on im.gr_code = tgr.[value]
INNER JOIN #store_codes tsc on d.store_code = tsc.[value]
WHERE h.doc_dt BETWEEN convert(DATETIME, #from_dt, 103)
AND convert(DATETIME, #to_dt, 103)
AND sh.Stat_Code <> 'CA'
GROUP BY sh.cmp_id
, d.unitcode
, d.store_code
, st.item_code
, d.item_code
, im.item_desc
END
Use table-valued parameters instead of CSV strings. Alternatively in your proc
create temp tables (table variables) first.
declare #tunitcode table (id int); -- you type may be different
insert #tunitcode(id)
select *
from utilfn_split(#unitcode, ',');
.. AND d.unitcode IN (
SELECT * FROM #tunitcode)
..

Outer apply with INSERT statement

I want to do something like this
CREATE TABLE #tempFacilitiesAssociated
(
FacilityID BIGINT,
FacilityName VARCHAR(MAX),
IsPrimary BIT
)
-- Insert statements for procedure here
;WITH CTE_RESULT AS
(
SELECT
usr_id, t.name AS Title,
usr_fname, usr_lname, primaryAddress.add_suburb,
CASE
WHEN primaryAddress.add_suburb = #suburb THEN 1
WHEN t.name = #Title THEN 2
ELSE 3
END AS MatchOrder
FROM
core_users u
LEFT JOIN
RIDE_ct_title t ON t.title_id = u.usr_title
OUTER APPLY
(INSERT INTO #tempFacilitiesAssociated
EXEC dbo.[sp_Common_Get_AllFacilitiesForSupervisor] usr_id, 5
SELECT TOP 1 fa.*
FROM CORE_Facilities f
LEFT JOIN CORE_FacilityAddresses fa ON fac_id = fa.add_owner
WHERE fac_id = (SELECT TOP 1 FacilityID
FROM #tempFacilitiesAssociated
WHERE IsPrimary = 1)) primaryAddress
WHERE
u.usr_fname = #FirstName AND usr_lname = #LastName
)
So, first I want to get all facilities of that user through a stored procedure, and then use it to outer apply and select its suburb
UPDATE
I tried using function instead
CREATE FUNCTION fn_GetAddressForUserFacility
(#UserID BIGINT)
RETURNS #Address TABLE (FacilityID BIGINT,
add_address NVARCHAR(MAX),
add_addressline2 NVARCHAR(MAX),
add_suburb NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #FacilitiesAssociated TABLE
(FacilityID BIGINT,
FacilityName NVARCHAR(MAX),
IsPrimary BIT)
INSERT INTO #FacilitiesAssociated
EXEC dbo.[sp_Common_Get_AllFacilitiesForSupervisor] #UserID, 5
INSERT INTO #Address
SELECT TOP 1
fa.add_owner, fa.add_address, fa.add_addressline2, fa.add_suburb
FROM
CORE_Facilities f
LEFT JOIN
CORE_FacilityAddresses fa ON f.fac_id = fa.add_owner AND add_type = 5
WHERE
fac_id = (SELECT TOP 1 FacilityID
FROM #FacilitiesAssociated
WHERE IsPrimary = 1)
RETURN
END
But now its returning
Invalid use of a side-effecting operator 'INSERT EXEC' within a function.

Can we make join between two stored procedures in SQL Server

I have this stored procedure:
CREATE PROCEDURE [dbo].[TestPackageAccept]
AS
BEGIN
SELECT A.Id,
a.PackageNumber,
a.Size,
a.Code,
a.TestPackageOrder,
B.status as LineCheckState,
B.ReportNumber as LineCheckReportNumber,
B.SubmitDateTime as LineCheckSubmitDateTime,
c.status as CleaningState,c.ReportNumber as CleanReportNumber,
c.SubmitDateTime as CleanSubmitDateTime,
c.status as ReInstatement,
d.ReportNumber as ReInstatementReportNumber,
d.SubmitDateTime as ReInstatementSubmitDateTime,
E.status as Flushing,
e.ReportNumber as FlushingReportNumber,
e.SubmitDateTime as FlushingSubmitDateTime,
f.status as Drying,
f.ReportNumber as DryingReportNumber,
f.SubmitDateTime as DryingSubmitDateTime,
m.status as PAD,
m.ReportNumber as PADReportNumber,
m.SubmitDateTime as PADSubmitDateTime,
n.status as Mono,
n.ReportNumber as MonoReportNumber,
n.SubmitDateTime as MonoSubmitDateTime,
p.status as Variation,
p.ReportNumber as VariationReportNumber,
p.SubmitDateTime as VariationSubmitDateTime
FROM TestPackages A
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'LineCheck')) B
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'Clean')) C
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'Reinstatment'))D
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'Flushing')) E
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'Drying')) F
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'Test')) G
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'PADTest')) M
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'Mono')) N
outer Apply (Select * from dbo.ReturnAcceptStepOfTestPackage(A.id,'Variation')) P
END;
And this
CREATE PROCEDURE [dbo].[TestPackageProgress]
AS
BEGIN
SELECT PackageId,
packagenumber,
count(*) as [Total],
sum(case [WeldStatus] when 'Accept' then 1 end) as Accept,
sum(case [WeldStatus] when 'accept' then 0 else 1 end) as Remain,
ROUND(CONVERT(float,sum(case [WeldStatus] when 'Accept' then 1 end))/CONVERT(float,count(*)) * 100,2) as PercentProgress
FROM [SPMS2].[dbo].[JointHistory]
WHERE PackageId is not null
GROUP BY PackageId,PackageNumber;
END;
Can I make a join between these two stored procedure's result sets on first.id = second.packageid?
You can put result sets from both SP into temp tables and then join them:
CREATE TABLE #PackageAccept (
Id INT,
PackageNumber INT,
Size INT,
Code NVARCHAR(100),
TestPackageOrder INT
--etc
--Here you add all columns from SP output with there datatypes
)
Then you can:
INSERT INTO #PackageAccept
EXEC [dbo].[TestPackageAccept]
The same way for second SP, then join:
SELECT *
FROM #PackageAccept pa
INNER JOIN #PackageProgress pp
ON pa.id = pp.packageid
Don't forget to DROP temp tables:
DROP TABLE #PackageAccept
DROP TABLE #PackageProgress
The full batch will be like:
IF OBJECT_ID(N'#PackageAccept') IS NOT NULL
BEGIN
DROP TABLE #PackageAccept
END
ELSE
BEGIN
CREATE TABLE #PackageAccept (
Id INT,
PackageNumber INT,
Size INT,
Code NVARCHAR(100),
TestPackageOrder INT
--etc
)
END
IF OBJECT_ID(N'#PackageProgress') IS NOT NULL
BEGIN
DROP TABLE #PackageProgress
END
ELSE
BEGIN
CREATE TABLE #P (
PackageId INT,
packagenumber INT,
[Total] INT,
Accept INT,
Remain INT
--etc
)
END
INSERT INTO #PackageAccept
EXEC [dbo].[TestPackageAccept]
INSERT INTO #PackageProgress
EXEC [dbo].[TestPackageProgress]
SELECT *
FROM #PackageAccept pa
INNER JOIN #PackageProgress pp
ON pa.id = pp.packageid

My query is not working as expected

My query is not working which is as follows:
CREATE TABLE #tempCal (
CategoryId BIGINT
,CategoryName NVARCHAR(max)
,ElementWeight MONEY
,MakingCharges MONEY
,GemstoneAttribute NVARCHAR(max)
,AlloyAttribute NVARCHAR(max)
,Rates MONEY
)
--insert into #tempCal(CategoryId,CategoryName,ElementWeight,MakingCharges,GemstoneAttribute,AlloyAttribute,Rates)
--values
DECLARE #iterator BIGINT = (
SELECT max(MstJewelleryProduct.ID)
FROM MstJewelleryProduct
)
INSERT INTO #tempCal (
CategoryId
,CategoryName
,ElementWeight
,MakingCharges
,GemstoneAttribute
,AlloyAttribute
,Rates
)
VALUES (
(
SELECT MstJewelleryProduct.ElementWeight
,MstJewelleryProduct.Element_Price
,MstJewelleryProduct.MakingCharges
,MstJewelleryProduct.GemstoneAttribute
,MstJewelleryProduct.AlloyAttribute
,MstJewelleryCategory.ID
,MstJewelleryCategory.CategoryName
,MstRates.Rates
,MstJewelleryOffers.OfferAmount
FROM MstJewelleryProduct
INNER JOIN MstJewelleryCategory ON MstJewelleryProduct.CategoryID = MstJewelleryCategory.ID
LEFT JOIN MstRates ON MstJewelleryProduct.CategoryID = MstRates.CategoryId
LEFT JOIN MstJewelleryOffers ON MstJewelleryProduct.CategoryID = MstJewelleryOffers.ProductCategory
AND MstJewelleryOffers.IsActive = 1
WHERE MstJewelleryProduct.IsActive = 1
)
)
SELECT *
FROM #tempCal
DROP TABLE #tempCal
The syntax of the (Insert Into) is not correct. When you use (Select) you do not need to use (Values). Please refer to this link to check the right syntax.