multi-select sql query with date range - sql

I have this query where I get totals of different stats from an employee roster table.
SELECT A.rempid AS EmpId,
E.flname,
A.rdo_total,
B.grave_total,
C.sundays,
D.holidays
FROM (SELECT rempid,
Count(rshiftid)AS RDO_Total
FROM rtmp1
WHERE rshiftid = 2
GROUP BY rempid
HAVING Count(rshiftid) > 0) A,
(SELECT rempid,
Count(rshiftid)AS Grave_Total
FROM rtmp1
WHERE rshiftid = 6
GROUP BY rempid
HAVING Count(rshiftid) > 0)B,
(SELECT rempid,
Count(rshiftid) AS Sundays
FROM rtmp1
WHERE Datepart(dw, rdate) = 1
AND rshiftid > 2
GROUP BY rempid
HAVING Count(rshiftid) > 0)C,
(SELECT rempid,
Count(rshiftid) AS Holidays
FROM rtmp1
WHERE rdate IN (SELECT pubhdt
FROM pubhol)
AND rshiftid > 2
GROUP BY rempid
HAVING Count(rshiftid) > 0)D,
(SELECT empid,
[fname] + ' ' + [sname] AS flName
FROM remp1)E
WHERE A.rempid = B.rempid
AND A.rempid = E.empid
AND A.rempid = C.rempid
AND A.rempid = D.rempid
ORDER BY A.rempid
I would like to add a date range into it, so that I can query the database within 2 dates. The rTmp1 table has a column called rDate. I was wondering what the best way to do this. I could add it to a stored procedure and add variable to each select query. Or is there a better way to run the query within a date range.

i think just add an additional where clause item similar to:
AND ( rDate > somedate AND rDate < someotherdate )

Adding the date range to each query is the most direct solution.
Making it a stored procedure is something that can always be done with a query, but has nothing to do with this specific case.
If the number of records resulting from narrowing down your table to the specified date range is substantially less than the entire table, it might be an option to insert these records into a temporary table or a table variable and run your existing query on that table/resultset.
Though I do not have any data to test, you might consider the following query as it is more easy to read and might perform better. But you have to check the results for yourself and maybe do some adjustments.
DECLARE #startDate date = '12/01/2012'
DECLARE #endDate date = DATEADD(MONTH, 1, #startDate)
SELECT
[e].[empid],
[e].[fname] + ' ' + [e].[sname] AS [flName],
SUM(CASE WHEN [t].[rshiftid] = 2 THEN 1 ELSE 0 END) AS [RDO_Total],
SUM(CASE WHEN [t].[rshiftid] = 6 THEN 1 ELSE 0 END) AS [Grave_Total],
SUM(CASE WHEN [t].[rshiftid] > 2 AND DATEPART(dw, [t].[rdate]) = 1 THEN 1 ELSE 0 END) AS [Sundays],
SUM(CASE WHEN [t].[rshiftid] > 2 AND [h].[pubhdt] IS NOT NULL THEN 1 ELSE 0 END) AS [Holidays]
FROM [remp1] [e]
INNER JOIN [rtmp1] [t] ON [e].[empid] = [t].[rempid]
LEFT JOIN [pubhol] [h] ON [t].[rdate] = [h].[pubhdt]
WHERE [t].[rdate] BETWEEN #startDate AND #endDate
GROUP BY
[e].[empid],
[e].[fname],
[e].[sname]
ORDER BY [empid] ASC

Related

Total Count of each

