Using parameters of Stored Procedure with Join's "ON" area - tsql

I have parameters like these
declare #Phl1_descr varchar(50)
SET #Phl1_descr = 'Greece'
declare #Phl2_descr varchar(50)
SET #Phl2_descr = 'Coffee & Beverages'
I want to join two tables with the above parameters (if they are not null), so I tried to do something like below in the "ON" keyword of my JOIN
ON
(CASE WHEN LEN(#Phl1_descr) > 0 THEN A.Phl1_descr ELSE B.Phl1_descr END) = B.Phl1_descr AND
(CASE WHEN LEN(#Phl2_descr) > 0 THEN A.Phl2_descr ELSE B.Phl2_descr END) = B.Phl2_descr
However if I send one of the parameters like as '', it doesn't work. Any simpler idea?

Is it posible to use simpler solution? Like:
IF #Phl1_descr IS NOT NULL AND #Phl2_descr IS NOT NULL
BEGIN
SELECT *
FROM Table1 as A
LEFT JOIN Table2 as B on A.Phl1_descr=B.Phl1_descr and A.Phl2_descr=B.Phl2_descr
END
ELSE IF #Phl1_descr IS NOT NULL AND #Phl2_descr IS NULL
BEGIN
SELECT *
FROM Table1 as A
LEFT JOIN Table2 as B on A.Phl1_descr=B.Phl1_descr
END
ELSE IF #Phl1_descr IS NULL AND #Phl2_descr IS NOT NULL
BEGIN
SELECT *
FROM Table1 as A
LEFT JOIN Table2 as B on A.Phl2_descr=B.Phl2_descr
END
So you will get a simpler execution plans and simpler logic.
You can also use ... CASE WHEN #Phl1_descr IS NULL THEN ... to check NULL values

Interesting but
B.Phl1_descr = B.Phl1_descr
not working but
ISNULL(B.Phl1_descr,'-1') = ISNULL(B.Phl1_descr,'-1')
works,
So just a simple change in the below code work it out
(CASE WHEN LEN(#Phl1_descr) > 1 THEN A.Phl1_descr ELSE ISNULL(B.Phl1_descr,'-1') END) = ISNULL(B.Phl1_descr,'-1') AND
(CASE WHEN LEN(#Phl2_descr) > 1 THEN A.Phl2_descr ELSE ISNULL(B.Phl2_descr,'-1') END) = ISNULL(B.Phl2_descr,'-1') AND

Related

db2 - Update statement using subselect with case

I want to do an update statement according to a result of a subquery
For example :
Update TABLE1
set A= (Select Count(*) from TABLE2 )
if the value of count is 0 then Update the value of A to be 0 Else set A = 1;
So could you please advice me how can I do it?
I tried the following but I got a syntax error :
SELECT count(*) as TC
CASE
WHEN TC > 0
THEN '1'
ELSE '0'
END AS dum
FROM Event E where E.Type= 'CANCELLING';
CASE is perfectly suitable:
UPDATE TABLE1
SET A =
CASE
WHEN (SELECT count(*) FROM TABLE2) > 0 THEN 1
ELSE 0
END
declare #count int
set #count=Select Count(*) from TABLE2
if #count=0
BEGIN
Update TABLE1
set A=0
end
else
Update TABLE1
set A=1

How to write a multi-parameter CTE script?

I am trying to write a TSQL script for an SSRS report that uses a CTE to select records based on the parameters chosen. I'm looking for the most efficient way to do this, either all in TSQL and/or SSRS. I have 4 parameters which can be set to NULL (All values) or one specific value. Then in my CTE, I have the following line:
ROW_NUMBER() over(partition by G.[program_providing_service],G.people_id
order by G.[actual_date] desc) as rowID
This above CTE is for the case when Program is NULL and People is not null. My 4 parameters are:
Program, Facility, Staff, and People.
So I only want to partition values when they are NULL. Currently I implement this by one CTE depending on the parameter values. For example, if they choose NULL for all parameters except People, then this CTE would look like:
ROW_NUMBER() over(partition by G.people_id
order by G.[actual_date] desc) as rowID
Or if all 5 parameters are null:
ROW_NUMBER() over(partition by G.[program_providing_service], G.[site_providing_service], G.staff_id, G.people_id
order by G.[actual_date] desc) as rowID
If they do not choose NULL for any of the 4 parameters, then I probably do not need to partition by any field since I just want the top 1 record ordered by actual_date descending. This is what my CTE looks like:
;with cte as
(
Select distinct
G.[actual_date],
G.[site_providing_service],
p.[program_name],
G.[staff_id],
G.program_providing_service,
ROW_NUMBER() over(partition by G.[program_providing_service],G.people_id
order by G.[actual_date] desc) as rowID
From
event_log_rv G With (NoLock)
WHERE
...
AND (#ClientID Is Null OR [people_id]=#ClientID)
AND (#StaffID Is Null OR [staff_id] = #StaffID)
AND (#FacilityID Is Null OR [site_providing_service] = #FacilityID)
AND (#ProgramID Is Null OR [program_providing_service] = #ProgramID)
and (#SupervisorID is NULL OR staff_id in (select staff_id from #supervisors))
)
SELECT
[actual_date],
[site_providing_service],
[program_name],
[staff_id],
program_providing_service,
people_id,
rowID
FROM cte WHERE rowid = 1
ORDER BY [Client_FullName]
where the ROW_NUMBER line varies depending on the parameters chosen. Currently I have 5 IF statements in this TSQL script that look like:
IF #ProgramID IS NOT NULL AND #ClientID IS NULL
BEGIN
...
END
with one CTE in each of these IF statements:
IF #FacilityID IS NOT NULL AND #ClientID IS NULL
BEGIN
...
END
IF #ProgramID IS NOT NULL AND #ClientID IS NULL
BEGIN
...
END
IF #StaffID IS NOT NULL AND #ClientID IS NULL
BEGIN
...
END
IF #ClientID IS NOT NULL
BEGIN
...
END
How can I code for all possible options, whether they choose NULL or else specific values?
OMG.... it took me long time to try to understand what you want to do. There is some contradiction in your description. Pleas revist your description. Like you said you only want to partition values when they are NULL; then you also said, when they choose NULL for all parameter except for people, then you partition on people....
No matter what way you want to achieve, partition on 'null' or 'not null', you can construct dynamic sql to achieve this, instead of adding a lot of [if...else]
Following code is pseudo, definitely not tested. Just give you a hint. The following code has one assumption, which is your parameters have priority in partition order, for example, if Program is not null (or null), Program is in the first location.
declare #sql varchar(max)
set #sql = '
;with cte as
(
Select distinct
G.[actual_date],
G.[site_providing_service],
p.[program_name],
G.[staff_id],
G.program_providing_service,
ROW_NUMBER() over(partition by
'
if(#progarm is null)
set #sql = #sql + 'G.[program_providing_service],'
if(#facility is null)
set #sql = #sql + 'G.[site_providing_service],'
if(#staff is null )
set #sql = #sql + 'G.staff_id,'
if(#people is null)
set #sql = #sql + 'G.people_id'
set #sql = #sql + '
order by G.[actual_date] desc) as rowID
From
event_log_rv G With (NoLock)
WHERE
...
AND (#ClientID Is Null OR [people_id]=#ClientID)
AND (#StaffID Is Null OR [staff_id] = #StaffID)
AND (#FacilityID Is Null OR [site_providing_service] = #FacilityID)
AND (#ProgramID Is Null OR [program_providing_service] = #ProgramID)
and (#SupervisorID is NULL OR staff_id in (select staff_id from #supervisors))
)
SELECT
[actual_date],
[site_providing_service],
[program_name],
[staff_id],
program_providing_service,
people_id,
rowID
FROM cte WHERE rowid = 1
ORDER BY [Client_FullName]
'
exec(#sql)

TSQL return all records in-case of null inside IN

I want to filter by #campId if not null, or return all if null
This compiles but does not work as intended:
declare #campId int
select *
from cli
where
cu in (
CASE #campId
when null then (select id from [dbo].[camp])
else #campId
end)
if cu is never null
where cu = isnull(#campid, cu)
Try this:
select *
from cli
where
cu in (select isnull(#campId, id) from [dbo].[camp])
This takes advantage of the fact that the select from camp will return #campId if it's not null.
Why not simply use an IF statement?
DECLARE #campId AS INT
IF (#campId IS NULL) BEGIN
SELECT [Column1], [Column2], ...
FROM [dbo].[cli] AS C1
INNER JOIN [dbo].[Camp] AS C2 ON C2.[Id] = C1.[Cu]
END
ELSE BEGIN
SELECT [Column1], [Column2], ...
FROM [dbo].[cli] AS
WHERE [Cu] = #camp
END

Establishing Upper / Lower Bound in T-SQL Procedure

I am trying to establish upper / lower bound in my stored procedure
below and am having some problems at the end (I am getting no results
where, without the temp table inner join i get the expected results).
I need some help where I am trying to join the columns in my temp table #PageIndexForUsers
to the rest of my join statement and I am mucking something up with
this statement:
INNER JOIN
#PageIndexForUsers ON ( dbo.aspnet_Users.UserId =
#PageIndexForUsers.UserId AND #PageIndexForUsers.IndexId >= #PageLowerBound AND
#PageIndexForUsers.IndexId <= #PageUpperBound )
I could use feedback at this point - and, any advice on how to improve
my procedure's logic (if you see anything else that needs improvement) is also appreciated.
Thanks in advance...
ALTER PROCEDURE dbo.wb_Membership_GetAllUsers
#ApplicationName nvarchar(256),
#sortOrderId smallint = 0,
#PageIndex int,
#PageSize int
AS
BEGIN
DECLARE #ApplicationId uniqueidentifier
SELECT #ApplicationId = NULL
SELECT #ApplicationId = ApplicationId FROM dbo.aspnet_Applications WHERE LOWER(#ApplicationName) = LoweredApplicationName
IF (#ApplicationId IS NULL)
RETURN 0
-- Set the page bounds
DECLARE #PageLowerBound int
DECLARE #PageUpperBound int
DECLARE #TotalRecords int
SET #PageLowerBound = #PageSize * #PageIndex
SET #PageUpperBound = #PageSize - 1 + #PageLowerBound
BEGIN TRY
-- Create a temp table TO store the select results
CREATE TABLE #PageIndexForUsers
(
IndexId int IDENTITY (0, 1) NOT NULL,
UserId uniqueidentifier
)
-- Insert into our temp table
INSERT INTO #PageIndexForUsers (UserId)
SELECT u.UserId
FROM dbo.aspnet_Membership m, dbo.aspnet_Users u
WHERE u.ApplicationId = #ApplicationId AND u.UserId = m.UserId
ORDER BY u.UserName
SELECT #TotalRecords = ##ROWCOUNT
SELECT dbo.wb_Profiles.profileid, dbo.wb_ProfileData.firstname, dbo.wb_ProfileData.lastname, dbo.wb_Email.emailaddress, dbo.wb_Email.isconfirmed, dbo.wb_Email.emaildomain, dbo.wb_Address.streetname, dbo.wb_Address.cityorprovince, dbo.wb_Address.state, dbo.wb_Address.postalorzip, dbo.wb_Address.country, dbo.wb_ProfileAddress.addresstype,dbo.wb_ProfileData.birthday, dbo.wb_ProfileData.gender, dbo.wb_Session.sessionid, dbo.wb_Session.lastactivitydate, dbo.aspnet_Membership.userid, dbo.aspnet_Membership.password, dbo.aspnet_Membership.passwordquestion, dbo.aspnet_Membership.passwordanswer, dbo.aspnet_Membership.createdate
FROM dbo.wb_Profiles
INNER JOIN dbo.wb_ProfileAddress
ON
(
dbo.wb_Profiles.profileid = dbo.wb_ProfileAddress.profileid
AND dbo.wb_ProfileAddress.addresstype = 'home'
)
INNER JOIN dbo.wb_Address
ON dbo.wb_ProfileAddress.addressid = dbo.wb_Address.addressid
INNER JOIN dbo.wb_ProfileData
ON dbo.wb_Profiles.profileid = dbo.wb_ProfileData.profileid
INNER JOIN dbo.wb_Email
ON
(
dbo.wb_Profiles.profileid = dbo.wb_Email.profileid
AND dbo.wb_Email.isprimary = 1
)
INNER JOIN dbo.wb_Session
ON dbo.wb_Profiles.profileid = dbo.wb_Session.profileid
INNER JOIN
dbo.aspnet_Membership
ON dbo.wb_Profiles.userid = dbo.aspnet_Membership.userid
INNER JOIN
dbo.aspnet_Users
ON dbo.aspnet_Membership.UserId = dbo.aspnet_Users.UserId
INNER JOIN
dbo.aspnet_Applications
ON dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
INNER JOIN
#PageIndexForUsers ON ( dbo.aspnet_Users.UserId =
#PageIndexForUsers.UserId AND #PageIndexForUsers.IndexId >= #PageLowerBound AND
#PageIndexForUsers.IndexId <= #PageUpperBound )
ORDER BY CASE #sortOrderId
WHEN 1 THEN dbo.wb_ProfileData.lastname
WHEN 2 THEN dbo.wb_Profiles.username
WHEN 3 THEN dbo.wb_Address.postalorzip
WHEN 4 THEN dbo.wb_Address.state
END
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 ROLLBACK TRAN
EXEC wb_ErrorHandler
RETURN 55555
END CATCH
RETURN #TotalRecords
END
GO
You don't have enough rows in #PageIndexForUsers, no?
If #PageSize = 50 and you want #PageIndex 2, then you are looking for rows 100 to 149 from #PageIndexForUsers. Do you have this many rows?
The row filter should be applied over the larger dataset that starts FROM dbo.wb_Profiles

TSQL Hack needed for getting a filter for data

A UI (before the report shows) shows a look up (Combo) that has
(ID = 0).All Organization Units
(ID =4).HR
(ID = 5).DEV
I need to:
Be able to show data of (4) + (5) if
(0) is selected.
Only (4) OR (5) if either HR or DEV is selected.
Lookup combo code (Selected Feeds the parameter in the below query.)
Select 0 AS ID,'All Org' AS Name from DP_ORG_OrganizationUnit
where DP_ORG_OrganizationUnit.Code IN {AccessData}
Union
SELECT
DP_ORG_OrganizationUnit.ID,
DP_ORG_OrganizationUnit.Name
FROM DP_ORG_OrganizationUnit where DP_ORG_OrganizationUnit.Code IN ('HR','DEV')
Report data row query
SET CONCAT_NULL_YIELDS_NULL OFF
DECLARE #EmpID as int;
DECLARE #OrganizationUnit as int;
DECLARE #StartDate as datetime;
DECLARE #EndDate as datetime;
SET #EmpID = ?;
SET #StartDate = ?;
SET #EndDate = ?;
SET #OrganizationUnit = ?;
SELECT
Employee.Code,
Employee.Name1+' '+Employee.Name2+' '+Employee.Name3+' '+Employee.Name4+' '+Employee.Name5 AS FullName,
Employee.OrganizationUnit,
ContractType.Name,
EmployeeContract.StartDate,
EmployeeContract.EndDate
FROM Employee INNER JOIN (ContractType INNER JOIN EmployeeContract
ON ContractType.ID = EmployeeContract.ContractType)
ON Employee.ID = EmployeeContract.Employee
WHERE (Employee.ID = #EmpID OR #EmpID=0)
AND
(Employee.OrganizationUnit = #OrganizationUnit OR #OrganizationUnit=0)
AND NOT((EndDate < #StartDate or StartDate > #EndDate));
Any way I can achieve it from the looks of it? 0=0 would show all the data from other
departments too..
Anybody :-o?
First off, your lookup combo code could be tightened up a bit:
-- the FROM clause was superfluous
SELECT 0 AS ID,'All Org' AS Name
UNION ALL
-- the two-part identifiers were superfluous (only one table)
SELECT ID, Name
FROM DP_ORG_OrganizationUnit
WHERE Code IN ('HR','DEV')
For the report query, the simplest form would be:
WHERE
((#OrganizationUnit > 0 AND Employee.OrganizationUnit = #OrganizationUnit) OR
(#OrganizationUnit = 0 AND Employee.OrganizationUnit IN (4,5)))
something like this should work
Where (Employee.OrganizationUnit = case when #OrganizationUnit=0 then 4 else #OrganizationUnit end OR case when #OrganizationUnit=0 then 5 else #OrganizationUnit end)
Try this, which should use indexes on your query...
DECALRE #FilterValues (FilterValue int not null primary key)
IF #Param=0
BEGIN
INSERT INTO #FilterValues VALUES (4)
INSERT INTO #FilterValues VALUES (5)
END
ELSE ID #PAram IS NOT NULL
BEGIN
INSERT INTO #FilterValues VALUES (#Param)
END
SELECT
....
FROM YourTable y
INNER JOIN #FilterValues f ON y.Value=f.Value
WHERE .....
KM's version will work, but this query does not need a temp table...
SELECT *
FROM Employee
WHERE (
#OrganizationUnit = 0
OR
(
#OrganizationUnit <> 0
AND
Employee.OrganizationUnit = #OrganizationUnit
)
)
How about
WHERE (Employee.ID = #EmpID OR #EmpID=0)
AND
(Employee.OrganizationUnit BETWEEN ISNULL(NULLIF(#OrganizationUnit,0),0) AND ISNULL(NULLIF(#OrganizationUnit,0),99))
AND NOT((EndDate < #StartDate or StartDate > #EndDate));