SQL Server : group by calculated column - sql

I have a table with columns like this:
I want to know the average compliance rate for every question for that period.
I am passing start dates and end dates as parameters to query.
So if I want for two periods I am passing #StartDate (e.g. 1/6/17) and #EndDate (e.g. 30/6/17) for first period and #StartDate2 (1/10/17) and #EndDate2 (31/10/17) for second period.
My SQL query is:
;WITH tmpTab AS
(
SELECT
question,
SUM((CASE WHEN AnswerValue = 1 THEN 1 ELSE 0 END)) Met,
SUM((CASE WHEN AnswerValue = 3 THEN 1 ELSE 0 END)) NA,
SUM((CASE WHEN (ISNULL(AnswerValue,3) <> 3) THEN 1 ELSE 0 END)) MetNotMet,
DATENAME(DAY, #StartDate) + ' ' + DATENAME(MONTH, #StartDate) + ' ' +
DATENAME(YEAR, #StartDate) + ' To ' + DATENAME(DAY,#EndDate) + ' ' +
DATENAME(MONTH, #EndDate) + ' ' + DATENAME(YEAR, #EndDate) AS RepMonthAndYear
FROM
tableA
WHERE
startdate >= #StartDate AND endate <= #EndDate
GROUP BY
Question
UNION ALL
SELECT
question,
SUM((CASE WHEN AnswerValue = 1 THEN 1 ELSE 0 END)) Met,
SUM((CASE WHEN AnswerValue = 3 THEN 1 ELSE 0 END)) NA,
SUM((CASE WHEN (ISNULL(AnswerValue,3) <> 3) THEN 1 ELSE 0 END)) MetNotMet,
DATENAME(DAY,#StartDate2)+' '+DATENAME(MONTH,#StartDate2)+' '+DATENAME(YEAR,#StartDate2)+ ' To ' + DATENAME(DAY,#EndDate2)+' '+DATENAME(MONTH,#EndDate2)+' '+DATENAME(YEAR,#EndDate2) AS RepMonthAndYear
FROM
tableA
WHERE
startdate >= #StartDate2 AND endate <= #EndDate2
GROUP BY
Question
)
SELECT
Question, Met, NA, MetNotMet,
CASE WHEN (Met) = 0 THEN 0 ELSE ROUND(((CONVERT(FLOAT,(Met))/(MetNotMet))* 100),4) END as CompRate
FROM
tmpTab
In this SQL query, I need to group by RepMonthAndYear column also which I can not do as it is a calculated column. I get an error "invalid column".
And if I use this GROUP BY clause:
(DATENAME(DAY,#StartDate2)+' '+DATENAME(MONTH,#StartDate2)+' '+DATENAME(YEAR,#StartDate2)+ ' To ' + DATENAME(DAY,#EndDate2)+' '+DATENAME(MONTH,#EndDate2)+' '+DATENAME(YEAR,#EndDate2) )
I get this error:
Each GROUP BY expression must contain at least one column that is not an outer reference.
How can I solve this problem?
Is there any other way to know average rate group by particular periods?

Given the following Test Data and your SQL I get what you discibe.
CREATE TABLE tableA (
question VARCHAR(50),
AnswerValue INT,
startdate DATE,
endate DATE
);
INSERT INTO tableA VALUES ('Question A', 1, '2017-06-25', '2017-06-26');
INSERT INTO tableA VALUES ('Question A', 1, '2017-06-27', '2017-06-27');
INSERT INTO tableA VALUES ('Question A', 2, '2017-06-27', '2017-06-27');
INSERT INTO tableA VALUES ('Question B', 1, '2017-06-11', '2017-06-12');
INSERT INTO tableA VALUES ('Question B', 2, '2017-06-13', '2017-06-13');
INSERT INTO tableA VALUES ('Question B', 1, '2017-06-13', '2017-06-13');
INSERT INTO tableA VALUES ('Question C', 1, '2017-06-20', '2017-06-20');
INSERT INTO tableA VALUES ('Question C', 1, '2017-06-23', '2017-06-23');
INSERT INTO tableA VALUES ('Question D', 2, '2017-06-01', '2017-06-01');
INSERT INTO tableA VALUES ('Question E', 1, '2017-10-11', '2017-10-11');
INSERT INTO tableA VALUES ('Question E', 1, '2017-10-15', '2017-10-15');
INSERT INTO tableA VALUES ('Question F', 1, '2017-10-20', '2017-10-20');
INSERT INTO tableA VALUES ('Question F', 2, '2017-10-20', '2017-10-20');
INSERT INTO tableA VALUES ('Question F', 2, '2017-10-20', '2017-10-20');
INSERT INTO tableA VALUES ('Question G', 1, '2017-10-26', '2017-10-26');
INSERT INTO tableA VALUES ('Question H', 1, '2017-10-26', '2017-10-26');
INSERT INTO tableA VALUES ('Question H', 2, '2017-10-26', '2017-10-26');
INSERT INTO tableA VALUES ('Question I', 1, '2017-10-26', '2017-10-26');
Here the outcome of your Query:
Question A 2 0 3 66,6667
Question B 2 0 3 66,6667
Question C 2 0 2 100
Question D 0 0 1 0
Question E 2 0 2 100
Question F 1 0 3 33,3333
Question G 1 0 1 100
Question H 1 0 2 50
Question I 1 0 1 100
I could simplify your SQL and have removed some code duplicates, maybe that was your intended question.
DECLARE #StartDate DATE = '2017-06-01';
DECLARE #EndDate DATE = '2017-06-30';
DECLARE #StartDate2 DATE = '2017-10-01';
DECLARE #EndDate2 DATE = '2017-10-30';
WITH
periods AS (
SELECT #StartDate as startdate,
#EndDate as enddate
UNION
SELECT #StartDate2 as startdate,
#EndDate2 as enddate
)
SELECT t.Question, t.Met, t.NA, t.MetNotMet,
CASE WHEN (t.Met) = 0 THEN 0 ELSE ROUND(((CONVERT(FLOAT,(t.Met))/(t.MetNotMet))* 100),4) END as CompRate
FROM (SELECT question,
SUM((CASE WHEN AnswerValue = 1 THEN 1 ELSE 0 END)) Met,
SUM((CASE WHEN AnswerValue = 3 THEN 1 ELSE 0 END)) NA,
SUM((CASE WHEN (ISNULL(AnswerValue,3) <> 3) THEN 1 ELSE 0 END)) MetNotMet
FROM tableA AS a
JOIN ( SELECT p.startdate,
p.enddate,
DATENAME(DAY, p.startdate) + ' ' + DATENAME(MONTH, p.startdate) + ' ' +
DATENAME(YEAR, p.startdate) + ' To ' + DATENAME(DAY, p.enddate) + ' ' +
DATENAME(MONTH, p.enddate) + ' ' + DATENAME(YEAR, p.enddate) AS RepMonthAndYear
FROM periods p ) AS p ON a.startdate >= p.startdate AND a.endate <= p.enddate
GROUP BY a.Question, p.RepMonthAndYear) AS t

Related

How can I manipulate a string a T-SQL?

business_id
open_day
open_time
close_day
close_time
1
FRIDAY
08:00
FRIDAY
12:00
1
FRIDAY
13:00
FRIDAY
17:00
1
MONDAY
08:00
MONDAY
17:00
2
SATURDAY
08:00
SATURDAY
16:00
2
SUNDAY
08:00
SUNDAY
16:00
3
MONDAY
08:00
MONDAY
16:00
I have a task to create and format opening hours for a business, I'm required to group these by days in a single string. However, it is repeating the day. Would it be possible to search for a particular value if it occurs twice within a string? I have gotten this far:
create table open_times (business_id int, open_day varchar(10), open_time varchar(10), close_day varchar(10), close_time varchar(10) )
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (1, 'FRIDAY', '08:00', 'FRIDAY', '12:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (1, 'FRIDAY', '13:00', 'FRIDAY', '17:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (1, 'MONDAY', '08:00', 'MONDAY', '17:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (2, 'SATURDAY', '08:00', 'SATURDAY', '16:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (2, 'SUNDAY', '08:00', 'SUNDAY', '16:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (3, 'MONDAY', '08:00', 'MONDAY', '16:00')
drop table open_times
I appreciate your help.
select
business_id
,left(name_values, LEN(name_values)-1) as opening_hours
from
(
select
results.business_id
,STUFF((
select
( case when open_day = 'FRIDAY' then 'Fr' when open_day = 'MONDAY' then 'Mo' when open_day = 'TUESDAY' then 'Tu' when open_day = 'WEDNESDAY' then 'We' When open_day = 'THURSDAY' then 'Th' when open_day = 'SATURDAY' then 'Sa' else 'Su' end )
+ ' ' + open_time + '-' + close_time + '; '
from open_times
where business_id = results.business_id
for xml path(''),type).value('(./text())[1]','VARCHAR(MAX)'),1,0, '') as name_values
from open_times results
group by business_id
) innerquery
Current Output for Business 1: 'Fr 08:00-12:00; Fr 13:00-17:00; Mo 08:00-17:00'
Desired Output For Business 1: 'Fr 08:00-12:00, 13:00-17:00; Mo 08:00-17:00'
You can use STRING_AGG here. You just need to do two levels of grouping, once per day, then again for the whole business_id
SELECT
ot.business_id,
Times = STRING_AGG(CONCAT(
UPPER(LEFT(ot.open_day, 1)),
LOWER(SUBSTRING(ot.open_day, 2, 1)),
' ',
ot.Times)
, '; ')
FROM (
SELECT
ot.business_id,
ot.open_day,
Times = STRING_AGG(CONCAT(
ot.open_time,
'-',
ot.close_time),
', ')
FROM open_times ot
GROUP BY ot.business_id, ot.open_day
) ot
GROUP BY ot.business_id;
db<>fiddle
You can do this with one level of aggregation by incorporating window functions into your logic:
select ot.business_id,
stuff((select (case when seqnum = 1 then '; ' else ', ' end) +
(case when seqnum = 1 and ot2.open_day = 'FRIDAY' then 'Fr '
when seqnum = 1 and ot2.open_day = 'MONDAY' then 'Mo '
when seqnum = 1 and ot2.open_day = 'TUESDAY' then 'Tu '
when seqnum = 1 and ot2.open_day = 'WEDNESDAY' then 'We '
when seqnum = 1 and ot2.open_day = 'THURSDAY' then 'Th '
when seqnum = 1 and ot2.open_day = 'SATURDAY' then 'Sa '
when seqnum = 1 then 'Su '
else ''
end ) +
ot2.open_time + '-' + ot2.close_time
from (select ot2.*,
row_number() over (partition by ot2.open_day order by ot2.open_time) as seqnum
from open_times ot2
where ot2.business_id = ot.business_id
) ot2
order by ot2.open_day, ot2.open_time
for xml path(''),type
).value('(./text())[1]', 'VARCHAR(MAX)'), 1, 2, ''
) as name_values
from open_times ot
group by ot.business_id;
Here is a db<>fiddle.
Your version of the query is actually incorrect, because you do not have an order by in the XML subquery. The results can be in any order.
In addition, you don't just want to remove the duplicate names, but you also want to change the delimiter from ; to ,.
The idea in the above query is that the times are enumerated on each day. The delimiter is ; for the first time and , for the subsequent ones. The abbreviation is used only for the first one. I also added qualifications to all the column references, a highly recommended practice.
Note that you can simplify the case logic to:
left(ot2.open_day, 1) + lower(substring(ot2.open_day, 2, 1))
For older versions use FOR XML PATH aggregation trick. Assuming no more then 2 open intervals a day
with t as (
select business_id, left(open_day,2) + ' ' + min(open_time + '-' + close_time) +
case when min(open_time) = max(open_time) then ''
else ', ' + max(open_time + '-' + close_time) end ots
from open_times
group by business_id, open_day
)
select business_id, stuff(
(select '; ' + ots
from t t2
where t2.business_id = t1.business_id
order by left(ots,2)
for xml path(''))
, 1, 2, '') opening_hours
from t t1
group by business_id

How to show monthly data even if there are no results yet SQL Server 2008

So I wrote a script that would show monthly premium. Say if you want to view the total premium up to November, you can pass through a parameter in in SSRS to pick 1/1/2016 - 11/30/2016. This would only show the data up until november, hoever, I would like to show it up until december even if there are no records there. How do I go about doing this in SQL? Here is my script so far:
SELECT lc.[Date]
,lc.Carrier
,lc.[Direct Ceded Written Premium]
,cast(cast(year(lc.[date]) as varchar(4)) + '-' + cast(month(lc.[date]) as varchar(2)) + '-01' as date) as [begofmonth]
from
(
SELECT
CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN cast(pd.TransactionDate as DATE)
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN cast(pd.EffectiveDate as DATE)
ELSE cast(pd.TransactionEffDate as date)
END AS [Date]
,CASE WHEN LEFT(PD.POLICYNUM, 3) = 'ORV'
THEN 'Palomar Value Select OR'
WHEN LEFT(PD.POLICYNUM, 3) = 'VSE'
THEN 'Palomar Value Select CA'
WHEN LEFT(PD.POLICYNUM, 3) = 'WAV'
THEN 'Palomar Value Select WA'
ELSE 'Palomar' END AS [Carrier]
,ISNULL(SUM(pd.WrittenPremium), 0) AS [Direct Ceded Written Premium]
FROM premdetail pd
JOIN transactionpremium tp ON pd.systemid = tp.systemid
AND pd.transactionpremiumid = tp.id
JOIN transactionhistory th ON tp.systemid = th.systemid
AND tp.cmmcontainer = th.cmmcontainer
AND tp.parentid = th.id
JOIN basicpolicy bp ON th.systemid = bp.systemid
AND th.cmmcontainer = bp.cmmcontainer
AND th.parentid = bp.id
WHERE
(CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN pd.TransactionDate
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN pd.EffectiveDate
ELSE pd.TransactionEffDate
END) > = CAST(#StartDate AS DATE)
AND (CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN pd.TransactionDate
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN pd.EffectiveDate
ELSE pd.TransactionEffDate
END) < CAST(#EndDate + 1 AS DATE)
AND (bp.carriercd = #ResEQCarrierCd
OR #ResEQCarrierCd = 'All')
GROUP BY
CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN cast(pd.TransactionDate as DATE)
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN cast(pd.EffectiveDate as DATE)
ELSE cast(pd.TransactionEffDate as date)
END
,CONVERT(VARCHAR, pd.EffectiveDate, 101)
,CONVERT(VARCHAR, pd.ExpirationDate, 101)
,CASE
WHEN LEFT(PD.POLICYNUM, 3) = 'ORV'
THEN 'Palomar Value Select OR'
WHEN LEFT(PD.POLICYNUM, 3) = 'VSE'
THEN 'Palomar Value Select CA'
WHEN LEFT(PD.POLICYNUM, 3) = 'WAV'
THEN 'Palomar Value Select WA'
ELSE 'Palomar'
END
,CASE
WHEN pd.TransactionCode = 'EN' THEN CONVERT(VARCHAR, th.TransactionEffectiveDt, 101)
ELSE ''
END
,CONVERT(VARCHAR, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(m, 0, th.transactiondt) + 1, 0)), 101)
,CASE
WHEN pd.TransactionEffDate < CAST(CONVERT(VARCHAR, pd.TransactionDate, 101) AS SMALLDATETIME) THEN CONVERT(VARCHAR, pd.TransactionDate, 101)
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN CONVERT(VARCHAR, pd.EffectiveDate, 101)
ELSE CONVERT(VARCHAR, pd.TransactionEffDate, 101)
END
) lc
ORDER BY lc.[Date], lc.[Carrier], lc.[Direct Ceded Written Premium]
With the parameter that I have, it would only show up until November. However, I would like it to show the whole year, up to December at in this case, even if there are no data there since I didn't pick the enddate variable to be december. I attached an example screenshot of what it should look like when exported to excel.
Just to give you an idea:
declare #tbl TABLE(ID INT IDENTITY,SomeValue VARCHAR(100),SomeDate DATE);
INSERT INTO #tbl VALUES('Some date in March',{d'2016-03-05'}),('Some date in June',{d'2016-06-30'});
WITH AllMonths AS
(
SELECT 1 AS MonthIndex
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
UNION ALL SELECT 10
UNION ALL SELECT 11
UNION ALL SELECT 12
)
SELECT MonthIndex
,t.*
FROM AllMonths
LEFT JOIN #tbl AS t ON MONTH(t.SomeDate)=MonthIndex
The result
1 NULL NULL NULL
2 NULL NULL NULL
3 1 Some date in March 2016-03-05
4 NULL NULL NULL
5 NULL NULL NULL
6 2 Some date in June 2016-06-30
7 NULL NULL NULL
8 NULL NULL NULL
9 NULL NULL NULL
10 NULL NULL NULL
11 NULL NULL NULL
12 NULL NULL NULL
There are many ways to create a tally table
CTE with ROW_NUMBER()
A list like in my example
A physical table
It is a good idea to maintain a numbers/DATE table!
In a previous answer I showed one way to create such a table.

SQL insert statement with "NOT EXIST" based on second column

I have this functioning insert statement, but I need to insert into SL_PROD only if the NUMBER does not already exist for DEPTCODE '725'... any ideas?
INSERT INTO SL_PROD (NUMBER, DEPTCODE, DISP_SEQ, LU_BY, LU_ON)
SELECT ST_EXTRA.NUMBER, '725', '1', 'IN', getdate()
FROM ST_EXTRA
INNER JOIN STOCK ON STOCK.NUMBER = ST_EXTRA.NUMBER
WHERE UNITS > 0 AND datename(m,colEMAILDATE) = datename(m, DATEADD(m, -1, getdate()))
Use not exists.
INSERT INTO SL_PROD (NUMBER, DEPTCODE, DISP_SEQ, LU_BY, LU_ON)
SELECT ST_EXTRA.NUMBER, '725', '1', 'IN', getdate()
FROM ST_EXTRA
INNER JOIN STOCK ON STOCK.NUMBER = ST_EXTRA.NUMBER
WHERE UNITS > 0
AND datename(m,colEMAILDATE) = datename(m, DATEADD(m, -1, getdate()))
AND NOT EXISTS (select 1 from sl_prod
where number = st_extra.number
and deptcode = '725')

Select count Columns group by No

Emp_No Emp_Shift Emp_Date
500 AL 1/5/2015
600 S 2/5/2015
600 H 3/5/2015
500 S 4/5/2015
500 AL 5/5/2015
600 AL 6/5/2015
I need help on this issue , HOW TO RETURN count in 3 Columns >>
EX:
Emp_No Count Al Count S Count H
500 2 1 0
600 1 1 1
this will work. you have to provide separate case statement to each condition
SQLFIDDLE for the same SQLFIDDLE
SELECT EMP_NO,
sum(CASE WHEN Emp_Shift = 'AL' THEN 1 ELSE 0 END) AS COUNT_AL,
sum(CASE WHEN Emp_Shift = 'S' THEN 1 ELSE 0 END) AS COUNT_S,
sum(CASE WHEN Emp_Shift = 'H' THEN 1 ELSE 0 END) AS COUNT_H
FROM YOUR_TABLE
GROUP BY EMP_NO;
You can try this:-
SELECT EMP_NO, COUNT(CASE
WHEN Emp_Shift = 'AL' THEN 1 ELSE 0 END AS COUNT_AL
WHEN Emp_Shift = 'S' THEN 1 ELSE 0 END AS COUNT_S
WHEN Emp_Shift = 'H' THEN 1 ELSE 0 END AS COUNT_H)
FROM YOUR_TABLE
GROUP BY EMP_NO;
Using Pivot :
declare #YOUR_TABLE TABLE
([Emp_No] int, [Emp_Shift] varchar(2), [Emp_Date] datetime)
;
INSERT INTO #YOUR_TABLE
([Emp_No], [Emp_Shift], [Emp_Date])
VALUES
(500, 'AL', '2015-01-05 00:00:00'),
(600, 'S', '2015-02-05 00:00:00'),
(600, 'H', '2015-03-05 00:00:00'),
(500, 'S', '2015-04-05 00:00:00'),
(500, 'AL', '2015-05-05 00:00:00'),
(600, 'AL', '2015-06-05 00:00:00')
;
select Emp_No,[AL] AS [Count Al],[S] As [Count S],[H] AS [Count H] from (
select Emp_No,[Emp_Shift],[Emp_Date] from #YOUR_TABLE)T
PIVOT(COUNT(Emp_Date) FOR Emp_Shift IN ([AL],[S],[H]))P
Using Pivot in Dynamic QUery :
if object_id('tempdb..#t') is not null
drop table #t
CREATE TABLE #t
([Emp_No] int, [Emp_Shift] varchar(2), [Emp_Date] datetime)
;
INSERT INTO #t
([Emp_No], [Emp_Shift], [Emp_Date])
VALUES
(500, 'AL', '2015-01-05 00:00:00'),
(600, 'S', '2015-02-05 00:00:00'),
(600, 'H', '2015-03-05 00:00:00'),
(500, 'S', '2015-04-05 00:00:00'),
(500, 'AL', '2015-05-05 00:00:00'),
(600, 'AL', '2015-06-05 00:00:00')
;
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' + tbl.Emp_Shift + ']'
FROM (
SELECT DISTINCT [Emp_Shift]
FROM #t
) AS tbl
SELECT #statement = ' select Emp_No,[AL] AS [Count Al],[S] As [Count S],[H] AS [Count H] from (
select Emp_No,[Emp_Shift],[Emp_Date] from #t)T
PIVOT(COUNT(Emp_Date) FOR Emp_Shift IN (' + #columns + ')) as pvt'
EXEC sp_executesql #statement = #statement

SQL cross tab pivot query

I have a table as below.
CaseID StatusID StageID CaseRegisterTime City
1 1 5 datetime XYZ
2 1 5 datetime ABC
Now I want its Citywise count and only for only specific dates, and also in condition for statusid = 1 and stageid = 5.
Cities CurrentDate-1 CurrentDate-2 January2012-CurrentDate-3
XYZ 5 51 5008
JUS 0 0 125
ABC 1 0 48
I want my header to group cases for CaseRegisterTime as shown above.
Please help.
Use case when to convert your dates of interest to 'CurrentDate-1' and 'CurrentDate-2', and then pivot the results, using this strings as the new columns.
Alternatively, you can do something like this:
select City, sum(Date1) as Date1, sum(Date2) as Date2
from(
select City,
case when CaseRegisterTime='2012-01-01' then 1 else 0 end as Date1,
case when CaseRegisterTime='2012-15-01' then 1 else 0 end as Date2
from sample
) as T
group by City
you'd also have to filter out the registers which doesn't have the desired date.
Here's one of many ways to do it in SQL Server 2008 (using the Date datatype):
select distinct a.City as Cities
, (select count(*)
from MyTable
where CaseRegisterTime >= cast(getdate() - 1 as date)
and CaseRegisterTime < cast(getdate() - 0 as date)
and StatusID = a.StatusID
and StageID = a.StageID
and City = a.City
) as [CurrentDate-1]
, (select count(*)
from MyTable
where CaseRegisterTime >= cast(getdate() - 2 as date)
and CaseRegisterTime < cast(getdate() - 1 as date)
and StatusID = a.StatusID
and StageID = a.StageID
and City = a.City
) as [CurrentDate-2]
, (select count(*)
from MyTable
where CaseRegisterTime >= cast('20120101' as date)
and CaseRegisterTime < cast(getdate() - 2 as date)
and StatusID = a.StatusID
and StageID = a.StageID
and City = a.City
) as [January2012-CurrentDate-3]
from MyTable a
where a.StatusID = 1
and a.StageID = 5
Update
The case and sum method #JotaBe uses is about twice as fast on my box (with many less scans and reads), so here's what that could look like:
select a.City as Cities
, sum(a.[CurrentDate-1]) as [CurrentDate-1]
, sum(a.[CurrentDate-2]) as [CurrentDate-2]
, sum(a.[January2012-CurrentDate-3]) as [January2012-CurrentDate-3]
from (
select City
, case when CaseRegisterTime >= cast(getdate() - 1 as date)
and CaseRegisterTime < cast(getdate() - 0 as date)
then 1 else 0 end [CurrentDate-1]
, case when CaseRegisterTime >= cast(getdate() - 2 as date)
and CaseRegisterTime < cast(getdate() - 1 as date)
then 1 else 0 end [CurrentDate-2]
, case when CaseRegisterTime >= cast('20120101' as date)
and CaseRegisterTime < cast(getdate() - 2 as date)
then 1 else 0 end [January2012-CurrentDate-3]
from MyTable
where StatusID = 1
and StageID = 5
) as a
group by a.City
Something like this will do:
begin tran;
go
create table #t1(
ID int identity,
City varchar,
RegisterDate datetime
);
declare #firstDate datetime, #secondDate datetime;
set #firstDate = '2012-1-1';
set #secondDate = '2012-1-2';
insert into #t1 values
('A', #firstDate),
('A', #firstDate),
('B', #firstDate),
('B', #firstDate),
('B', #firstDate),
('A', #secondDate),
('A', #secondDate),
('A', #secondDate),
('B', #secondDate),
('B', #secondDate);
select * from #t1;
select pvt.*
from(
select ID, City, RegisterDate
from #t1
) a
pivot(
count(a.ID)
for a.RegisterDate in ([2012-1-1], [2012-1-2])
) as pvt;
drop table #t1;
go
rollback tran;