Skip a WHERE condition if a #variable is empty - sql

In the below code I don't want the second part of the join condition to be applicable if #selectAll = 1
(ie and (listMap.dateOfTask between #startDate and #endDate)
I am using SQL Server.
#userId nvarchar(200),
#startDate nvarchar(200),
#endDate nvarchar(200),
#selectAll bit
select
*
from tmListMap l
right join tmTime t
on
l.timeId = t.timeId
and (l.dateOfTask between #startDate and #endDate) //Don’t need this condition if #selectAll = 1

#Damien suggested you need a or condition like
#userId nvarchar(200),
#startDate nvarchar(200),
#endDate nvarchar(200),
#selectAll bit
select
*
from tmListMap l
right join tmTime t
on
l.timeId = t.timeId
and ((l.dateOfTask between #startDate and #endDate) or #selectAll=1)

#userId nvarchar(200),
#startDate nvarchar(200),
#endDate nvarchar(200),
#selectAll bit
select
*
from tmListMap l
right join tmTime t
on
l.timeId = t.timeId
where #selectAll = 1 or (l.dateOfTask between #startDate and #endDate)

Two options.
Option A as OR clause
#startDate date,
#endDate date,
#selectAll bit
select
*
from tmListMap l
right join tmTime t
on l.timeId = t.timeId
WHERE
(
l.dateOfTask between #startDate and #endDate and #selectAll = 0
OR
#selectAll = 1
)
Option B as UNION ALL
#startDate date,
#endDate date,
#selectAll bit
select
*
from tmListMap l
right join tmTime t
on l.timeId = t.timeId
WHERE #selectAll = 0
and l.dateOfTask between #startDate and #endDate
UNION ALL
select
*
from tmListMap l
right join tmTime t
on l.timeId = t.timeId
WHERE #selectAll = 1
Depends a bit on your data which will be faster. In my experience the UNION ALL scales better. As long as the different parts are absolutely not able to create duplicates.

Related

Sql joins returning Null Results and not accepting conditions

I have 4 tables that I am trying to get data from yet my join statement returns null. I have tried full, left and right joins with no success. Below I have provided my code and the diagram, the table that returns null values is the ChannelData table. I am trying to sum the Vvalue from this table, when i add the condition that i commented out below i.e.between start and end date` my query return no results. I know there must be a problem with my joins but I have tried everything. This table is not normalized properly and I have to use it as is:
DECLARE #bp varchar(4)
DECLARE #priority varchar(2)
DECLARE #startDate datetime
DECLARE #endDate datetime
SET #bp = 1710
SET #priority = 2
SET #endDate = (SELECT EndDate FROM BillingPeriod WHERE BillingPeriodClass_ID = 1 AND CODE = #BP)
SET #startDate = (SELECT EndDate FROM BillingPeriod WHERE BillingPeriodClass_ID = 1 AND CODE = #BP -1 )
SET #startDate = dateadd(minute, 1, #startDate)
SELECT CGS.Description, SUM(CD.Vvalue) AS P_Val, COUNT(CD.VValue) AS P_Rec, DI.Margin
FROM CGS AS CGS
FULL JOIN ChannelParameter AS CP ON CP.ID = CGS.ID
FULL JOIN ChannelData AS CD ON CP.ID = CD.ID
FULL JOIN DataIntegrity AS DI ON DI.CGS_ID_1 = CGS.ID OR DI.CGS_ID_2 = CGS.ID
WHERE --CD.DDate BETWEEN #startDate AND #endDate AND
DI.Priority = #priority
group by CGS.Description, DI.Margin
Click this for Query Result
Please see below:
Channel Data Table
Channel Parameter Table
I have attached pictures as links: also here is what i mean by the table not being normalised properly they both have CGS.ID as a primrary and foreign key but this is actually a primary key in the cgs table the problem is when i try and join the DI table i dont get results from all tables:
DECLARE #bp varchar(4)
DECLARE #priority varchar(2)
DECLARE #startDate datetime
DECLARE #endDate datetime
SET #bp = 1710
SET #priority = 2
SET #endDate = (SELECT EndDate FROM BillingPeriod WHERE BillingPeriodClass_ID = 1 AND CODE = #BP)
SET #startDate = (SELECT EndDate FROM BillingPeriod WHERE BillingPeriodClass_ID = 1 AND CODE = #BP -1 )
SET #startDate = dateadd(minute, 1, #startDate)
SELECT CGS.Description, SUM(CD.Vvalue) AS P_Val, COUNT(CD.VValue) AS P_Rec
FROM CGS AS CGS
FULL JOIN ChannelParameter AS CP ON CP.ID = CGS.ID
FULL JOIN ChannelData AS CD ON CP.ID = CD.ID
WHERE CD.DDate BETWEEN #startDate AND #endDate and CGS.ID = 88
group by CGS.Description
RESULT :
Description P_Val P_Rec
EP 308 12 CONTROL TRF FEEDER NO 1 - Q Exp, 4514.37, 1488
The problem is pretty clear that there is no matched record for CD.DDate BETWEEN #startDate AND #endDate condition. And I suspected that #startDate variable might be null because of returning no record for CODE = #BP -1 condition. So, would you try to change this line;
SET #startDate = (SELECT top 1 EndDate FROM BillingPeriod
WHERE BillingPeriodClass_ID = 1 AND CODE < #BP order by CODE desc)

Column Invalid in the Selected List

I have this scalar function:
ALTER FUNCTION [dbo].[Custom_SumKayakoMonthProfit]
(#ClientId int, #KKId int,
#StartDate SmallDateTime, #EndDate SmallDatetime,
#Month int)
RETURNS INT
AS
BEGIN
DECLARE #Total INT
SELECT
#Total = ((CAST(SUM(WorkedTimeInMinutes) AS FLOAT) / 60) * KayakoValue)
FROM
[VDBSERVER2012\SQLEXPRESS2014].PlaterITDB.dbo.KayakoTimeEntries
INNER JOIN
ClientContract ON ClientId = #ClientId
AND Workdate BETWEEN ClientContract.StartDt AND ClientContract.EndDt
WHERE
OrganizationID = #KKId
AND WorkDate BETWEEN #StartDate AND #EndDate
AND MONTH(WorkDate) = #Month
RETURN #Total
END
Whenever I try to execute it to use it on a stored procedure, I get this error.
Column 'ClientContract.KayakoValue' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I can't figure out how to solve it.
What don't you understand about the message? You have an aggregation query with no GROUP BY. Hence, all columns must be the arguments to aggregation functions.
I suspect that you intend:
SELECT #Total = CAST(SUM(WorkedTimeInMinutes * KayakoValue) AS FLOAT)/60
FROM [VDBSERVER2012\SQLEXPRESS2014].PlaterITDB.dbo.KayakoTimeEntries kte INNER JOIN
ClientContract cc
ON ClientId = #ClientId AND
Workdate BETWEEN cc.StartDt AND cc.EndDt
WHERE OrganizationID = #KKId AND
WorkDate BETWEEN #StartDate AND #EndDate AND MONTH(WorkDate) = #Month
Note that you should learn to use table aliases and to qualify all column names. This is a good practice for writing readable and maintainable code.
You should use 'KayakoValue' in aggregate function like sum,count, . . . or in group by at the end .
SELECT #Total = ((CAST(SUM(WorkedTimeInMinutes) AS FLOAT)/60) * KayakoValue)
FROM [VDBSERVER2012\SQLEXPRESS2014].PlaterITDB.dbo.KayakoTimeEntries
INNER JOIN ClientContract ON ClientId = #ClientId AND Workdate BETWEEN ClientContract.StartDt AND ClientContract.EndDt
WHERE OrganizationID = #KKId AND WorkDate BETWEEN #StartDate AND #EndDate AND MONTH(WorkDate) = #Month
group by KayakoValue
OR
SELECT #Total = ((CAST(SUM(WorkedTimeInMinutes * KayakoValue) AS FLOAT)/60))
FROM [VDBSERVER2012\SQLEXPRESS2014].PlaterITDB.dbo.KayakoTimeEntries
INNER JOIN ClientContract ON ClientId = #ClientId AND Workdate BETWEEN ClientContract.StartDt AND ClientContract.EndDt
WHERE OrganizationID = #KKId AND WorkDate BETWEEN #StartDate AND #EndDate AND MONTH(WorkDate) = #Month

Can we merge 2 SQL with same logic with just marginally difference?

I have 2 SQLs,
SELECT #AlreadyPerformedActionsPerDay = COUNT(*)
FROM UserRewardActions URA
INNER JOIN UserRewardActionTypes URAT ON URAT.ID = URA.UserRewardActionTypeID
WHERE URA.UserID = #UserID
AND (
#UserRewardActionTypeID = 1 -- Because the register action is not per-date-wise(only allows once in lifetime)
OR CreationDateInUtc BETWEEN CAST(GETUTCDATE() AS DATE) AND DATEADD(DAY, 1, CAST(GETUTCDATE() AS DATE)) -- Inside Current Date
);
SELECT #AlreadyRedeemedTheCurrentAction = 1
FROM UserRewardActions URA
INNER JOIN UserRewardActionTypes URAT ON URAT.ID = URA.UserRewardActionTypeID
WHERE URA.UserID = #UserID
AND CreationDateInUtc BETWEEN CAST(GETUTCDATE() AS DATE) AND DATEADD(DAY, 1, CAST(GETUTCDATE() AS DATE)) -- Inside Current Date
AND URL IS NOT NULL
AND URL = #Url;
The fist SQL is the grabbing total number of user actions today. Second, is checking whether the current url is already used by the same user. This is fine. But I am looking to merge this query for performance issue.
well, after reformatting your queries as below. I can see that they have different criteria.
DECLARE #from DateTime;
DECLARE #to DateTime;
SET #from = cast(getutcdate() as Date);
SET #to = dateadd(DAY, 1, #from));
SELECT
#AlreadyPerformedActionsPerDay = COUNT(*)
FROM
UserRewardActions URA
JOIN
UserRewardActionTypes URAT
ON URAT.ID = URA.UserRewardActionTypeID
WHERE
URA.UserID = #UserID
AND
(
#UserRewardActionTypeID = 1
OR
CreationDateInUtc BETWEEN #from AND #to
);
SELECT
#AlreadyRedeemedTheCurrentAction = 1
FROM
UserRewardActions URA
JOIN
UserRewardActionTypes URAT
ON URAT.ID = URA.UserRewardActionTypeID
WHERE
URA.UserID = #UserID
AND
CreationDateInUtc BETWEEN #from AND #to
AND
URL IS NOT NULL
AND
URL = #Url;

Remove subquery from JOIN?

In the following query, I would like the remove the subquery from the JOIN statement (since my two SELECT statements are selecting data from same table). How can I use that alias? Thanks in advance for any help.
declare #StartDate datetime= '8/01/2011'
declare #EndDate datetime = '9/20/2011'
declare #PortfolioId int = 6
SELECT
Previous.PreviousNAV,
Todays.TodaysNAV,
ISNULL((Todays.TodaysNAV-Previous.PreviousNAV),0) NetChange,
ISNULL((Todays.TodaysNAV-Previous.PreviousNAV) / Todays.TodaysNAV,0) BAMLIndex
FROM
(
SELECT PortfolioId,ISNULL(NAV,0) PreviousNAV
FROM Fireball..NAV
WHERE Date BETWEEN #StartDate AND #EndDate and PortfolioId = #PortfolioId
) Previous
JOIN
(
SELECT PortfolioId,ISNULL(NAV,0) TodaysNAV
FROM Fireball..NAV
WHERE Date = #EndDate and PortfolioId = #PortfolioId
) Todays
ON Previous.PortfolioId = Todays.PortfolioId
Just eliminate the subqueries entirely. I don't think they add anything to the query. Try this instead:
SELECT
Previous.NAV as PreviousNAV,
Todays.NAV as TodaysNav,
ISNULL((Todays.NAV-Previous.NAV),0) NetChange,
ISNULL((Todays.NAV-Previous.NAV) / Todays.NAV,0) BAMLIndex
FROM
Fireball..NAV as Previous
JOIN
Fireball..NAV as Todays
ON Previous.portfolioID = Todays.PortfolioID
WHERE Previous.Date BETWEEN #StartDate AND #EndDate
AND Previous.PortfolioId = #PortfolioId
AND Todays.Date = #EndDate

SQL query date null check

I have the following stored procedure.
ALTER PROCEDURE [dbo].[spList_Report]
#id INT,
#startDate DATETIME = NULL,
#endDate DATETIME = NULL,
#includeStatus1 BIT,
#includeStatus2 BIT,
#includeStatus3 BIT,
#includeStatus4 BIT
AS
SET NOCOUNT ON
SELECT *
FROM
tblProducts as products
WHERE
product.intID = #id
AND product.dateMain >= #startDate
AND product.dateMain <= #endDate
If #startDate AND #endDate are both null then I want it to return the rows ignoring the date check in the where clause.
How?
This should do
AND product.dateMain >= ISNULL( #startDate, 0)
AND product.dateMain <= ISNULL( #endDate, product.dateMain + 1)
ISNULL yields the second value, if the first value is null.
Thus:
if #startDate is null, then dateMain must be bigger than 0 (1900-01-01)
if #endDate is null, then dateMain must be smaller than dateMain + 1 day
you can try something like this
ALTER PROCEDURE [dbo].[spList_Report]
#id INT,
#startDate DATETIME = NULL,
#endDate DATETIME = NULL,
#includeStatus1 BIT,
#includeStatus2 BIT,
#includeStatus3 BIT,
#includeStatus4 BIT
AS
SET NOCOUNT ON
SELECT *
FROM
tblProducts as products
WHERE
product.intID = #id
AND product.dateMain >= ISNULL( #startDate, product.dateMain )
AND product.dateMain <= ISNULL( #endDate, product.dateMain )
You can utilize an "or" in your Sql, but since this is a stored procedure:
If #startdate is null Or #enddate is null
begin
select without using a date range
end
Else
begin
select using date range
end
I would use Kris Krause's solution, but change the "IF" statement to use "AND". I think if you use the first two solutions the query engine may perform a table/index scan on the date fields. You want to keep your queries as concise as possible for best performance, so don’t run queries on unnecessary columns.
IF #startdate IS NULL AND #enddate IS NULL
BEGIN
SELECT * FROM tblProducts as products WHERE
product.intID = #id
END
ELSE
BEGIN
SELECT * FROM tblProducts as products WHERE
product.intID = #id
AND product.dateMain >= #startDate
AND product.dateMain <= #endDate
END