Remove subquery from JOIN? - sql

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

Related

Skip a WHERE condition if a #variable is empty

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.

How to assign Column Results to Parameters of a Query

I have a table "Values" The data looks like this:
ID Label Value
1 StartDate 1/1/17
2 EndDate 1/15/17
3 Dept 6
What I'd like to do is load the values of the "Label" column to the corresponding Parameters in my Query:
Declare
#startdate Datetime,
#enddate Datetime,
#DepartmentID int
Select *
From Customers
Where created between #startdate and #enddate and #DepartmentID
How can I assign #Startdate to the 'Startdate' 'value' in the value table? Additionally, Since i'm using different datatypes in my query, than what they are stored in the Values table (Values are 'nvarchar' in values table) Will I run into potential problems?
Declare
#startdate Datetime,
#enddate Datetime,
#DepartmentID int
set #startdate = (Select convert(datetime,[Value]) from dbo.Values where Label='StartDate')
set #enddate = (Select convert(datetime,[Value]) from dbo.Values where Label='EndDate')
set #DepartmentID =(Select convert(int,[Value]) from dbo.Values where Label='Dept')
Select *
From Customers
Where created between #startdate and #enddate and DepartmentId = #DepartmentID
You could try to do something like this:
SELECT
*
FROM
CUSTOMERS
WHERE
CREATED BETWEEN
(SELECT TOP 1 [Value] FROM Values WHERE Label = 'StartDate') --perform casts here if necessary
AND
(SELECT TOP 1 [Value] FROM Values WHERE Label = 'EndDate') --perform casts here if necessary

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

get last date in tsql

i show you my logic is getting error only when month is December
declare #startDate datetime
declare #endDate datetime
set #startDate = convert(varchar(2),#month)+'/1/'+ convert(varchar(4),#year)
set #endDate = dateadd(DD,-1,(convert(varchar(2),#month+1)+'/1/'+convert(varchar(4),#year)))
while(#startDate < #endDate+1)
begin
insert into #tempday
select #startDate
set #startDate = dateadd(day, 1, #startDate )
end
please help
Once you have #startdate, use:
set #enddate = dateadd(day,-1,dateadd(month,1,#startdate))
And I don't think you mean plsql...
There are other things you could think about too, such as not using a while-loop. Why not query a table that has plenty of rows (such as sys.all_columns) and use:
insert #tempday
select top (datediff(day,#startdate,#enddate)+1)
dateadd(day,row_number() over (order by (select 1))-1,#startdate)
from sys.all_columns;
In case of December #month+1 will get you 13 which is not a valid month number

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