calling a udf in listing of values in a select - sql-server-2005

i have a list of items i am selecting and want to also include a few values from a UDF mixed in.
I am pulling names of people in various roles of a project management system.
where there is a name i want to get its initials, so i want to use the Abbreviate UDF mixed in the select to fn_ProjectStakeholders such that it will return names and initials along side names as its result.
see the section:
ExecutiveChampion NVARCHAR(500),
-- Abbreviate (ExecutiveChampion) as ExecutiveChampionInit,
BusinessOwner NVARCHAR(500),
-- Abbreviate (BusinessOwner) as BusinessOwnerInit,
here is my code:
CREATE FUNCTION [dbo].[fn_ProjectStakeholders]
(
#ProjectListCSV VARCHAR(8000)
)
RETURNS #TableOfValues TABLE
(
ProjectId INT,
ExecutiveChampion NVARCHAR(500),
-- Abbreviate (ExecutiveChampion) as ExecutiveChampionInit,
BusinessOwner NVARCHAR(500),
-- Abbreviate (BusinessOwner) as BusinessOwnerInit,
BusinessAnalyst NVARCHAR(500),
GeneralContractor NVARCHAR(500),
PrimaryPM NVARCHAR(500),
DevelopmentManager NVARCHAR(500),
DevelopmentLead NVARCHAR(500),
TDM NVARCHAR(500),
PTM NVARCHAR(500)
)
AS
BEGIN
DECLARE #pList TABLE (pk INT IDENTITY(1,1),ProjectId INT)
INSERT INTO #pList (ProjectId) SELECT Value FROM Split(',', #ProjectListCSV)
INSERT INTO #TableOfValues
SELECT ProjectId,
ISNULL([95],'n/a') ExecutiveChampion,
ISNULL([96],'n/a') BusinessOwner,
ISNULL([97],'n/a') BusinessAnalyst,
ISNULL([100],'n/a') GeneralContractor,
ISNULL([101],'n/a') PrimaryPM,
ISNULL([102],'n/a') DevelopmentManager,
ISNULL([103],'n/a') DevelopmentLead,
ISNULL([104],'n/a') TDM,
ISNULL([105],'n/a') PTM
FROM (
SELECT pl.ProjectId, StakeholderCID, FullName
FROM #pList pl
INNER JOIN StatusCode sc ON 1 = 1 AND SCID IN (8, 9)
LEFT JOIN ProjectStakeholder ps ON pl.ProjectId = ps.ProjectId AND sc.CID = ps.StakeholderCID
) AS ST
PIVOT
(MAX(FullName) FOR StakeholderCID IN ([95], [96], [97], [100], [101], [102], [103], [104], [105])) AS PT
RETURN
END
CREATE FUNCTION dbo.Abbreviate ( #InputString varchar(1000) )
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE #Index INT
DECLARE #OutputString VARCHAR(100)
SET #InputString = LTRIM(#InputString)
SET #OutputString = UPPER(LEFT(#InputString, 1))
SET #Index = CHARINDEX(' ', #InputString) + 1
WHILE #Index > 1
BEGIN
SET #OutputString = #OutputString + UPPER(SUBSTRING(#InputString, #Index, 1))
SET #Index = CHARINDEX(' ', #InputString, #Index) + 1
END
RETURN #OutputString
END

answer inspired by this question
my resulting code is thus:
select
--p.parentprojectid,
pp.ProjectName as ParentProjectName,
p.ProjectName as ProjectName,
p.ClarityId,
R.Name as releaseName,
CASE WHEN PSH.GeneralContractor = 'Jeff Jablonski' THEN 'Y' ELSE 'N' END as 'GC',
-- cg initials
PSH.GeneralContractor,
dbo.Abbreviate(PSH.GeneralContractor),
p.CaseManagerBenId,
P.Budget,
PSH.BusinessOwner,
PSH.DevelopmentLead ,
PSH.PrimaryPM,
PSH.DevelopmentManager,
-- SA ?!?!!?
scs.CodeName as latestStatus
-- 6x true/ false status for link types (with sanity check)
from project p
left outer join project pp on pp.projectid = p.parentprojectid
inner join Release R on R.ReleaseID = P.ReleaseID
LEFT OUTER JOIN ProjectStatus ps ON ps.ProjectId = p.ProjectId
AND ps.LastUpdate = (SELECT MAX(LastUpdate)
FROM ProjectStatus ips
WHERE ips.ProjectId = p.ProjectId)
LEFT OUTER JOIN StatusCode scs ON scs.CID = ps.RAGStatusCID
Left OUTER JOIN fn_ProjectStakeholders ('25,66,97') as PSH ON PSH.projectId = p.ProjectId
where p.projectId in (25,66,97)

Related

Offer to increase performance in stored procedure

I write this query in SQL Server 2016:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[s2_GetReceivedDocumentsCount]
#_Username NVARCHAR(MAX),
#_SearchText NVARCHAR(MAX),
#_States NVARCHAR(MAX),
#_Senders NVARCHAR(MAX),
#_Date1 NVARCHAR(MAX),
#_Date2 NVARCHAR(MAX),
#_Filter1ID NVARCHAR(MAX),
#_Filter1Value NVARCHAR(MAX)
AS
BEGIN
--https://blogs.technet.microsoft.com/mdegre/2011/11/06/what-is-parameter-sniffing/
DECLARE #Username NVARCHAR(MAX)
DECLARE #Fild BIT
DECLARE #SearchText NVARCHAR(MAX)
DECLARE #States NVARCHAR(MAX)
DECLARE #Senders NVARCHAR(MAX)
DECLARE #Date1 NVARCHAR(MAX)
DECLARE #Date2 NVARCHAR(MAX)
DECLARE #Filter1ID NVARCHAR(MAX)
DECLARE #Filter1Value NVARCHAR(MAX)
SELECT
#Username = #_Username,
#SearchText = #_SearchText,
#States = #_States,
#Senders = #_Senders,
#Date1 = #_Date1,
#Date2 = #_Date2,
#Filter1ID = #_Filter1ID,
#Filter1Value = #_Filter1Value
SELECT #SearchText = LTRIM(RTRIM(IsNull(#SearchText, '')))
SELECT #Filter1ID = LTRIM(RTRIM(IsNull(#Filter1ID, '')))
SELECT #Filter1Value = LTRIM(RTRIM(IsNull(#Filter1Value, '')))
DECLARE #PersonalPostID INT = NULL
SELECT #PersonalPostID = p.PostID
FROM Person pr
JOIN PersonPost pp ON pp.PersonID = pr.PersonID
JOIN Post p ON p.PostID = pp.PostID
WHERE pr.Username = #Username
AND p.IsPersonalPost = 1
DECLARE #independentPostExists BIT = CASE
WHEN EXISTS (SELECT 1 FROM Post t
WHERE t.Independent = 1 AND t.PostID > 0)
THEN 1
ELSE 0
END
DECLARE #temp0 TABLE (
DocumentID int
, Likeness int
, ParentScrutinyID int
)
;With AllPost
As
(
Select pp.PostID
From
PersonPost pp
Join Person prs On prs.PersonID = pp.PersonID
Where prs.Username = #Username
Union
Select [type].PostID
From
Post [type]
Join Post p On p.TypeID = [type].PostID
Join PersonPost pp On pp.PostID = p.PostID
Join Person prs On prs.PersonID = pp.PersonID
Where prs.Username = #Username
)
,
SplitSearchText
AS
(
Select * From dbo._1001_Split(dbo.ReplaceYK(#SearchText),N'')
),
Temp0
AS
(
Select Distinct
s.DocumentID
, s.Code
, s2_Scrutiny.ParentScrutinyID
From
s2_Document s
Join s2_State state On state.StateID = s.StateID
Join Post sender On sender.PostID = s.SenderID
Join s2_Scrutiny On
s2_Scrutiny.DocumentID = s.DocumentID
And s2_Scrutiny.IsActive = 1
And s2_Scrutiny.ReferenceID not in (-10, -20)
Cross Join AllPost
Join s2_Producer On s2_Producer.DocumentID = s.DocumentID
Join PersonPost producerPost On producerPost.PostID = s2_Producer.PostID
Join Person producerPerson On producerPerson.PersonID = producerPost.PersonID
Where
1 = 1
And (#States = '' Or (N',' + #States + N',') Like (N'%,' + Cast(s.StateID as nvarchar(max)) + ',%'))
And (#Senders = '' Or (N',' + #Senders + N',') Like (N'%,' + Cast(s.SenderID as nvarchar(max)) + ',%'))
And (#Date1 = '' Or s.RegistrationDate >= #Date1)
And (#Date2 = '' Or s.RegistrationDate <= #Date2)
And (#Filter1ID = ''
Or Exists(
Select 1
From
s2_FieldValue fv
Join s2_Field f On f.FieldID = fv.FieldID
Where
fv.DocumentID = s.DocumentID
And fv.FieldID = #Filter1ID
And (
(f.FieldTypeID in (0, 5/*فیلد محاسباتی*/) And fv.[Value] = #Filter1Value)
Or (f.FieldTypeID = 3 And Cast(fv.[FieldOptionID] as nvarchar(max)) = #Filter1Value)
Or (f.FieldTypeID in(1,2,4))
)
))
--پیشنهاد به پست یا نوع پستی که این شخص حائز آن است، ارجاع شده است
And AllPost.PostID = s2_Scrutiny.ReferenceID
), Temp1
AS
(
Select Distinct
s.DocumentID
,Likeness = 99999999
From Temp0 s
Where #SearchText != '' And #SearchText = ISNULL(s.Code, s.DocumentID)
Union
Select Distinct
s.DocumentID
,Likeness = SUM(ts.[Length])
From
Temp0 s
Join s2_TextSegment ts On
ts.TableName = N's2_Document'
And ts.FieldName = N'Subject'
And ts.RecordID = s.DocumentID
Where #SearchText != '' And #SearchText != ISNULL(s.Code, s.DocumentID)
Group by s.DocumentID
Union
Select Distinct
s.DocumentID
,Likeness = 1
From Temp0 s
Where #SearchText = ''
)
, Temp2
AS
(
Select t0.*, t1.Likeness
From
Temp0 t0
Join Temp1 t1 On t0.DocumentID = t1.DocumentID
)
Insert Into #temp0 (DocumentID, Likeness, ParentScrutinyID)
Select DocumentID, Likeness, ParentScrutinyID From Temp2
DECLARE #temp1 TABLE (
DocumentID int
, Likeness int
)
If #independentPostExists = 0
Begin
Insert Into #temp1 (DocumentID, Likeness)
Select
t.DocumentID
, t.Likeness
From
#temp0 t
End
ELSE
Begin--حوزه مستقلی تعریف شده باشد
--انتقال حوزه فعال باشد
Insert Into #temp1 (DocumentID, Likeness)
Select
t.DocumentID
, t.Likeness
From
#temp0 t
Join s2_Scrutiny parentScrutiny On parentScrutiny.ScrutinyID = t.ParentScrutinyID
Join s2_ScrutinyItem sci On sci.ScrutinyItemID = parentScrutiny.ScrutinyItemID
Where
sci.TransferArea = 1
-- شخص جاری در حوزه ارجاع دهنده باشد
Insert Into #temp1 (DocumentID, Likeness)
Select
t.DocumentID
, t.Likeness
From
#temp0 t
Join s2_Scrutiny parentScrutiny On parentScrutiny.ScrutinyID = t.ParentScrutinyID
Join Temp_SubalternPost tsp1 On tsp1.Subaltern_PostID = parentScrutiny.ScrutinierID
Join Temp_SubalternPost tsp2 On tsp2.Superior_PostID = tsp1.Superior_PostID
Where
tsp1.Superior_NearestIndependent = 1
And tsp2.Subaltern_PostID = #PersonalPostID
--And Not Exists(Select 1 From #temp0 tt Where tt.DocumentID = t.DocumentID)
End
Select Count(Distinct t.DocumentID) From #temp1 t Where Likeness > 0
END--end procedure
GO
This code takes 26 seconds:
exec sp_executesql N'Exec [dbo].[s2_GetReceivedDocumentsCount] #username=N'admin', #Filter1ID=N'12',#Filter1Value=N'17658'
BUT :
I tested this code for another state but returned 22,000 records in 3 seconds
exec sp_executesql N'Exec [dbo].[s2_GetReceivedDocumentsCount] #username=N'admin'
In this code I removed the #Filter1ID=N'12',#Filter1Value=N'17658'
When I remove this #Filter1ID it not enter here:
And (#Filter1ID = ''
Or Exists(
Select 1
From
s2_FieldValue fv
Join s2_Field f On f.FieldID = fv.FieldID
Where
fv.DocumentID = s.DocumentID
And fv.FieldID = #Filter1ID
And (
(f.FieldTypeID in (0, 5/*فیلد محاسباتی*/) And fv.[Value] = #Filter1Value)
Or (f.FieldTypeID = 3 And Cast(fv.[FieldOptionID] as nvarchar(max)) = #Filter1Value)
Or (f.FieldTypeID in(1,2,4))
)
))
Now I'm sure problem is here. But where is it? Where is the problem?
While correlated EXISTS clauses can be a real problem, your overall SP is such a dogs breakfast that I think you should focus on other aspects first:
Do not use LIKE to match a list of numeric values:
(N',' + #States + N',') Like (N'%,' + Cast(s.StateID as nvarchar(max)) + ',%'))
Since you already utilise string splitting function, you should split input value into a table variable of stateIDs (make sure that data type is the same as s.StateID and join it. Do the same for #Senders.
Minimise the use of OR as this kills performance really quickly:
This And (#Date1 = '' Or s.RegistrationDate >= #Date1) should be replaced by:
SET #Date1 = CASE WHEN '' THEN '01-Jan-1753' ELSE #Date1 END and then in your query you can simply have And s.RegistrationDate >= #Date1.
For #Date2 use the maximum value as per DATETIME reference.
Get rid of NVARCHAR( MAX ). Unless you realistically expect input values to be more than 4000 characters, you should use NVARCHAR( 2000 ) or something smaller.
There is a major performance difference between UNION and UNION ALL. Make sure you use UNION ALL unless you need to remove duplicate records. See this
And lastly EXISTS: without fully knowing your table structure and being able to run the query myself I cannot see a way of removing it, such that it will definitely improve performance.

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.

passing multiple varchar values to parameter in procedure [duplicate]

This question already has answers here:
Passing an array of parameters to a stored procedure
(11 answers)
Closed 8 years ago.
sp_panelistid1 '585','201401','108972',''4','5''
alter procedure sp_panelistid1
(
#branch int,
#yearweak int,
#id int ,
#branchid varchar(10))
as
print #branchid
select f.lydelse as QuestionText, f.id as QuestionID, i.artal as Year, i.vecka as Week, i.id as Intervjuperson,
b.beskrivning as Branch, b.id as BranchID, v.beskrivning as Brand, v.id as BrandID, s.regperson as Buss, f.land as CountryID
, vi.NepaVikt as Weight , cp.CintPanelistId
from fraga f
inner join svar s on s.fraga = f.id
inner join bransch b on b.id = f.bransch
inner join varumarke v on v.id = s.varumarke
inner join intervjuperson i on i.id = s.intervjuperson
inner join vikt vi ON f.Bransch = vi.Bransch AND s.Intervjuperson = vi.Intervjuperson
inner join CintPanelistIntervjuperson cp on s.Intervjuperson=cp.Intervjuperson
where f.bransch = #branch
and (100*i.artal)+i.vecka > #yearweak
and f.land = 1 and f.id=#id
and v.beskrivning in (#branchid)
I need to pass multiple values in #branch id how do I pass parameters such that it works in 'IN condition ' like v.beskrivning in ('4','5','6','7 = Stämmer helt')
If you pass comma separated ids like this - '1, 2, 3' and if you want to use with "In" clause then you have to use Split() function. like this -
SELECT f.lydelse AS QuestionText
,f.id AS QuestionID
,i.artal AS Year
,i.vecka AS Week
,i.id AS Intervjuperson
,b.beskrivning AS Branch
,b.id AS BranchID
,v.beskrivning AS Brand
,v.id AS BrandID
,s.regperson AS Buss
,f.land AS CountryID
,vi.NepaVikt AS Weight
,cp.CintPanelistId
FROM fraga f
INNER JOIN svar s ON s.fraga = f.id
INNER JOIN bransch b ON b.id = f.bransch
INNER JOIN varumarke v ON v.id = s.varumarke
INNER JOIN intervjuperson i ON i.id = s.intervjuperson
INNER JOIN vikt vi ON f.Bransch = vi.Bransch
AND s.Intervjuperson = vi.Intervjuperson
INNER JOIN CintPanelistIntervjuperson cp ON s.Intervjuperson = cp.Intervjuperson
WHERE f.bransch = #branch
AND (100 * i.artal) + i.vecka > #yearweak
AND f.land = 1
AND f.id = #id
AND v.beskrivning IN (SELECT items FROM dbo.split(#branchid, ','))
Note: Split function is not in-built function. Its used defined table-valued function.
and here is the split function.
and here is the function.
CREATE FUNCTION [dbo].[Split] (
#String NVARCHAR(4000)
,#Delimiter CHAR(1)
)
RETURNS #Results TABLE (Items NVARCHAR(4000))
AS
BEGIN
DECLARE #INDEX INT
DECLARE #SLICE NVARCHAR(4000)
-- HAVE TO SET TO 1 SO IT DOESNT EQUAL Z
SELECT #INDEX = 1
IF #String IS NULL
RETURN
WHILE #INDEX != 0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter, #STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX != 0
SELECT #SLICE = LEFT(#STRING, #INDEX - 1)
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results (Items)
VALUES (#SLICE)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING, LEN(#STRING) - #INDEX)
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0
BREAK
END
RETURN
END

Convert Comma Delimited String to bigint in SQL Server

I have a varchar string of delimited numbers separated by commas that I want to use in my SQL script but I need to compare with a bigint field in the database. Need to know to convert it:
DECLARE #RegionID varchar(200) = null
SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
SELECT a.ClassAdID, -- 1
a.AdURL, -- 2
a.AdTitle, -- 3
a.ClassAdCatID, -- 4
b.ClassAdCat, -- 5
a.Img1, -- 6
a.AdText, -- 7
a.MemberID, -- 9
a.Viewed, -- 10
c.Domain, -- 11
a.CreateDate -- 12
FROM ClassAd a
INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID
INNER JOIN Region c ON c.RegionID = a.RegionID
AND a.PostType = 'CPN'
AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0
AND a.RegionID IN (#RegionID)
AND Viewable = 'Y'
This fails with the following error:
Error converting data type varchar to bigint.
RegionID In the database is a bigint field.. need to convert the varchar to bigint.. any ideas..?
Many thanks in advance,
neojakey
create this function:
CREATE function [dbo].[f_split]
(
#param nvarchar(max),
#delimiter char(1)
)
returns #t table (val nvarchar(max), seq int)
as
begin
set #param += #delimiter
;with a as
(
select cast(1 as bigint) f, charindex(#delimiter, #param) t, 1 seq
union all
select t + 1, charindex(#delimiter, #param, t + 1), seq + 1
from a
where charindex(#delimiter, #param, t + 1) > 0
)
insert #t
select substring(#param, f, t - f), seq from a
option (maxrecursion 0)
return
end
change this part:
AND a.RegionID IN (select val from dbo.f_split(#regionID, ','))
Change this for better overall performance:
AND DATEDIFF(d, 0, GETDATE()) <= ExpirationDate
Your query does not know that those are separate values, you can use dynamic sql for this:
DECLARE #RegionID varchar(200) = null
SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
declare #sql nvarchar(Max)
set #sql = 'SELECT a.ClassAdID, -- 1
a.AdURL, -- 2
a.AdTitle, -- 3
a.ClassAdCatID, -- 4
b.ClassAdCat, -- 5
a.Img1, -- 6
a.AdText, -- 7
a.MemberID, -- 9
a.Viewed, -- 10
c.Domain, -- 11
a.CreateDate -- 12
FROM ClassAd a
INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID
INNER JOIN Region c ON c.RegionID = a.RegionID
AND a.PostType = ''CPN''
AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0
AND a.RegionID IN ('+#RegionID+')
AND Viewable = ''Y'''
exec sp_executesql #sql
I use this apporach sometimes and find it very good.
It transfors your comma-separated string into an AUX table (called #ARRAY) and then query the main table based on the AUX table:
declare #RegionID varchar(50)
SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
declare #S varchar(20)
if LEN(#RegionID) > 0 SET #RegionID = #RegionID + ','
CREATE TABLE #ARRAY(region_ID VARCHAR(20))
WHILE LEN(#RegionID) > 0 BEGIN
SELECT #S = LTRIM(SUBSTRING(#RegionID, 1, CHARINDEX(',', #RegionID) - 1))
INSERT INTO #ARRAY (region_ID) VALUES (#S)
SELECT #RegionID = SUBSTRING(#RegionID, CHARINDEX(',', #RegionID) + 1, LEN(#RegionID))
END
select * from your_table
where regionID IN (select region_ID from #ARRAY)
It avoids you from ahving to concatenate the query string and then use EXEC to execute it, which I dont think it is a very good approach.
if you need to run the code twice you will need to drop the temp table
I think the answer should be kept simple.
Try using CHARINDEX like this:
DECLARE #RegionID VARCHAR(200) = NULL
SET #RegionID =
'853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
SELECT 1
WHERE Charindex('834', #RegionID) > 0
SELECT 1
WHERE Charindex('999', #RegionID) > 0
When CHARINDEX finds the value in the large string variable, it will return it's position, otherwise it return 0.
Use this as a search tool.
The easiest way to change this query is to replace the IN function with a string function. Here is what I consider the safest approach using LIKE (which is portable among databases):
AND ','+#RegionID+',' like '%,'+cast(a.RegionID as varchar(255))+',%'
Or CHARINDEX:
AND charindex(','+cast(a.RegionID as varchar(255))+',', ','+#RegionID+',') > 0
However, if you are explicitly putting the list in your code, why not use a temporary table?
declare #RegionIds table (RegionId int);
insert into #RegionIds
select 853 union all
select 834 union all
. . .
select 303
Then you can use the table in the IN clause:
AND a.RegionId in (select RegionId from #RegionIds)
or in a JOIN clause.
I like Diego's answer some, but I think my modification is a little better because you are declaring a table variable and not creating an actual table. I know the "in" statement can be a little slow, so I did an inner join since I needed some info from the Company table anyway.
declare #companyIdList varchar(1000)
set #companyIdList = '1,2,3'
if LEN(#companyIdList) > 0 SET #companyIdList = #companyIdList + ','
declare #CompanyIds TABLE (CompanyId bigint)
declare #S varchar(20)
WHILE LEN(#companyIdList) > 0 BEGIN
SELECT #S = LTRIM(SUBSTRING(#companyIdList, 1, CHARINDEX(',', #companyIdList) - 1))
INSERT INTO #CompanyIds (CompanyId) VALUES (#S)
SELECT #companyIdList = SUBSTRING(#companyIdList, CHARINDEX(',', #companyIdList) + 1, LEN(#companyIdList))
END
select d.Id, d.Name, c.Id, c.Name
from [Division] d
inner join [Company] c on d.CompanyId = c.Id
inner join #CompanyIds cids on c.Id = cids.CompanyId

Optimizing T-SQL Insert -- temptable, CTEs, WHILE loops

I have a situation where I need to process and finally insert 1000s of records from a temptable into a database table. Before each insert, I need to ensure that conditions are met and right after each insert, I need to update a second table in my database. My problem is that currently, it takes approximately 25 minutes to run the query and I would like to drastically cut that time so my application can be more responsive. How can I go about doing this please?
DECLARE #rowcounter as INTEGER
CREATE TABLE #temporary_phonetable
(
rownumber int not null identity(1,1),
record_no BIGINT,
phone_name BIGINT,
phone_number Varchar(25) not null ,
responsemessage Varchar(200) not null ,
messagepriority Varchar(14) not null ,
phone_id BIGINT,
AD_show BIGINT,
power_show Varchar(400),
service_provider VARCHAR(30),
Phone_flag VARCHAR(30),
questionMessage BIGINT,
PRIMARY KEY (phone_id, phone_number, rownumber)
,UNIQUE (questionMessage, record_no, rownumber)
)
--GET PHONE DATA
--if phone numbers are sent in from the client, then we want to process those instead
IF ( ( ( #listofphones IS NULL OR LEN(#listofphones) <1) AND LEN(#peoplegroups) >0) )
BEGIN
--NO PHONENUMBER BUT THERE ARE GROUPS AVAILABLE
INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show, responsemessage)
SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE #includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + #responsemessages
ELSE #responsemessages END as text_message
FROM user u WITH(NOLOCK)
INNER JOIN Phonenumbers n WITH(NOLOCK) ON n.user_no = u.user_no
INNER JOIN PeopleGroupRelations g ON g.phone_id=n.phone_id
INNER JOIN ( Select items FROM Split(#peoplegroups, #listofphonesdelimiter)) gg ON g.group_no = gg.items
WHERE n.user_no=#userid
AND n.status=''active''
SET #rowcounter = ##ROWCOUNT
END
ELSE IF ( LEN(#listofphones) >1 AND LEN(#peoplegroups) >0)
BEGIN
--PHONENUMBER AND GROUPS
INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show, responsemessage)
SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE #includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + #responsemessages
ELSE #responsemessages END as text_message
FROM Split(#listofphones, ''|'') s
INNER JOIN PhoneNumbers n WITH(NOLOCK) ON n.phone_number = s.items
INNER JOIN User u WITH(NOLOCK) ON n.user_no =u.user_no
INNER JOIN PeoplegroupRelations g ON g.phone_id=n.phone_id
INNER JOIN ( Select items FROM Split(#peoplegroups, #listofphonesdelimiter)) gg ON g.group_no = gg.items
WHERE n.user_no=#userid
AND n.status=''active''
SET #rowcounter = ##ROWCOUNT
END
ELSE IF ( LEN(#listofphones) >1 AND LEN(#peoplegroups) >0)
BEGIN
--PHONENUMBER AND NO GROUPS
INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show, responsemessage)
SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE #includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + #responsemessages
ELSE #responsemessages END as text_message
FROM Split(#listofphones, ''|'') s
INNER JOIN PhoneNumbers n WITH(NOLOCK) ON n.phone_number = s.items
INNER JOIN User u WITH(NOLOCK) ON n.user_no =u.user_no
INNER JOIN PeopleGroupRelations g ON g.phone_id=n.phone_id
INNER JOIN ( Select items FROM Split(#peoplegroups, #listofphonesdelimiter)) gg ON g.group_no = gg.items
WHERE n.user_no=#userid
AND n.status=''active''
SET #rowcounter = ##ROWCOUNT
END
ELSE
BEGIN
-- NO PHONENUMBER NO GROUP --- IE. SEND TO ALL PHONE NUMBERS
INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show,responsemessage)
SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE #includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + #responsemessages
ELSE #responsemessages END as text_message
FROM User u
INNER JOIN PhoneNumbers n ON n.user_no = u.user_no
WHERE
n.status=''active''
AND n.user_no=#userid
SET #rowcounter = ##ROWCOUNT
END
IF( #rowcounter>0)
BEGIN
DECLARE #service_provider as Varchar(30)
DECLARE #PhoneType as Varchar(30)
IF (LOWER(RTRIM(LTRIM(#sendresponseswhen))) ='now')
BEGIN
SET #dateresponsessent = GETDATE()
END
DECLARE #rownumber int
DECLARE #power_show BIT
DECLARE #AD_show BIT
set #rownumber = 0
WHILE #rownumber < #rowcounter
BEGIN
set #rownumber = #rownumber + 1
-- THE VARIABLES
DECLARE #record_no as BIGINT
DECLARE #phone_name VARCHAR(30)
DECLARE #messagepriority as INTEGER
DECLARE #phone_number VARCHAR(30)
DECLARE #phone_id BIGINT
DECLARE #questionMessage BIGINT
SELECT
#phone_name = n.phone_name, #phone_number =n.phone_number, #messagepriority =n.messagepriority, #phone_id=n.phone_id ,
#AD_show=n.AD_show, #power_show=n.power_show
FROM
#temporary_phonetable n WITH(NOLOCK)
WHERE n.rownumber = #rownumber
SET #record_no = AddMessageToQueue(#phone_number, #responsemessages, #dateresponsessent, #savednames, #userid, un.messagepriority, #responsetype,
un.AD_show, un.power_show, #service_provider, #PhoneType)
If(#questionid > 0)
BEGIN
SET #questionMessage = AddQuestionMessage(#questionid,#phone_id, #record_no, DATEADD(d, 30, GETDATE()) )
END
UPDATE #temporary_phonetable SET record_no = #record_no, questionMessage=#questionMessage WHERE phone_number = #phone_number AND rownumber = #rownumber
END
IF( #power_show >0)
BEGIN
SET #responsemessages = #responsemessages + dbo.returnPoweredBy()
END
IF( #AD_show > 0)
BEGIN
SELECT #responsemessages = #responsemessages + CASE
WHEN (LEN(#responsemessages) + 14)< 160 THEN dbo.returnAD(#responsemessages)
ELSE '''' END
END
RETURN #rowcounter
END
I believe this is the place where the bulk of the issue resides.
WHILE #rownumber < #rowcounter
BEGIN
set #rownumber = #rownumber + 1
-- THE VARIABLES
DECLARE #record_no as BIGINT
DECLARE #phone_name VARCHAR(30)
DECLARE #messagepriority as INTEGER
DECLARE #phone_number VARCHAR(30)
DECLARE #phone_id BIGINT
DECLARE #questionMessage BIGINT
SELECT
#phone_name = n.phone_name, #phone_number =n.phone_number, #messagepriority =n.messagepriority, #phone_id=n.phone_id ,
#AD_show=n.AD_show, #power_show=n.power_show
FROM
#temporary_phonetable n WITH(NOLOCK)
WHERE n.rownumber = #rownumber
SET #record_no = AddMessageToQueue(#phone_number, #responsemessages, #dateresponsessent, #savednames, #userid, un.messagepriority, #responsetype,
un.AD_show, un.power_show, #service_provider, #PhoneType)
If(#questionid > 0)
BEGIN
SET #questionMessage = AddQuestionMessage(#questionid,#phone_id, #record_no, DATEADD(d, 30, GETDATE()) )
END
UPDATE #temporary_phonetable SET record_no = #record_no, questionMessage=#questionMessage WHERE phone_number = #phone_number AND rownumber = #rownumber
END
Add a unique constraint to rownumber in your temp table. Rewrite the WHILE as a CTE. Use APPLY to call the functions.
You also might want to consider using a table variable rather than a temporary table. You won't be writing to the tempdb and as table variables are created in memory they're faster.
This article has a nice comparison.