I have a problem with my SQL Server query.
My query must display the total number of each category. Not the total amount of all categories.
SELECT [CATEGORY],
(SELECT COUNT(*)
FROM [Group_New_DB].[dbo].[INCIDENTSM1]
WHERE ([OPEN_TIME] >= #StartDate and [OPEN_TIME] < #EndDate + 1) ) AS OpenedCount,
(SELECT COUNT(*)
FROM [Group_New_DB].[dbo].[INCIDENTSM1]
WHERE ([CLOSE_TIME] >= #StartDate and [CLOSE_TIME] < #EndDate + 1)) AS ClosedCount
FROM [Group_New_DB].[dbo].[INCIDENTSM1]
GROUP BY CATEGORY
ORDER BY CATEGORY
The report consists of a table with 3 columns: Category, Registered, Closed.
1 column is the category name.
2 column is how many categories have been registered.
3 column -> how many columns were closed.
But result
The result that turned out as a result does not look right.
I don't quite understand what is the difference between total number vs total amount as the question doesn't provide any context.
Although, if you are trying to get OpenedCount and ClosedCount as you have named the columns, I suggest you try below:
SELECT
CATEGORY,
SUM(CASE WHEN (OPEN_TIME >= #start_date AND OPEN_TIME < #end_date+1)
THEN 1
ELSE 0
END) AS OPENED_COUNT,
SUM(CASE WHEN (CLOSED_TIME >= #start_date AND CLOSED_TIME < #end_date+1)
THEN 1
ELSE 0
END) AS CLOSED_COUNT
FROM
[Group_New_DB].[dbo].[INCIDENTSM1]
GROUP BY
CATEGORY
ORDER BY
CATEGORY
IMO, This is also a better way as it doesn't include multiple sub-queries.
Correction: changed COUNT to SUM as suggested by TriV - Thanks!
Try this instead -
SELECT [CATEGORY],
COUNT(CASE WHEN [OPEN_TIME] >= #StartDate and [OPEN_TIME] < #EndDate + 1 THEN 1 ELSE NULL END) AS OpenedCount,
COUNT(CASE WHEN [CLOSE_TIME] >= #StartDate and [CLOSE_TIME] < #EndDate + 1 THEN 1 ELSE NULL END) AS ClosedCount
FROM [Group_New_DB].[dbo].[INCIDENTSM1] GROUP BY
CATEGORY ORDER BY CATEGORY

How to return count in 2 columns?

I have this query. It should return Count for both AWARDED (1) and NOT AWARDED(0) works from works table.
Select Count(w.WorkID)as Total, w.IsAwarded, org.OrganizationName
From Works w
Inner Join MC_MemberShip.Membership.Organization org
ON org.OrganizationID= w.Organization_ID
where Convert(varchar(11), w.OpeningDate) >= Convert(varchar(11), #FromDate)
and Convert(varchar(11), w.OpeningDate) < DATEADD(day, 1, Convert(varchar(11), #ToDate))
and w.IsActive=1 and
ISNULL(w.IsAwarded,0)= 0 and w.Organization_ID= case when #OrgID= -1 then w.Organization_ID else #OrgID end
group by org.OrganizationName, w.IsAwarded
Now this query returns Total count for NOT AWARDED i.e. 0 only but i want to return count for AWARDED too in same query.
Organization TotalAwardedWorks TotalNotAwardedWorks
Town 1 1 2
Town 2 44 33
Your query should look something like this:
select org.OrganizationName,
Count(*) as Total,
sum(case when w.IsAwarded = 0 or w.IsAwarded is null then 1 else 0 end) as TotalNotAward,
sum(case when w.IsAwarded = 1 then 0 else 1 end) as TotalAward
from Works w Inner Join
MC_MemberShip.Membership.Organization org
on org.OrganizationID = w.Organization_ID
where w.OpeningDate >= #FromDate and
w.OpeningDate < dateadd(day, 1, #ToDate) and
w.IsActive = 1 and
(w.Organization_ID = #OrgId or #OrgID= -1)
group by org.OrganizationName;
Notes:
Do not convert dates to strings to perform comparisons. That is just perverse.
Generally, the use of case in the where clause is discouraged. The logic is more clearly represented using or.
You can get what you want by using case to put conditions in the aggregation functions.

sql join and group by generated date range

I have Table1 and I need a query to populate Table2:
Problem here is with Date column. I want to know the process of location/partner combination per day. Main issue here is that I can't pick DateCreated and make it as default date since it doesn't necessarily cover whole date range, like in this example where it doesn't have 2015-01-07 and 2015-01-09. Same case with other dates.
So, my idea is to first select dates from some table which contains needed date range and then perform calculation for each day/location/partner combination from cte but in that case I can't figure out how to make a join for LocationId and PartnerId.
Columns:
Date - CreatedItems - number of created items where Table1.DateCreated = Table2.Date
DeliveredItems - number of delivered items where Table1.DateDateOut = Table2.Date
CycleTime - number of days delivered item was in the location (DateOut - DateIn + 1)
I started with something like this but it's very like that I completely missed the point with it:
with d as
(
select date from DimDate
where date between DATEADD(DAY, -365, getdate()) and getdate()
),
cr as -- created items
(
select
DateCreated,
LocationId,
PartnerId,
CreatedItems = count(*)
from Table1
where DateCreated is not null
group by DateCreated,
LocationId,
PartnerId
),
del as -- delivered items
(
select
DateOut,
LocationId,
ParnerId,
DeliveredItems = count(*),
CycleTime = DATEDIFF(Day, DateOut, DateIn)
from Table1
where DateOut is not null
and Datein is not null
group by DateOut,
LocationId,
PartnerId
)
select
d.Date
from d
LEFT OUTER JOIN cr on cr.DateCreated = d.Date -- MISSING JOIN PER LocationId and PartnerId
LEFT OUTER JOIN del on del.DateCompleted = d.Date -- MISSING JOIN PER LocationId and PartnerId
with range(days) as (
select 0 union all select 1 union all select 2 union all
select 3 union all select 4 union all select 5 union all
select 6 /* extend as necessary */
)
select dateadd(day, r.days, t.DateCreated) as "Date", locationId, PartnerId,
sum(
case
when dateadd(day, r.days, t.DateCreated) = t.DateCreated
then 1 else 0
end) as CreatedItems,
sum(
case
when dateadd(day, r.days, t.DateCreated) = t.Dateout
then 1 else 0
end) as DeliveredItems,
sum(
case
when dateadd(day, r.days, t.DateCreated) = t.Dateout
then datediff(days, t.DateIn, t.DateOut) + 1 else 0
end) as CycleTime
from
<yourtable> as t
inner join range as r
on r.days between 0 and datediff(day, t.DateCreated, t.DateOut)
group by dateadd(day, r.days, t.DateCreated), LocationId, PartnerId;
If you only want the end dates (rather than all the dates in between) this is probably a better approach:
with range(dt) as (
select distinct DateCreated from T union
select distinct DateOut from T
)
select r.dt as "Date", locationId, PartnerId,
sum(
case
when r.dt = t.DateCreated
then 1 else 0
end) as CreatedItems,
sum(
case
when r.dt = t.Dateout
then 1 else 0
end) as DeliveredItems,
sum(
case
when r.dt = t.Dateout
then datediff(days, t.DateIn, t.DateOut) + 1 else 0
end) as CycleTime
from
<yourtable> as t
inner join range as r
on r.dt in (t.DateCreated, t.DateOut)
group by r.dt, LocationId, PartnerId;
If to specify WHERE clause? Something Like that:
WHERE cr.LocationId = del.LocationId AND
cr.PartnerId = del.PartnerId

Inline Table Join Multiplying Results

The below query joins two views and one inline table to another inline table. When I run the query without table FI all of the SUM values return correctly, however, when I run the query with table FI all of the SUM values from vw_Interactions are multiplied and returned incorrect (SUM values from vw_LeadInteractions are not affected).
vw_Interactions is a transactional log and returns a 1 in each column where that measure is true (ex: a 1 is returned in I.[Call] where a phone call was logged), and vw_LeadInteractions is the same except it returns the Client's ID.
I did several hours of research and found that inline tables can cause issues when joining (the Cartesian product?), however I wasn't able to understand how those answers were relevant to this query.
Can someone explain why that when table FI is included in this query that it multiplies the SUM values of everything from vw_Interactions? And then how do I fix my query so this does not happen?
This query is for my employer's outbound call center to measure what's happening during each 'round' of calling.
/* Parameters */
DECLARE #StartDatetime AS Date
SET #StartDatetime = '06/01/13'
DECLARE #EndDatetime AS Date
SET #EndDatetime = '05/31/14'
/* Dataset */
SELECT R.[RoundsGoal]
,R.[RoundNumber]
,COUNT(DISTINCT R.[Client_Id]) AS 'Leads'
,ISNULL(SUM(I.[Call]), 0) AS 'Calls'
,ISNULL(COUNT(DISTINCT LI.[Call]), 0) AS 'CallLeads'
,ISNULL(SUM(FI.[FirstCall]), 0) AS 'FirstCalls'
,ISNULL(SUM(I.[DecisionMakerCall]), 0) AS 'DecisionMakerCalls'
,ISNULL(COUNT(DISTINCT LI.[DecisionMakerCall]), 0) AS 'DecisionMakerCallLeads'
,ISNULL(SUM(FI.[FirstDecisionMakerCall]), 0) AS 'FirstDecisionMakerCalls'
,ISNULL(SUM( I.[LeftMessageCall]), 0) AS 'LeftMessageCalls'
,ISNULL(COUNT(DISTINCT LI.[LeftMessageCall]), 0) AS 'LeftMessageLeads'
,ISNULL(SUM(FI.[FirstLeftMessageCall]), 0) AS 'FirstLeftMessageCalls'
,ISNULL(SUM(I.[NoAnswerCall]), 0) AS 'NoAnswerCalls'
,ISNULL(COUNT(DISTINCT LI.[NoAnswerCall]), 0) AS 'NoAnswerCallLeads'
,ISNULL(SUM(FI.[FirstNoAnswerCall]), 0) AS 'FirstNoAnswerCalls'
FROM (
SELECT RD.[Client_Id]
,ISNULL(UF1.[NumericCol], 0) AS 'RoundsGoal'
,COUNT(RD.[RoundDate]) OVER(PARTITION BY RD.[Client_Id] ORDER BY RD.[RoundDate] ASC) AS 'RoundNumber'
,RD.[RoundDate]
FROM [dbo].[vw_RoundDates] RD
LEFT JOIN [dbo].[AMGR_User_Fields] UF1 ON RD.[Client_Id] = UF1.[Client_Id] AND UF1.[Type_Id] = 140 --Rounds Goal TypeId
LEFT JOIN [dbo].[AMGR_User_Field_Defs] UFD1 ON UF1.[Type_Id] = UFD1.[Type_Id] AND UF1.[Code_Id] = UFD1.[Code_Id]
WHERE RD.[RoundDate] >= #StartDatetime AND RD.[RoundDate] <= #EndDatetime
) R
LEFT JOIN [dbo].[vw_Interactions] I ON R.[Client_Id] = I.[Client_Id] AND R.[RoundDate] = CAST(I.[Created] AS DATE)
LEFT JOIN [dbo].[vw_LeadInteractions] LI ON R.[Client_Id] = LI.[Client_Id] AND R.[RoundDate] = CAST(LI.[Created] AS DATE)
LEFT JOIN (
SELECT I.[Client_Id]
,CASE WHEN (CASE WHEN I.[Call] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[Call] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstCall'
,CASE WHEN (CASE WHEN I.[DecisionMakerCall] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[DecisionMakerCall] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstDecisionMakerCall'
,CASE WHEN (CASE WHEN I.[LeftMessageCall] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[LeftMessageCall] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstLeftMessageCall'
,CASE WHEN (CASE WHEN I.[NoAnswerCall] = 1 THEN ROW_NUMBER() OVER(PARTITION BY I.[Client_Id], I.[NoAnswerCall] ORDER BY I.[Created] ASC) ELSE NULL END) = 1 THEN 1 ELSE NULL END AS 'FirstNoAnswerCall'
,[Created]
FROM [dbo].[vw_Interactions] I
) FI ON R.[Client_Id] = FI.[Client_Id] AND R.[RoundDate] = CAST(FI.[Created] AS DATE)
GROUP BY R.[RoundsGoal]
,R.[RoundNumber]
ORDER BY R.[RoundsGoal] ASC
,R.[RoundNumber] ASC
Here is the correct results set without table FI. Notice the Calls on row 23 equals 135,110.
Here is the incorrect results, that include table FI. Notice the Calls on row 23 are multiplied to 1,561,038.

Conditional updates on sql query

In my code I have written an update query according to the date. That means, I have created an application for payroll, in that monthly they want to add month leave as two. If it is a new joinee that will separate two. This is the process I have done through my code. Now they want to change the model, that is, if the new joinee date of join has been greater than 15 days it should add one day leave. Please help me to do this. And this is my code befor I used:
UPDATE tbl_emploeedetails
SET elbal = elbal - 2
WHERE employeestatus = 'L'
AND ( Month(doj) = Month(Getdate()) - 1
AND Year(doj) = Year(Getdate())
AND Day(doj) > 25 )
OR ( Month(doj) = Month(Getdate())
AND Year(doj) = Year(Getdate()) )
and this is month leave add query :
update tbl_emploeedetails
set elbal = elbal + 2 where employeestatus = 'L'
You can use something like this
UPDATE YourTable
SET UpdateColumn =
(CASE
WHEN <Condition1> THEN <Expression1>
WHEN <Condition2> THEN <Expression2>
ELSE <Expression3>
END)
Example:
UPDATE YourTable
SET UpdateColumn =
(CASE
WHEN A>B THEN D * 2
WHEN A>C THEN D * 3
ELSE D * 4
END)