Column Invalid in the Selected List - sql

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

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.

count the weekend and holiday dates and sub struct it from 2 dates if it is between of it sql

I have 3 tables with columns shown below,
Holidays : HolidayId, HolidayName, HolidayDate, Comment
Entitlements:
EntitlementId, EmployeeId, LeaveTypeId, LeavePeriodId, FromDate
, UptoDate, Entitlementdays
Weekend: WeekeindId, Weekends
TODO:
create a store procedure for insertion
Before insertion it should check and count the dates in holiday and weekend table
if it is between the date which is in the startdate and enddate of entitlement table should be subtract.
in sql
Try this one as you already have weekend table and holiday table
CREATE PROCEDURE
usp_LeaveDays (#employeeid int)
as
BEGIN
DECLARE #fromdate DATE
SET #fromdate =
SELECT convert( varchar(10),fromdate,120) fromdate
FROM Entitlement
WHERE employeeid = #employeeid
DECLARE #enddate DATE
SET #enddate =
SELECT convert ( varchar(10),enddate,120) enddate
FROM entitlement
WHERE employeeid = #employeeid
DECLARE #weekendcount INT
SET #weekendcount =
SELECT Count(*)
FROM Weekend
WHERE weekends BETWEEN #fromdate AND #enddate;
DECLARE #holidayCount INT
SET #holidaycount =
SELECT Count(*)
FROM holidays
WHERE holidaydate BETWEEN #fromdate AND #enddate
DECLARE #Totaldays INT
SET #Totaldays =
SELECT DATEDIFF(day, #fromdate, #enddate)
DECLARE #Actualdays INT
SET #Actualdays = #Totaldays - (#weekendcount + isnull(#holidayCount, 0))
DECLARE #recordCount INT
SELECT #recordCount = #Actualdays
IF (#recordCount > 0)
begin
insert into -- Enter your script here
END

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

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

T-SQL - Using CASE with Parameters in WHERE clause

I'm running a report on a Sales table:
SaleId INT | SalesUserID INT | SiteID INT | BrandId INT| SaleDate DATETIME
I'm having a nightmare trying to do something like this with a set of Nullable parameters #SalesUserID, #SiteId, #BrandID and two DateTime params.
Additional Point: Only ONE of the filter parameters will ever be passed as a Non-Null value.
SELECT * from Sales
WHERE
SaleDate BETWEEN #StartDate AND #EndDate
AND
SalesUserID IN
(
Select SalesUserID FROM Sales
WHERE
SaleDate BETWEEN #StartDate AND #EndDate
AND
CASE
WHEN #SalesUserId IS NOT NULL THEN SalesUserId = #SalesUserID
WHEN #SiteId Is Not Null THEN SiteId = #SiteId
ELSE BrandId = #BrandID
END
)
My use of CASE here smells bad but I'm not sure how to correct it. Can you please assist?
Thanks.
5arx
I don't think you want a CASE statement at all, but a compound conditional... Give this a shot and let me know:
select *
from Sales
where SaleDate between #StartDate and #EndDate
and
(
(#SalesUserId is not null and SalesUserId = #SalesUserID)
or (#SiteId is not null and SiteId = #SiteId)
or (BrandId = #BrandID)
)
If I understood you correctly, you want the three conditions either be NULL or checked for:
WHERE
/* ... */
AND SalesUserId = ISNULL(#SalesUserId, SalesUserId)
AND SiteId = ISNULL(#SiteId, SiteId)
AND BrandId = ISNULL(#BrandID, BrandID)
Be aware that this forces a table scan which might not be in your best interest.
This should work and use any index if you want to use CASE:
SELECT *
from Sales
WHERE SaleDate BETWEEN #StartDate AND #EndDate
AND SalesUserID = CASE WHEN #SalesUserID IS NULL THEN
SalesUserID ELSE #SalesUserID END
COALESCE() returns the 1st non NULL argument so you could;
...
WHERE SaleDate BETWEEN #StartDate AND #EndDate
AND SalesUserId = COALESCE(#SalesUserId, SalesUserId)
AND SiteId = COALESCE(#SiteId, SiteId)
AND BrandID = COALESCE(#BrandID, BrandId)
I would use a dynamic generated code in such a circumstance:
declare #SalesUserId int,#SiteId int,#StartDate datetime, #EndDate datetime,#BrandID int
declare #sql nvarchar(max)
set #sql = N'
SELECT * from Sales
WHERE
SaleDate BETWEEN #StartDate AND #EndDate
AND
SalesUserID IN
(
Select SalesUserID FROM Sales
WHERE
SaleDate BETWEEN #StartDate AND #EndDate AND
' +
CASE
WHEN #SalesUserId IS NOT NULL THEN 'SalesUserId = #SalesUserID'
WHEN #SiteId Is Not Null THEN 'SiteId = #SiteId'
ELSE 'BrandId = #BrandID'
END
+')'
print #sql
exec sp_executesql #sql
, N'#SalesUserId int,
#SiteId int,
#StartDate datetime,
#EndDate datetime,
#BrandID int'
,#SalesUserId
,#SiteId
,#StartDate
,#EndDate
,#BrandID
This is generally a job for dynamic SQl if you want performance.
http://www.sommarskog.se/dynamic_sql.html
Try this:
SELECT *
from Sales
WHERE SaleDate BETWEEN #StartDate AND #EndDate
AND SalesUserID = CASE WHEN #SalesUserID IS NULL THEN
SalesUserID ELSE #SalesUserID END