ADJUST/EDIT SQL QUERY ASSISTANCE - sql

I have the below query which calculates from the first requested date to first completed date how much time elapsed.
However in the example below there is a requested date of 2017-02-02 (backdated) which was created on the 2017-02-06.
I want to edit the query to select the requested date and calculate how much time elapsed until completed from the FIRST CREATED DATE
So right now it returns 1 when it should be 0
Reasoning, because first created date is 2017-02-03 and it was requested and completed on the same day 2017-02-03
Any help is appreciated greatly!
CREATE TABLE #temp
(Identifier VARCHAR(40) NOT NULL,
Created_Date DATETIME NOT NULL,
Requested_Date DATETIME NOT NULL,
Completed_Date DATETIME NULL,
SN_Type VARCHAR(20) NOT NULL,
SN_Status VARCHAR(20) NOT NULL
);
INSERT INTO #temp
VALUES
('11111',
'20170203',
'20170203',
'20170203',
'Re-Activattion',
'COMP'
);
INSERT INTO #temp
VALUES
('11111',
'20170206',
'20170202',
NULL,
'Re-Activattion',
'N-CO'
);
SELECT *
FROM #temp;
-- calculate/identify Order start and Order End records
WITH cte
AS (
-- 1st Order start record i.e. earliest record in the table for a given "Identifier"
SELECT Identifier,
MIN(Created_Date) AS Created_Date,
CONVERT(VARCHAR(30), 'Created') AS RecordType,
1 AS OrderNumber
FROM #temp
GROUP BY Identifier
UNION ALL
-- All records with "COMP" status are treated as order completed events. Add 2 weeks to the completed date to create a "dummy" Order End Date
SELECT Identifier,
DATEADD(WEEK, 2, Created_Date) AS Created_Date,
'Completed' AS RecordType,
ROW_NUMBER() OVER(PARTITION BY Identifier ORDER BY Created_Date) AS OrderNumber
FROM #temp
WHERE SN_STATUS = 'COMP'
UNION ALL
-- Set the start period of the next order to be right after (3 ms) the previous Order End Date
SELECT Identifier,
DATEADD(ms, 3, DATEADD(WEEK, 2, Created_Date)) AS Created_Date,
'Created' AS RecordType,
ROW_NUMBER() OVER(PARTITION BY Identifier ORDER BY Created_Date) + 1 AS OrderNumber
FROM #temp
WHERE SN_STATUS = 'COMP'),
-- Combine Start / End records into one record
OrderGroups
AS (
SELECT Identifier,
OrderNumber,
MIN(Created_Date) AS OrderRangeStartDate,
MAX(Created_Date) AS OrderRangeEndDate
FROM cte
GROUP BY Identifier,
OrderNumber)
SELECT a.Identifier,
a.OrderNumber,
OrderRangeStartDate,
OrderRangeEndDate,
CASE
WHEN SUM(CASE
WHEN SN_STATUS = 'COMP'
AND SN_TYPE = 'Re-Activattion'
THEN 1
ELSE 0
END) > 0
THEN STR(DATEDIFF(day, MIN(CASE
WHEN SN_TYPE = 'Re-Activattion'
THEN Requested_Date
ELSE NULL
END), MIN(CASE
WHEN(SN_TYPE = 'Re-Activattion'
AND SN_STATUS = 'COMP')
THEN Completed_Date
ELSE NULL
END)))
WHEN SUM(CASE
WHEN SN_TYPE = 'Re-Activattion'
THEN 1
ELSE 0
END) > 0
THEN 'NOT COMP'
ELSE 'NO RE-ACT'
END AS RE_ACT_COMPLETION_TIME,
SUM(CASE
WHEN SN_STATUS = 'N-CO'
THEN 1
ELSE 0
END) AS [RE-AN NCO #]
FROM OrderGroups AS a
INNER JOIN #Temp AS b ON a.Identifier = b.Identifier
AND a.OrderRangeStartDate <= b.Created_Date
AND b.Created_Date <= a.OrderRangeEndDate
GROUP BY a.Identifier,
a.OrderNumber,
OrderRangeStartDate,
OrderRangeEndDate;

I want to edit the query to select the requested date and calculate
how much time elapsed until completed from the FIRST CREATED DATE
Change this:
,MIN(case
when SN_TYPE = 'Re-Activattion'
then Requested_Date
else null
end
To this:
,MIN(case
when SN_TYPE = 'Re-Activattion'
then Created_Date
else null
end

Related

SQL case statement closest to current date

Need help create a case statement to find the closest date from date table. My data: https://imgur.com/hkBu4SA
I basically want to set:
Y flag if it's closest to today's date from a.FROM_EFFDT and is not null.
F if to_effdate is null
else N
WHEN a.FROM_EFFDT < GETDATE() AND (to_effdate) IS NOT NULL THEN 'Y'
WHEN to_effdate IS NULL THEN 'F'
ELSE 'N'
You can use window functions:
(case when row_number() over (order by abs(datediff(day, getdate(), to_effdate)) = 1
then 'Y'
when to_effdate is null then 'F'
else 'N'
end)
You may be able to accomplish it with something like this. Though this isn't bulletproof, you could get duplicates if the closest date is tied.
create table Dates (from_effdt datetime, to_effdt datetime, flag varchar(1))
insert Dates (from_effdt, to_effdt, flag)
values
('2019-03-16', null, '') ,
('2018-06-14', '2019-03-16', '') ,
('2018-05-14', '2018-06-14', '') ,
('2018-01-01', '2018-05-14', '')
select * from Dates
UPDATE Dates
SET flag =
CASE
WHEN from_effdt = (
select top 1 from_effdt
from Dates
order by ABS ( DATEDIFF(day, from_effdt, getdate()) )
)
THEN 'Y'
ELSE
'N'
END
*update, not sure why I created it as an update. This select should do.
SELECT from_effdt, to_effdt,
CASE
WHEN from_effdt = (
select top 1 from_effdt
from Dates
order by ABS ( DATEDIFF(day, from_effdt, getdate()) )
)
THEN 'Y'
ELSE
'N'
END [numberOfDaysAway]
FROM Dates
You can simply do this:
CASE
WHEN from_effdt = (
select from_effdt
from Dates
where abs(datediff(second, from_effdt, getdate()))
= (select min(
abs(datediff(second, from_effdt, getdate()))
)
from Dates)
)
THEN 'Y'
ELSE
'N'
END
ROW_NUMBER() Over (Partition by id order by to_effdt desc)
,id
,from_effdt
,to_effdt
, CASE WHEN (ROW_NUMBER() Over (Partition by id order by to_effdt desc) = 1) THEN ('Y')
WHEN (to_effdt IS NULL) THEN ('F') ELSE ('N') End as flag
from a

Multiply two (2) columns of a table

Please I need to multiply total no of jobtype and the value of MEAL_Ticket for a particular date
SELECT DISTINCT
DATENAME(dw, Time) + ', ' + CONVERT(VARCHAR(12), Time, 107) AS Date_to_Display,Vale,
(SELECT COUNT(*) FROM CanLog AS c
WHERE c.Time= clog.Time AND jobtype = 'fulltime') AS Fulltime,
(SELECT COUNT(Jobtype) * SUM(Value) FROM CanLog
WHERE Time BETWEEN '2018-02-12' AND '2018-02-14' AND jobtype = 'fulltime' ) AS FulltimeTicket_Value,
(SELECT COUNT(*) FROM CanLog AS c
WHERE c.Time = clog.Time AND jobtype = 'contract') AS Contract,
(SELECT COUNT(*) FROM CanLog AS c
WHERE c.Time = clog.Time AND jobtype = 'casual') AS Casual
FROM
CanLog AS clog
WHERE
Time BETWEEN '2018-02-12' AND '2018-02-14'
GROUP BY
Time, Jobtype
ORDER BY
2 ASC
I got this error
Column 'CanLog.Value' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
What I want is this output:
Fulltime FulltimeTicket_Value Contract Casual
2018/06/04 1 500(1*500) 6 2
2018/06/05 3 1500(3*500) 0 0
2018/06/06 0 0 (0*500) 3 1
2018/06/07 2 1000(2*500) 1 0
2018/06/08 1 500(1*500) 1 3
2018/06/09 0 0(0*500) 1 4
Please help
EDIT:
Sample table
CREATE TABLE [dbo].[CanLog]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[Firstname] [nvarchar](50) NOT NULL,
[Designation] [nvarchar](50) NOT NULL,
[Jobtype] [nvarchar](50) NOT NULL,
[Employ_No] [nvarchar](50) NOT NULL,
[Receipt_No] [int] NOT NULL,
[Username] [nvarchar](50) NOT NULL,
[Time] [datetime] NOT NULL,
[Value] [int] NULL
) ON [PRIMARY]
Initial query has a lot of warning signs:
GROUP BY does not match SELECT
DISTINCT + GROUP BY
unnecessary subqueries could be replaced with conditional aggregation
positional ORDER BY
I would recommend to avoid column names such as Value/Time
Datename(dw, Time) + ', ' + CONVERT(VARCHAR(12), Time, 107) I would replace it with CAST(Time AS DATE)
Time BETWEEN '2018-02-12' AND '2018-02-14' this kind of comparison may be dangerous (as mentioned by #Gordon)
I believe you want something like:
SELECT
Date_to_Display = CAST(Time AS DATE),
Fulltime = SUM(CASE WHEN jobtype = 'fulltime' THEN 1 ELSE 0 END),
FulltimeTicket_Value = SUM(CASE WHEN jobtype = 'fulltime' THEN 1 ELSE 0 END) *
MAX(CASE WHEN jobtype = 'fulltime' THEN Value ELSE 0 END),
Contract = SUM(CASE WHEN jobtype = 'contract' THEN 1 ELSE 0 END),
Casual = SUM(CASE WHEN jobtype = 'casual' THEN 1 ELSE 0 END)
FROM
CanLog AS clog
WHERE
Time >= '2018-02-12' and time < '2018-02-15'
GROUP BY
CAST(Time AS DATE)
ORDER BY
CAST(Time AS DATE);
In addition to many of the points that Lukasz makes, you should avoid using between on date/time columns. A very good explanation is in Aaron Bertrand's blog What do Between and the Devil Have In Common.
You can also simplify the logic using indicator variables:
select cast(time as date) as Date_to_Display,
sum(is_fulltime) as Fulltime,
sum(value * is_fulltime) as FulltimeTicket_Value,
sum(is_contract) as Contract,
sum(is_casual) as Casual
from CanLog cl cross apply
(values (case when cl.jobtype = 'fulltime' then 1 else 0 end),
(case when cl.jobtype = 'contract' then 1 else 0 end),
(case when cl.jobtype = 'casual' then 1 else 0 end)
) v(is_contract, iscasual)
where Time >= '2018-02-12' and time < '2018-02-15'
group by cast(time as date)
order by cast(time as date);

trouble in query

hey every one i have this record
id date hours groupkey
1 1-12-2016 1 NULL
2 2-12-2016 2 NULL
3 3-12-2016 1 3
4 4-12-2016 1 3
5 5-12-2016 1 3
and i want this
id startdate enddate hours
1 1-12-2016 1-12-2016 1
2 2-12-2016 2-12-2016 2
3 3-12-2016 5-12-2016 3
i am using this query
SELECT Max(Isnull(groupkey, id)) AS id,
Min(date) AS startdate,
Max(date) AS enddate,
Sum(timeoffhours) AS hours,
CASE
WHEN Min(groupkey) IS NULL THEN 'No'
ELSE 'Yes'
END Status
FROM table
WHERE employeekey = 20
AND date >= '1/1/2016'
AND date <= '12/31/2016'
GROUP BY groupkey
but it is making one row for null group key please help me
You should GROUP BY Isnull(groupkey, id)) to solve your issue here. You're still grouping on the regular groupkey.
Try in dynamic table
SELECT
id, startdate, enddate, hours,
CASE WHEN mingroup IS NULL THEN 'No' ELSE 'YES' END AS status
FROM
(SELECT
MAX(ISNULL(groupkey, id)) AS id,
MIN(date) AS startdate,
MAX(date) AS enddate,
SUM(timeoffhours) AS hours,
MIN(groupkey) AS mingroup
FROM
table
WHERE
employeekey = 20
AND date >= '1/1/2016'
AND date <= '12/31/2016'
GROUP BY
groupkey)
BEGIN TRAN
CREATE TABLE #Temp (id INT IDENTITY(1,1) , _date DATE ,_hours INT , groupkey INT)
CREATE TABLE #OutPutTemp (_id INT , _Startdate DATE ,_EndDate DATE, _Hours INT)
INSERT INTO #Temp (_date ,_hours , groupkey )
SELECT '1-12-2016' ,1,NULL UNION ALL
SELECT '2-12-2016' ,2,NULL UNION ALL
SELECT '3-12-2016' ,1,3 UNION ALL
SELECT '4-12-2016' ,1,3 UNION ALL
SELECT '5-12-2016' ,1,3
INSERT INTO #OutPutTemp(_id , _Startdate ,_EndDate,_Hours)
SELECT id , _date , _date , _hours
FROM #Temp
WHERE ISNULL(groupkey,0) = 0
INSERT INTO #OutPutTemp(_id)
SELECT groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
UPDATE #OutPutTemp SET _Startdate = Startdate
FROM
(
SELECT MIN(_date) Startdate ,groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
)A
WHERE _id = groupkey
UPDATE #OutPutTemp SET _EndDate = EndDate
FROM
(
SELECT MAX(_date) EndDate ,groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
)B
WHERE _id = groupkey
UPDATE #OutPutTemp SET _hours = tothours
FROM
(
SELECT SUM(_hours) tothours ,groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
)C
WHERE _id = groupkey
SELECT * FROM #OutPutTemp
ROLLBACK TRAN

How to combine multiple rows of employee into single row in SQL Server

I'm having following table and below is expected results. Please let me known if there is a easy to way to get the expected results in SQL server.
EmpNo Name Benefit StartDate Status
--------------------------------------------
0001 ABC Medical 01/01/2014 Active
0001 ABC Dental 02/02/2013 Inactive
0001 ABC Vision 03/03/2012 Active
0002 XYZ Medical 01/01/2014 Active
0002 XYZ Dental 02/02/2008 Inactive
The results should be like below
EmpNo Name MedicalStart MedStatus DenStart DenStatus VisionStart VisStatus
---------------------------------------------------------------------------------------
0001 ABC 01/01/2014 Active 02/02/2013 Inactive 03/03/2012 Active
0002 XYZ 01/01/2014 Active 02/02/2008 Inactive .
I forgot put a few notes in my initial post.
1) There are 10 benefit plans available, so an employee may enroll for any number of plans up to ten (all plan or few plan or no plans at all).
2) There will be only one row with same benefit plan per EmpNo/Name.
3) Also, there are several fields associated with each row, for example, election option (Self, Family, etc) and many more. To make it simple, I have not included in the question.
Sample data:
CREATE TABLE #Test
(
EmpNo INT
, Name VARCHAR(255)
, Benefit VARCHAR(255)
, StartDate DATETIME2
, Status VARCHAR(255)
);
INSERT INTO #Test
(EmpNo, Name, Benefit, StartDate, Status)
VALUES
(0001, 'ABC', 'Medical', '01/01/2014', 'Active')
, (0001, 'ABC', 'Dental', '02/02/2013', 'Inactive')
, (0001, 'ABC', 'Vision', '03/03/2012', 'Active')
, (0002, 'XYZ', 'Medical', '01/01/2014', 'Active')
, (0002, 'XYZ', 'Dental', '02/02/2008', 'Inactive')
And a simple group clause:
Actual query (if there are historical records), using ROW_NUMBER will let you find latest record for each User and its Benefit:
SELECT T.EmpNo
, T.Name
, MAX(CASE WHEN T.Benefit = 'Medical ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS MedStart
, MAX(CASE WHEN T.Benefit = 'Medical' THEN T.Status END) AS MedStatus
, MAX(CASE WHEN T.Benefit = 'Dental ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS DenStart
, MAX(CASE WHEN T.Benefit = 'Dental' THEN T.Status END) AS DenStatus
, MAX(CASE WHEN T.Benefit = 'Vision ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS VisStart
, MAX(CASE WHEN T.Benefit = 'Vision' THEN T.Status END) AS VisStatus
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY EmpNo, Name, Benefit ORDER BY StartDate DESC) AS RowNo
, EmpNo
, Benefit
, Name
, StartDate
, Status
FROM #Test
) AS T
WHERE T.RowNo = 1
GROUP BY T.EmpNo
, T.Name
Query using dynamic SQL if there is unknown amount of Benefits. Might not be very efficient:
DECLARE #SQL NVARCHAR(MAX) = 'SELECT T.EmpNo, T.Name'
, #Benefit VARCHAR(MAX);
SELECT #SQL += ', MAX(CASE WHEN T.Benefit = ''' + Benefit + ''' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS ' + LEFT(Benefit, 3) + 'Star
, MAX(CASE WHEN T.Benefit = ''' + Benefit + ''' THEN T.Status END) AS ' + LEFT(Benefit, 3) + 'Status'
FROM (SELECT DISTINCT Benefit FROM #Test) AS T
SET #SQL += '
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY EmpNo, Name, Benefit ORDER BY StartDate DESC) AS RowNo, EmpNo, Benefit, NAME, StartDate, STATUS
FROM #Test
) AS T
WHERE T.RowNo = 1
GROUP BY T.EmpNo, T.Name'
EXEC sp_executesql #SQL
Query (if there are no historical records):
SELECT T.EmpNo
, T.Name
, MAX(CASE WHEN T.Benefit = 'Medical ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS MedStart
, MAX(CASE WHEN T.Benefit = 'Medical' THEN T.Status END) AS MedStatus
, MAX(CASE WHEN T.Benefit = 'Dental ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS DenStart
, MAX(CASE WHEN T.Benefit = 'Dental' THEN T.Status END) AS DenStatus
, MAX(CASE WHEN T.Benefit = 'Vision ' THEN CONVERT(VARCHAR(10), CONVERT(DATE, T.StartDate, 106), 103) END) AS VisStart
, MAX(CASE WHEN T.Benefit = 'Vision' THEN T.Status END) AS VisStatus
FROM #Test AS T
GROUP BY T.EmpNo
, T.Name
Output:
EmpNo Name MedStart MedStatus DenStart DenStatus VisStart VisStatus
-------------------------------------------------------------------------------------
1 ABC 01/01/2014 Active 02/02/2013 Inactive 03/03/2012 Active
2 XYZ 01/01/2014 Active 02/02/2008 Inactive NULL NULL
PIVOT solution on StartDate field:
DECLARE #tb AS TABLE
(
EmpNo INT
,Name NVARCHAR(25)
,Benefit NVARCHAR(25)
,StartDate DATE
,[Status] NVARCHAR(25)
);
INSERT INTO #tb VALUES (1, 'ABC', 'Medical', '01/01/2014', 'Active');
INSERT INTO #tb VALUES (1, 'ABC', 'Dental', '02/02/2013', 'Inactive');
INSERT INTO #tb VALUES (1, 'ABC', 'Vision', '03/03/2012', 'Active');
INSERT INTO #tb VALUES (2, 'XYZ', 'Medical', '01/01/2014', 'Active');
INSERT INTO #tb VALUES (2, 'XYZ', 'Dental', '02/02/2012', 'Inactive');
SELECT EmpNo
,Name
,MAX(MedicalStart) AS MedicalStart
,MAX(MedStatus) AS MedStatus
,MAX(DenStart) AS DenStart
,MAX(DenStatus) AS DenStatus
,MAX(VisionStart) AS VisionStart
,MAX(VisStatus) AS VisStatus
FROM
(
SELECT EmpNo
,Name
,[Medical] AS MedicalStart
,CASE
WHEN [Medical] IS NOT NULL AND [Status] = 'Active' THEN 'Active'
WHEN [Medical] IS NOT NULL AND [Status] = 'Inactive' THEN 'Inactive'
ELSE NULL END AS MedStatus
,[Dental] AS DenStart
,CASE
WHEN [Dental] IS NOT NULL AND [Status] = 'Active' THEN 'Active'
WHEN [Dental] IS NOT NULL AND [Status] = 'Inactive' THEN 'Inactive'
ELSE NULL END AS DenStatus
,[Vision] AS VisionStart
,CASE
WHEN [Vision] IS NOT NULL AND [Status] = 'Active' THEN 'Active'
WHEN [Vision] IS NOT NULL AND [Status] = 'Inactive' THEN 'Inactive'
ELSE NULL END AS VisStatus
,[Status]
FROM #tb
PIVOT
(
MAX(StartDate)
FOR Benefit IN ([Medical], [Dental], [Vision])
) AS pivotTableDate
) AS tb
GROUP BY EmpNo, Name;
You can check this link 'PIVOT on two or more fields in SQL Server' for information about full PIVOT solution.
I assume that for each employee you have at most 1 row for Medical, at most 1 row for Dental, and at most 1 row for Vision. If so, you can do it like this:
select
t.EmpNo, t.Name,
tMedical.MedicalStart, tMedical.MedicalStatus
from
(
select
EmpNo, Name
from
TableName
group by EmpNo, Name
) t
left outer join
(
select
EmpNo, Name, Benefit,
min(StartDate) as MedicalStart,
min(Status) as MedicalStatus
from
TableName
where
Benefit = 'Medical'
group by EmpNo, Name, Benefit
) tMedical on t.EmpNo = tMedical.EmpNo and t.Name = tMedical.Name
left outer join ...
Analogically to tMedical, you can add here left joins to tDental and tVision. And that should be it.
You can use Outer Apply to do this. I am assuming that one employee can have any number of medical, dental and vision rows. This query will take the latest StartDate for each type.
Select EmpNo, Name, Medical.StartDate MedicalStart, Medical.Status MedStatus, Dental.StartDate DenStart, Dental.Status DenStatus, Vision.StartDate VisionStart, Vision.Status VisStatus
From (Select Distinct EmpNo, Name From TableName) Emp
Outer Apply (Select Top 1 StartDate, Status From TableName Med Where Benefit='Medical' and Med.EmpNo=Emp.EmpNo Order By StartDate Desc) Medical
Outer Apply (Select Top 1 StartDate, Status From TableName Den Where Benefit='Dental' and Den.EmpNo=Emp.EmpNo Order By StartDate Desc) Dental
Outer Apply (Select Top 1 StartDate, Status From TableName Vis Where Benefit='Vision' and Vis.EmpNo=Emp.EmpNo Order By StartDate Desc) Vision
Let me know if this works for you...

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;