Calculating age from a varchar column with discrepancies - sql

Hoping you had a restful Easter. Appreciate if you could advice/help me in the following. (Using Function/without function)
Below are my DataSet, Desired Output (With derived Age using the DOB specifications from the rules)
Your help is needed in (Please note that i looking for solution in MSSQL environment):-
1. Coming up with Age field. (I tried the following script but it didn't work as it is not dynamic enough to include all the DOB rules, i also attached an oracle script which worked as a reference for you guys)
SELECT
[ID],
[DOB],
'age' = DATEDIFF(HOUR,(CONVERT(date,(CASE WHEN ([DOB] like '99/%/%') THEN (REPLACE([DOB],'99','01'))
ELSE [DOB] END),103)),GETDATE())/8766
from [Sample]
Sample_Dataset
create table Sample (
Id Varchar (50),
DOB Varchar (50))
insert into Sample(Id, DOB)
Values
('38603', '24/02/1969'),
('38605', '22/09/1969'),
('36356', '17/03/1954'),
('36374', '17/05/1975'),
('36441', '17/08/1961'),
('1a', '10/05/9999'),
('1b', '10/99/9999'),
('1c', '99/99/9999'),
('2a', '--/--/1935'),
('2b', '00/00/1935'),
('2c', '88/88/1935'),
('2d', '99/99/1935'),
('3a', '10/--/1935'),
('3b', '10/00/1935'),
('3c', '10/88/1935'),
('3d', '10/99/1935'),
('4a', '--/09/1935'),
('4b', '00/09/1935'),
('4c', '88/09/1935'),
('4d', '99/09/1935')
Desired output
ID | DOB | Age (As of 05-03-2018; dd-mm-yyyy)
38603 | 24/02/1969 | 49 --Everything is known
38605 | 22/09/1969 | 48
36356 | 17/03/1954 | 63
36374 | 17/05/1975 | 42
36441 | 17/08/1961 | 56
1a | 10/05/9999 |null --unknown year
1b | 10/99/9999 |null
1c | 99/99/9999 |null
2a | --/--/1935 |82 --unknown day and month
2b | 00/00/1935 |82
2c | 88/88/1935 |82
2d | 99/99/1935 |82
3a | 10/--/1935 |82 --unknown month but known year
3b | 10/00/1935 |82
3c | 10/88/1935 |82
3d | 10/99/1935 |82
4a | --/09/1935 |82 --unknown day but known month
4b | 00/09/1935 |82
4c | 88/09/1935 |82
4d | 99/09/1935 |82
Rules:-
As you can see in the above 5 scenarios in the comments
Everything is known (use the stated DOB to calculate the age)
Unknown Year (put age as null as the year is known)
Unknown day and month (Use 01/07 for the unknown dd/mm and the stated yyyy)
Unknown month but known day (Use 07 for the unknown mm and the stated dd/07/yyyy)
Unknown day but known month (Use 15 for the unknown dd and the stated 15/mm/yyyy)
Solution in Oracle
Creating a function first (Tried replicating this logic in T-SQL but unsuccessful, hence i am here)
create or replace function check_dt(in_date in VARCHAR2, in_format in VARCHAR2 default 'DD/MM/YYYY')
RETURN NUMBER
IS
V_DATE DATE;
V_STATUS INTEGER;
BEGIN
SELECT TO_DATE(in_date,in_format)
INTO V_DATECASE
FROM DUAL;
V_STATUS := 0;
RETURN V_STATUS;
EXCEPTION WHEN OTHERS THEN
V_STATUS := SQLCODE;
RETURN V_STATUS;
END;
select check_dt('11/30/2017') from dual;
select TO_DATE('15/--/9999','DD/MM/YYYY') from dual;
select id, dob,
case when check_dt(dob) = -1843 --not valid month, default it to July (07)
THEN substr(dob,1,2)||'/07'||substr(dob,7,4)
when check_dt(dob) = -01847 -- day of month must between 1 and last day of month
THEN '1/07/'||substr(dob,7,4)
WHEN check_dt(dob) = 0 and to_date(dob,'dd/mm/yyyy') > sysdate
THEN NULL
WHEN check_dt(dob) = -0183 -- date not valid for month
THEN '15/'||substr(dob,4)
ELSE
THEN dob
END New_dob
from SAMPLE;
Any help would be much appreciated.
Thank you very Much.

SQL SERVER
SELECT id,
CASE WHEN YEAR(GETDATE())-REVERSE(LEFT(REVERSE(DOB), CHARINDEX('/', REVERSE(DOB)) - 1)) > = 0
THEN
YEAR(GETDATE())-REVERSE(LEFT(REVERSE(DOB), CHARINDEX('/', REVERSE(DOB)) - 1))
ELSE
NULL
END AS Age
FROM Sample
Solution For Your Question
WITH CTE AS
(
SELECT id,
CASE WHEN ISNUMERIC(REVERSE(LEFT(REVERSE(DOB), CHARINDEX('/', REVERSE(DOB)) - 1))) = 1 THEN
REVERSE(LEFT(REVERSE(DOB), CHARINDEX('/', REVERSE(DOB)) - 1))
ELSE
NULL
END
AS Year,
CASE WHEN ISNUMERIC(LEFT(DOB, CHARINDEX('/', DOB) - 1)) = 1 THEN
LEFT(DOB, CHARINDEX('/', DOB) - 1)
ELSE
NULL
END AS DAY,
CASE WHEN ISNUMERIC(SUBSTRING(DOB,CHARINDEX('/',DOB)+1, CHARINDEX('/',DOB,CHARINDEX('/',DOB)+1) -CHARINDEX('/',DOB)-1)) = 1 THEN
CASE WHEN SUBSTRING(DOB,CHARINDEX('/',DOB)+1, CHARINDEX('/',DOB,CHARINDEX('/',DOB)+1) -CHARINDEX('/',DOB)-1) >= 1 AND SUBSTRING(DOB,CHARINDEX('/',DOB)+1, CHARINDEX('/',DOB,CHARINDEX('/',DOB)+1) -CHARINDEX('/',DOB)-1) <= 12 THEN
SUBSTRING(DOB,CHARINDEX('/',DOB)+1, CHARINDEX('/',DOB,CHARINDEX('/',DOB)+1) -CHARINDEX('/',DOB)-1)
ELSE
NULL
END
ELSE
NULL
END AS MONTH
FROM Sample),CTE1 AS
(
SELECT id,
year,
month,
CASE WHEN DAY IS NOT NULL THEN
CASE WHEN DAY >= 1 AND DAY <= DAY(EOMONTH(year+'-'+month+'-01')) THEN
DAY
ELSE
NULL
END
ELSE NULL
END AS Day
FROM CTE
)
,CTE2 AS
(
SELECT id,
CASE WHEN YEAR IS NULL
THEN NULL
ELSE
CASE WHEN DAY IS NULL AND MONTH IS NULL THEN '01/07'
WHEN MONTH IS NULL AND DAY IS NOT NULL THEN CAST(day AS VARCHAR)+'/07'
WHEN MONTH IS NOT NULL AND DAY IS NULL THEN '15/'+CAST(MONTH AS VARCHAR)
ELSE CAST(day AS VARCHAR)+'/'+CAST(MONTH AS VARCHAR)
END
+ '/'+CAST(YEAR AS VARCHAR)
END
AS DOB
FROM CTE1
)
SELECT id,DOB,
CASE WHEN DOB IS NOT NULL
THEN
CASE WHEN DATEDIFF (day, CONVERT(DATE, DOB, 103),CONVERT(DATE,GETDATE(),103)) >=0
THEN FLOOR(DATEDIFF (day, CONVERT(DATE, DOB, 103), CONVERT(DATE,GETDATE(),103)) / 365.2425)
ELSE
NULL
END
ELSE
DOB
END AS Age
FROM CTE2
DEMO LIVE
http://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=3714d33cacb02c3fce4f0868c9d0990b

You can use the following. I used different CTE's to show you the progression towards obtaining the date of birth from your varchar DOB. I also changed the table to a temporary one.
IF OBJECT_ID('tempdb..#Sample') IS NOT NULL
DROP TABLE #Sample
create table #Sample (
Id Int,
DOB Varchar (50))
insert into #Sample(Id, DOB)
Values
(38603, '24/02/1969'),
(38605, '22/09/1969'),
(36356, '17/03/1954'),
(36374, '17/05/1975'),
(36441, '17/08/1961'),
(119, '10/05/9999'),
(114, '10/99/9999'),
(132, '99/99/9999'),
(25125, '--/--/1935'),
(2323, '00/00/1935'),
(2512, '88/88/1935'),
(2156, '99/99/1935'),
(368, '10/--/1935'),
(34135, '10/00/1935'),
(3435, '10/88/1935'),
(3241, '10/99/1935'),
(4512, '--/09/1935'),
(4161, '00/09/1935'),
(4312, '88/09/1935'),
(456, '99/09/1935')
;WITH ParsedBirth AS
(
SELECT
S.Id,
S.DOB,
Year = SUBSTRING(S.DOB, 7, 4),
Month = SUBSTRING(S.DOB, 4, 2),
Day = SUBSTRING(S.DOB, 1, 2)
FROM
#Sample AS S
),
ParsedBirthInteger AS
(
SELECT
P.Id,
P.DOB,
Year = CASE WHEN ISNUMERIC(P.Year) = 1 AND P.Year <> '9999' THEN CONVERT(INT, P.Year) END,
Month = CASE
WHEN ISNUMERIC(P.Month) = 1 AND CONVERT(INT, P.Month) BETWEEN 1 AND 12 THEN CONVERT(INT, P.Month)
ELSE 7 END,
Day = CASE
WHEN ISNUMERIC(P.Day) = 1 AND CONVERT(INT, P.Day) BETWEEN 1 AND 31 THEN CONVERT(INT, P.Day)
ELSE 15 END
FROM
ParsedBirth AS P
),
InferredBirth AS
(
SELECT
P.Id,
P.DOB,
InferredBirth = CONVERT(DATE, CONVERT(VARCHAR(100), P.Year * 10000 + P.Month * 100 + P.Day))
FROM
ParsedBirthInteger AS P
)
SELECT
T.Id,
T.DOB,
T.InferredBirth,
Age = (CONVERT(INT,CONVERT(char(8), GETDATE(),112))-CONVERT(char(8),T.InferredBirth,112))/10000
FROM
InferredBirth AS T

First of all:
It is a very bad idea to store a date in a culture dependant string format.
It is a very bad idea to use magic values (9999 meaning "no year").
Is is a most dangerous, bad idea to mix this!
The following code will transform your values to the format you should use to store this actually. You can build your age-logic from here, but I'd really recommend you, to use this approach to clean up this mess and store your data properly!
DECLARE #sample TABLE(
Id VARCHAR(10),
DOB VARCHAR (50))
INSERT INTO #sample(Id, DOB)
VALUES
('38603', '24/02/1969'),
('38605', '22/09/1969'),
('36356', '17/03/1954'),
('36374', '17/05/1975'),
('36441', '17/08/1961'),
('1a', '10/05/9999'),
('1b', '10/99/9999'),
('1c', '99/99/9999'),
('2a', '--/--/1935'),
('2b', '00/00/1935'),
('2c', '88/88/1935'),
('2d', '99/99/1935'),
('3a', '10/--/1935'),
('3b', '10/00/1935'),
('3c', '10/88/1935'),
('3d', '10/99/1935'),
('4a', '--/09/1935'),
('4b', '00/09/1935'),
('4c', '88/09/1935'),
('4d', '99/09/1935');
--The query will split your string on the / and try to cast the values to int:
WITH Splitted AS
(
SELECT Id
,DOB
,CAST('<x>' + REPLACE(DOB,'/','</x><x>') + '</x>' AS XML).value('/x[1]','varchar(10)') AS DOB_Day
,CAST('<x>' + REPLACE(DOB,'/','</x><x>') + '</x>' AS XML).value('/x[2]','varchar(10)') AS DOB_Month
,CAST('<x>' + REPLACE(DOB,'/','</x><x>') + '</x>' AS XML).value('/x[3]','varchar(10)') AS DOB_Year
FROM #sample
)
,Casted AS
(
SELECT Id
,DOB
--below SQL-Server 2012 you can use `CASE` with `ISNUMERIC` instead of TRY_CAST
,TRY_CAST(DOB_Day AS INT) AS CastedDay
,TRY_CAST(DOB_Month AS INT) AS CastedMonth
,TRY_CAST(DOB_Year AS INT) AS CastedYear
FROM Splitted
)
,Checked AS
(
SELECT Id
,DOB
--You can use further logic to get the month's days correctly (instead of the plain 31)
,CASE WHEN CastedDay BETWEEN 1 AND 31 THEN CastedDay ELSE NULL END AS TheDay
,CASE WHEN CastedMonth BETWEEN 1 AND 12 THEN CastedMonth ELSE NULL END AS TheMonth
,CASE WHEN CastedYear BETWEEN 1900 AND 2100 THEN CastedYear ELSE NULL END AS TheYear
FROM Casted
)
SELECT *
FROM Checked;
The result
+-------+------------+--------+----------+---------+
| Id | DOB | TheDay | TheMonth | TheYear |
+-------+------------+--------+----------+---------+
| 38603 | 24/02/1969 | 24 | 2 | 1969 |
+-------+------------+--------+----------+---------+
| 38605 | 22/09/1969 | 22 | 9 | 1969 |
+-------+------------+--------+----------+---------+
| 36356 | 17/03/1954 | 17 | 3 | 1954 |
+-------+------------+--------+----------+---------+
| 36374 | 17/05/1975 | 17 | 5 | 1975 |
+-------+------------+--------+----------+---------+
| 36441 | 17/08/1961 | 17 | 8 | 1961 |
+-------+------------+--------+----------+---------+
| 1a | 10/05/9999 | 10 | 5 | NULL |
+-------+------------+--------+----------+---------+
| 1b | 10/99/9999 | 10 | NULL | NULL |
+-------+------------+--------+----------+---------+
| 1c | 99/99/9999 | NULL | NULL | NULL |
+-------+------------+--------+----------+---------+
| 2a | --/--/1935 | NULL | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 2b | 00/00/1935 | NULL | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 2c | 88/88/1935 | NULL | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 2d | 99/99/1935 | NULL | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 3a | 10/--/1935 | 10 | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 3b | 10/00/1935 | 10 | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 3c | 10/88/1935 | 10 | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 3d | 10/99/1935 | 10 | NULL | 1935 |
+-------+------------+--------+----------+---------+
| 4a | --/09/1935 | NULL | 9 | 1935 |
+-------+------------+--------+----------+---------+
| 4b | 00/09/1935 | NULL | 9 | 1935 |
+-------+------------+--------+----------+---------+
| 4c | 88/09/1935 | NULL | 9 | 1935 |
+-------+------------+--------+----------+---------+
| 4d | 99/09/1935 | NULL | 9 | 1935 |
+-------+------------+--------+----------+---------+

Related

How to perform group by in SQL Server for specific output

I have a table with few records, I want to get month wise data along with count on one of the column. The output should contain Month and count of Isregistered flag.
Table structure
| Inserted On | IsRegistered |
+-------------+--------------+
| 10-01-2020 | 1 |
| 15-01-2020 | 1 |
| 17-01-2020 | null |
| 17-02-2020 | 1 |
| 21-02-2020 | null |
| 04-04-2020 | null |
| 18-04-2020 | null |
| 19-04-2020 | 1 |
Excepted output
| Inserted On | Registered | Not Registered
+-------------+------------+---------------
| Jan | 2 | 1
| Feb | 1 | 1
| Apr | 1 | 2
I tried by performing normal group by but didn't got desired output
SELECT
DATENAME(MONTH, dateinserted) AS [MonthName], COUNT(ISRegistered)
FROM
tablename
GROUP BY
(DATENAME(MONTH, dateinserted))
Note: here null is treated as not registered
You can use aggregation. I would include the year and use the month number rather than name, so:
select year(inserted_on), month(inserted_on),
coalesce(sum(is_registered), 0) as num_registered,
sum(case when is_registered is null then 1 else 0 end) as num_not_registered
from tablename
group by year(inserted_on), month(inserted_on)
order by year(inserted_on), month(inserted_on);
Note: If you really want the monthname and want to combine data from different years (which seems unlikely, but . . . ), then you can use:
select datename(month, inserted_on),
coalesce(sum(is_registered), 0) as num_registered,
sum(case when is_registered is null then 1 else 0 end) as num_not_registered
from tablename
group by datename(month, inserted_on)
order by month(min(inserted_on));
The GROUP BY should include both the year and month (so there's no overlapping) as well as the DATENAME (for display). Something like this
drop table if exists #tablename;
go
create table #tablename(dateinserted date, ISRegistered int);
insert #tablename values
('2020-12-01', 0),
('2020-11-02', 1),
('2020-11-03', 1),
('2020-12-01', 1),
('2020-12-03', 1),
('2020-11-02', 0);
select year(dateinserted) yr,
datename(month, dateinserted) AS [MonthName],
sum(ISRegistered) Registered ,
sum(1-ISRegistered) [Not Registered]
from #tablename
group by year(dateinserted), month(dateinserted), datename(month, dateinserted)
order by year(dateinserted), month(dateinserted);
yr MonthName Registered Not Registered
2020 November 2 1
2020 December 2 1

SQL: Query to filter MemberId if stay is not consecutive (same hotel, check in and check out occur on the same day)

Below is the explanation to include the condition along with the code I want to modify. I need to put this condition in my code below, but I am unable to do so and need some help.
So you have property A and property B.
A Member should not earn multiple credits if a reservation is booked at property A for 8/1 to 8/2 and a second reservation at property A for 8/2 to 8/3. This is within the same property and there is not 24 hours in between the checkout and next check in.
A Member should earn multiple credits if a reservation is booked at property A for 8/1 to 8/2 and a second reservation at property B for 8/2 to 8/3. This is within a different property so timing doesn’t matter.
Visual Example:
Property A – check in 8/1 to 8/2 – qualified stay
Property A – check in 8/2 to 8/3 – non qualified
Property A – check in 8/4 to 8/5 - qualified
Property B – check in 8/5 to 8/6 – qualified
Property C – check in 8/6 to 8/29 - qualified
Property C – check in 8/30 to 9/15 – non qualified
This is my code:
SELECT
LP.LoyaltyMemberID, LP.MemberEmail, H.pcode, cs.TotalRevenue,
cdc.MarketSubSegment, CS.RoomNights, cs.RateType,
CS.ReservationNumber, CS.StayStatus, H.HotelStatus, cs.departuredate,
CAST(CS.ArrivalDate AS DATE) AS ArrivalDate
FROM
ODS.C_DCustomerStay AS CS
LEFT OUTER JOIN
[ODS].[MemberTransactions] AS CDC ON CDC.SourceReferenceNumber = CS.ReservationNumber
LEFT JOIN
[ODS].[Memberships] AS LP ON LP.profileID = CDC.profileID
LEFT OUTER JOIN
dbo.[Hotels] AS H ON CS.CPropertyID = H.cidcode
WHERE
CAST(ArrivalDate AS DATE) = DATEADD(day, -1, CONVERT(DATE, GETDATE())) --extracting records for yesterday
AND LoyaltyMemberID <> '' AND LoyaltyMemberID IS NOT NULL
AND RoomNights >= 1 -- Min room nights > 1
AND CAST(totalrevenue AS FLOAT) >= 1 -- Min Revenue >= 1
AND DATEDIFF(DAY, arrivaldate, departuredate) >= 1
Data is shown below and only 2 unique reservation numbers per LoyaltyMemberid satisfying the above rule will be given credits.Not all reservations that qualify will get credits.
LoyaltyMemberID MemberEmail propertycode TotalRevenue MarketSubSegment RoomNights RateType ReservationNumber StayStatus rlhc_hotelstatusname arrivaldate departuredate
102282482 ljbirr#aol.com WAFEDW 118.8 PR 1 EXT1 88676 R Active 7/30/2018 7/31/2018
102282482 ljbirr#aol.com ORPEND 285.6 BR 3 WEB 119223 R Active 7/30/2018 8/2/2018
102296283 tj711#aol.com WAPOUL 246 PR 3 FDR 975372 R Active 7/30/2018 8/2/2018
102898784 JW#gmail.com WAANGE 900.9 BR 4 RNR 33401155 R Active 7/30/2018 8/3/2018
102898784 JW#gmail.com WAANGE 900.9 BR 4 RNR 33401156 R Active 7/30/2018 8/3/2018
102898784 JW#gmail.com WAANGE 937.4 BR 4 RNR 33401170 R Active 7/30/2018 8/3/2018
103723804 hmayfield#co.net IDCANY 85.48 PR 1 EX1HR 168702 R Active 7/30/2018 7/31/2018
103723804 hmayfield#co.net WAKENT 499.75 IN 4 EX1 100803 R Active 7/30/2018 8/3/2018
104157546 dfa#pn.com CAPERR 89.38 BR 1 EX1 71220 R Active 7/30/2018 7/31/2018
104337973 ralphog#eoni.com ORPEND 160 BR 2 WEB 119221 R Active 7/30/2018 8/1/2018
104408813 dennisvaughn#msn.comPAHARR 218 IN 2 GRPNP 164701 R Active 7/30/2018 8/1/2018
104420433 mahlerkelsey#me.com WAFEDW 245.1 C0 2 RNR 87476 R Active 7/30/2018 8/1/2018
104420433 mahlerkelsey#me.com WAFEDW 118.8 C0 1 EXT1 88676 R Active 7/30/2018 7/31/2018
If I am understanding you correctly, what you are stating is that if a 24-hour window has gone by since the previous checkout then a member is qualified for some sort of credit.
First thing I am going to point out is the inconsistency in the sample data you provided.
Property A – check in 8/4 to 8/5 - qualified
This is qualified for a credit because a full day passed from the previous "check out" of 08/03.
But then you say:
Property C – check in 8/30 to 9/15 – non qualified
How can this be when Property A qualifies under the exact same circumstance?
Regardless, I moved ahead believing this perhaps on oversight. Here is an example that I think will get you moving in the right direction to accomplish what you need.
You can run the following example in SSMS:
DECLARE #data TABLE ( [member] VARCHAR(10), [hotel] VARCHAR(10), [check_in] DATETIME, [check_out] DATETIME );
INSERT INTO #data (
[member], [hotel], [check_in], [check_out]
)
VALUES
( '60135522', 'PropA', '08/01/2018', '08/02/2018' )
, ( '60135522', 'PropA', '08/02/2018', '08/03/2018' )
, ( '60135522', 'PropA', '08/04/2018', '08/05/2018' )
, ( '60135522', 'PropB', '08/05/2018', '08/06/2018' )
, ( '60135522', 'PropC', '08/06/2018', '08/29/2018' )
, ( '60135522', 'PropC', '08/30/2018', '09/15/2018' );
SELECT
MemberStays.member
, MemberStays.hotel
, MemberStays.PrevCheckOut
, MemberStays.CheckIn
, MemberStays.CheckOut
, DATEDIFF( DD, [PrevCheckOut], [CheckIn] ) PrevCheckoutDays
, CASE DATEDIFF( DD, [PrevCheckOut], [CheckIn] )
WHEN 0 THEN 'non qualified'
ELSE 'qualified'
END AS [CreditStatus]
FROM (
SELECT
data1.member
, data1.hotel
, CONVERT(
VARCHAR(10)
, LAG( [check_out], 1, NULL ) OVER ( PARTITION BY [member], [hotel] ORDER BY [member], [hotel], [check_in] )
, 101
) AS PrevCheckOut
, CONVERT( VARCHAR(10), data1.check_in, 101 ) AS CheckIn
, CONVERT( VARCHAR(10), data1.check_out, 101 ) AS CheckOut
FROM #data AS data1
) AS MemberStays
ORDER BY
[hotel], [CheckIn];
Returns
+----------+-------+--------------+------------+------------+------------------+---------------+
| member | hotel | PrevCheckOut | CheckIn | CheckOut | PrevCheckoutDays | CreditStatus |
+----------+-------+--------------+------------+------------+------------------+---------------+
| 60135522 | PropA | NULL | 08/01/2018 | 08/02/2018 | NULL | qualified |
| 60135522 | PropA | 08/02/2018 | 08/02/2018 | 08/03/2018 | 0 | non qualified |
| 60135522 | PropA | 08/03/2018 | 08/04/2018 | 08/05/2018 | 1 | qualified |
| 60135522 | PropB | NULL | 08/05/2018 | 08/06/2018 | NULL | qualified |
| 60135522 | PropC | NULL | 08/06/2018 | 08/29/2018 | NULL | qualified |
| 60135522 | PropC | 08/29/2018 | 08/30/2018 | 09/15/2018 | 1 | qualified |
+----------+-------+--------------+------------+------------+------------------+---------------+
I broke the main logic into a table subquery to keep it simple for viewing purposes. The key here is using SQL Server's LAG function (coupled with its partitioning/ordering) to look at the previous checkout for a member's stay on a given hotel. Once you have that, you can then compare it against the current row's CheckIn to determine how much time has passed between the two. From there it gets simple. If the days passed is 0 (zero) then it does not qualify for consecutive credits, otherwise, it does.
This is where the second record for Property C threw me off. If I am to apply the logic you state, both Property C records qualify.
UPDATED TO REFLECT NEW RESULTSET SPECIFIED
I have updated my example to use the updated data from your resultset. You can run this code from within SSMS for review.
-- replicate resultset definition --
DECLARE #resultset TABLE (
LoyaltyMemberID VARCHAR(10)
, MemberEmail VARCHAR(100)
, PropertyCode VARCHAR(10)
, TotalRevenue DECIMAL(18, 2)
, MarketSubSegment VARCHAR(2)
, RoomNights INT
, RateType VARCHAR(10)
, ReservationNumber VARCHAR(10)
, StayStatus VARCHAR(10)
, rlhc_HotelStatusName VARCHAR(10)
, ArrivalDate SMALLDATETIME
, DepartureDate SMALLDATETIME
);
-- insert sample data into #resultset --
INSERT INTO #resultset (
LoyaltyMemberID, MemberEmail, PropertyCode, TotalRevenue, MarketSubSegment, RoomNights, RateType, ReservationNumber, StayStatus, rlhc_HotelStatusName, ArrivalDate, DepartureDate
) VALUES
( '102282482', 'ljbirr#aol.com', 'WAFEDW', 118.8, 'PR', 1, 'EXT1', '88676', 'R', 'Active', '7/30/2018', '7/31/2018' )
, ( '102282482', 'ljbirr#aol.com', 'ORPEND', 285.6, 'BR', 3, 'WEB', '119223', 'R', 'Active', '7/30/2018', '8/2/2018' )
, ( '102296283', 'tj711#aol.com', 'WAPOUL', 246, 'PR', 3, 'FDR', '975372', 'R', 'Active', '7/30/2018', '8/2/2018' )
, ( '102898784', 'JW#gmail.com', 'WAANGE', 900.9, 'BR', 4, 'RNR', '33401155', 'R', 'Active', '7/30/2018', '8/3/2018' )
, ( '102898784', 'JW#gmail.com', 'WAANGE', 937.4, 'BR', 4, 'RNR', '33401170', 'R', 'Active', '7/30/2018', '8/3/2018' )
, ( '103723804', 'hmayfield#co.net', 'IDCANY', 85.48, 'PR', 1, 'EX1HR', '168702', 'R', 'Active', '7/30/2018', '7/31/2018' )
, ( '103723804', 'hmayfield#co.net', 'WAKENT', 499.75, 'IN', 4, 'EX1', '100803', 'R', 'Active', '7/30/2018', '8/3/2018' )
, ( '104157546', 'dfa#pn.com', 'CAPERR', 89.38, 'BR', 1, 'EX1', '71220', 'R', 'Active', '7/30/2018', '7/31/2018' )
, ( '104337973', 'ralphog#eoni.com', 'ORPEND', 160, 'BR', 2, 'WEB', '119221', 'R', 'Active', '7/30/2018', '8/1/2018' )
, ( '104408813', 'dennisvaughn#msn.com', 'PAHARR', 218, 'IN', 2, 'GRPNP', '164701', 'R', 'Active', '7/30/2018', '8/1/2018' )
, ( '104420433', 'mahlerkelsey#me.com', 'WAFEDW', 245.1, 'C0', 2, 'RNR', '87476', 'R', 'Active', '7/30/2018', '8/1/2018' )
, ( '104420433', 'mahlerkelsey#me.com', 'WAFEDW', 118.8, 'C0', 1, 'EXT1', '88676', 'R', 'Active', '7/30/2018', '7/31/2018' );
Then...
/*
SELECT data from #resultset with the following rules:
- Any stay less than 24 hours does *not* qualify for loyalty credits.
- Only 2 unique reservation numbers per LoyaltyMemberid satisfying the above rule will be given credits.
- Note: Not all reservations that qualify will get credits.
*/
SELECT
LoyaltyMemberID
, MemberEmail
, PropertyCode
, TotalRevenue
, MarketSubSegment
, RoomNights
, RateType
, ReservationNumber
, StayStatus
, rlhc_HotelStatusName
, ArrivalDate
, DepartureDate
, PrevDeparture
, DepartureSeq
-- apply business rules --
, CASE
WHEN ( DATEDIFF( DD, ArrivalDate, PrevDeparture ) = 0 ) THEN 'Not Eligible'
WHEN ( DepartureSeq > 1 ) THEN 'Not Eligible'
ELSE 'Eligible'
END AS CreditEligible
FROM (
-- perform some intital work on the base resultsel --
SELECT
MemberStays.LoyaltyMemberID
, MemberStays.MemberEmail
, MemberStays.PropertyCode
, MemberStays.TotalRevenue
, MemberStays.MarketSubSegment
, MemberStays.RoomNights
, MemberStays.RateType
, MemberStays. ReservationNumber
, MemberStays.StayStatus
, MemberStays.rlhc_HotelStatusName
, CONVERT( VARCHAR(10), MemberStays.ArrivalDate, 101) AS ArrivalDate
, CONVERT( VARCHAR(10), MemberStays.DepartureDate, 101) AS DepartureDate
, CONVERT(
VARCHAR(10),
LAG( MemberStays.DepartureDate, 1, NULL ) OVER (
PARTITION BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber
ORDER BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber, MemberStays.ArrivalDate
)
, 101
) AS PrevDeparture
, ROW_NUMBER() OVER (
PARTITION BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber
ORDER BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber, MemberStays.ArrivalDate
) AS DepartureSeq
FROM #resultset AS MemberStays
) AS LoyaltyData
ORDER BY
LoyaltyData.LoyaltyMemberID, LoyaltyData.PropertyCode, LoyaltyData.ReservationNumber, LoyaltyData.ArrivalDate;
Returns
+-----------------+----------------------+--------------+--------------+------------------+------------+----------+-------------------+------------+----------------------+-------------+---------------+---------------+--------------+----------------+
| LoyaltyMemberID | MemberEmail | PropertyCode | TotalRevenue | MarketSubSegment | RoomNights | RateType | ReservationNumber | StayStatus | rlhc_HotelStatusName | ArrivalDate | DepartureDate | PrevDeparture | DepartureSeq | CreditEligible |
+-----------------+----------------------+--------------+--------------+------------------+------------+----------+-------------------+------------+----------------------+-------------+---------------+---------------+--------------+----------------+
| 102282482 | ljbirr#aol.com | ORPEND | 285.60 | BR | 3 | WEB | 119223 | R | Active | 07/30/2018 | 08/02/2018 | NULL | 1 | Eligible |
| 102282482 | ljbirr#aol.com | WAFEDW | 118.80 | PR | 1 | EXT1 | 88676 | R | Active | 07/30/2018 | 07/31/2018 | NULL | 1 | Eligible |
| 102296283 | tj711#aol.com | WAPOUL | 246.00 | PR | 3 | FDR | 975372 | R | Active | 07/30/2018 | 08/02/2018 | NULL | 1 | Eligible |
| 102898784 | JW#gmail.com | WAANGE | 900.90 | BR | 4 | RNR | 33401155 | R | Active | 07/30/2018 | 08/03/2018 | NULL | 1 | Eligible |
| 102898784 | JW#gmail.com | WAANGE | 937.40 | BR | 4 | RNR | 33401170 | R | Active | 07/30/2018 | 08/03/2018 | NULL | 1 | Eligible |
| 103723804 | hmayfield#co.net | IDCANY | 85.48 | PR | 1 | EX1HR | 168702 | R | Active | 07/30/2018 | 07/31/2018 | NULL | 1 | Eligible |
| 103723804 | hmayfield#co.net | WAKENT | 499.75 | IN | 4 | EX1 | 100803 | R | Active | 07/30/2018 | 08/03/2018 | NULL | 1 | Eligible |
| 104157546 | dfa#pn.com | CAPERR | 89.38 | BR | 1 | EX1 | 71220 | R | Active | 07/30/2018 | 07/31/2018 | NULL | 1 | Eligible |
| 104337973 | ralphog#eoni.com | ORPEND | 160.00 | BR | 2 | WEB | 119221 | R | Active | 07/30/2018 | 08/01/2018 | NULL | 1 | Eligible |
| 104408813 | dennisvaughn#msn.com | PAHARR | 218.00 | IN | 2 | GRPNP | 164701 | R | Active | 07/30/2018 | 08/01/2018 | NULL | 1 | Eligible |
| 104420433 | mahlerkelsey#me.com | WAFEDW | 245.10 | C0 | 2 | RNR | 87476 | R | Active | 07/30/2018 | 08/01/2018 | NULL | 1 | Eligible |
| 104420433 | mahlerkelsey#me.com | WAFEDW | 118.80 | C0 | 1 | EXT1 | 88676 | R | Active | 07/30/2018 | 07/31/2018 | NULL | 1 | Eligible |
+-----------------+----------------------+--------------+--------------+------------------+------------+----------+-------------------+------------+----------------------+-------------+---------------+---------------+--------------+----------------+
Mind you, I cannot test this against your database, but my thoughts are if you modify your above SQL to:
SELECT
* -- I didn't feel like typing out all the column names again, however you should as it is a best practice
, CASE
WHEN ( DATEDIFF( DD, ArrivalDate, PrevDeparture ) = 0 ) THEN 'Not Eligible'
WHEN ( DepartureSeq > 1 ) THEN 'Not Eligible'
ELSE 'Eligible'
END AS CreditEligible
FROM (
SELECT
LP.LoyaltyMemberID
, LP.MemberEmail
, H.pcode AS PropertyCode
, CS.TotalRevenue
, CDC.MarketSubSegment
, CS.RoomNights
, CS.RateType
, CS.ReservationNumber
, CS.StayStatus
, H.HotelStatus
, CAST( CS.departuredate AS SMALLDATETIME ) AS DepartureDate
, CAST( CS.ArrivalDate AS SMALLDATETIME ) AS ArrivalDate
, CONVERT(
VARCHAR(10),
LAG( MemberStays.DepartureDate, 1, NULL ) OVER (
PARTITION BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber
ORDER BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber, MemberStays.ArrivalDate
)
, 101
) AS PrevDeparture
, ROW_NUMBER() OVER (
PARTITION BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber
ORDER BY MemberStays.LoyaltyMemberID, MemberStays.PropertyCode, MemberStays.ReservationNumber, MemberStays.ArrivalDate
) AS DepartureSeq
FROM ODS.C_DCustomerStay AS CS
LEFT OUTER JOIN [ODS].[MemberTransactions] AS CDC
ON CDC.SourceReferenceNumber = CS.ReservationNumber
LEFT JOIN [ODS].[Memberships] AS LP
ON LP.profileID = CDC.profileID
LEFT OUTER JOIN dbo.[Hotels] AS H
ON CS.CPropertyID = H.cidcode
WHERE
CAST( ArrivalDate AS DATE ) = DATEADD( DD, -1, GETDATE() ) --extracting records for yesterday
AND NULLIF( LoyaltyMemberID, '' ) IS NOT NULL
AND RoomNights >= 1 -- Min room nights > 1
AND CAST(totalrevenue AS FLOAT) >= 1 -- Min Revenue >= 1
AND DATEDIFF( DD, arrivaldate, departuredate ) >= 1
) AS LoyaltyInfo
ORDER BY
LoyaltyMemberID, PropertyCode, ReservationNumber, ArrivalDate;
It should give you what you need based on what I've gathered from your initial question.
Couple of notes:
I shortened
AND LoyaltyMemberID <> '' AND LoyaltyMemberID IS NOT NULL
to
AND NULLIF( LoyaltyMemberID, '' ) IS NOT NULL
It does the same thing with less code.
I changed this
CAST(ArrivalDate AS DATE) = DATEADD(day, -1, CONVERT(DATE, GETDATE()))
to
CAST( ArrivalDate AS DATE ) = DATEADD( DD, -1, GETDATE() )
You don't need to convert GETDATE(). It is already a date.
The CASE...
WHEN ( DepartureSeq > 1 ) THEN 'Not Eligible'
excludes any subsequent stays from the same reservation from being eligible for credit.
You can modify the CASE statement used for determining eligibility to return numeric values that you can perform math on if needed.
Couple of thoughts:
» You appear to have a duplicate reservation in your data with #33401156. I have removed it for this demonstrations purposes.
» Why are you having to cast your arrival and departure dates? Are they not date columns in your database?
» You should pick up a book or look into some online training in regard to SQL Best Practices. I'm going to be blunt: Your SQL is a mess of alias inconsistencies, (possible) datatype issues and inconsistent case sensitivity. Improving this will go a long ways toward making your life easier when it comes to refactoring code later on down the road.
P.S.Adding
, ( '102898784', 'JW#gmail.com', 'WAANGE', 225.23, 'BR', 4, 'RNR', '33401155', 'R', 'Active', '08/03/2018', '8/4/2018' )
to the values inserted into #resultset will demonstrate you how a "Not Eligible" works within your ruleset.

SQL Server - Return correct column 1 value based on check of column 2 value(s)

Data:
| id | Year | CPT | RVU | MOD |
+----+-------------+--------+-------+-----+
| 1 | 2015 | 99212 | 12 | 26 |
| 2 | 2015 | 99212 | 23 | TC |
| 3 | 2015 | 99212 | 56 | |
| 4 | 2015 | 99213 | 59 | 53 |
| 5 | 2015 | 99214 | 60 | |
| 6 | 2015 | 99215 | 99 | 53 |
| 7 | 2015 | 99216 | 78 | |
Output :
Return RVU = 12 for CPT 99212
Return RVU = 59 for CPT 99213
Return RVU = 60 for CPT 99214
Return RVU = 99 for CPT 99215
A CPT can have a MOD of 26, TC, 53, or NULL. My SQL needs to check for 26 first and if there is a 26 then return the RVU for that row, if not 26 then whatever else is left.
Worded differently: If a CPT does not have a MOD 26, then that CPT will only have one possible other MOD to choose from. If a CPT has a MOD 26 it will always have an accompanying TC and NULL MOD. If the CPT does not have a 26 MOD then I need to grab whatever RVU value is available regardless of the MOD. So the order of operations is to check for 26 first and if there, return RVU for that row, if no 26 then return the only possible RVU choice for that CPT.
You can use row_number() function with conditional ordering :
select top (1) with ties *
from table t
order by row_number() over (partition by cpt
order by (case when mod = '26' then 0 else 1 end)
);
Use row_number(). I think the prioritization is as follows:
select t.*
from (select t.*,
row_number() over (partition by cpt
order by (case mod when '26' then 1 when 2 end)
) as seqnum
from t
) t
where seqnum = 1;
You could do a self-join to get CPTs with a 26 mod in a separate virtual table.
Sample data creation:
declare #Data table
( id int identity
,[year] int default 2015
,CPT nchar(5)
,RVU nchar(2)
,[MOD] nchar(2)
)
insert into #Data
(CPT, RVU, [MOD])
values
('99212', '12', '26'),
('99212', '23', 'TC'),
('99212', '56', null),
('99213', '59', '53'),
('99214', '60', null),
('99215', '99', '53'),
('99216', '78', null)
Query:
select
Data.CPT
,case
when Is26.CPT is not null then Is26.RVU
else Data.RVU
end RVU
from #Data Data
left join #Data Is26 on
Is26.CPT = Data.CPT
and Is26.[MOD] = '26'
group by
Data.CPT
,case
when Is26.CPT is not null then Is26.RVU
else Data.RVU
end

SQL Server - Insert lines with null values when month doesn't exist

I have a table like this one:
Yr | Mnth | W_ID | X_ID | Y_ID | Z_ID | Purchases | Sales | Returns |
2015 | 10 | 1 | 5210 | 1402 | 2 | 1000.00 | etc | etc |
2015 | 12 | 1 | 5210 | 1402 | 2 | 12000.00 | etc | etc |
2016 | 1 | 1 | 5210 | 1402 | 2 | 1000.00 | etc | etc |
2016 | 3 | 1 | 5210 | 1402 | 2 | etc | etc | etc |
2014 | 3 | 9 | 880 | 2 | 7 | etc | etc | etc |
2014 | 12 | 9 | 880 | 2 | 7 | etc | etc | etc |
2015 | 5 | 9 | 880 | 2 | 7 | etc | etc | etc |
2015 | 7 | 9 | 880 | 2 | 7 | etc | etc | etc |
For each combination of (W, X, Y, Z) I would like to insert the months that don't appear in the table and are between the first and last month.
In this example, for combination (W=1, X=5210, Y=1402, Z=2), I would like to have additional rows for 2015/11 and 2016/02, where Purchases, Sales and Returns are NULL. For combination (W=9, X=880, Y=2, Z=7) I would like to have additional rows for months between 2014/4 and 2014/11, 2015/01 and 2015/04, 2016/06.
I hope I have explained myself correctly.
Thank you in advance for any help you can provide.
The process is rather cumbersome in this case, but quite possible. One method uses a recursive CTE. Another uses a numbers table. I'm going to use the latter.
The idea is:
Find the minimum and maximum values for the year/month combination for each set of ids. For this, the values will be turned into months since time 0 using the formula year*12 + month.
Generate a bunch of numbers.
Generate all rows between the two values for each combination of ids.
For each generated row, use arithmetic to re-extract the year and month.
Use left join to bring in the original data.
The query looks like:
with n as (
select row_number() over (order by (select null)) - 1 as n -- start at 0
from master.spt_values
),
minmax as (
select w_id, x_id, y_id, z_id, min(yr*12 + mnth) as minyyyymm,
max(yr*12 + mnth) as maxyyyymm
from t
group by w_id, x_id, y_id, z_id
),
wxyz as (
select minmax.*, minmax.minyyyymm + n.n,
(minmax.minyyyymm + n.n) / 12 as yyyy,
((minmax.minyyyymm + n.n) % 12) + 1 as mm
from minmax join
n
on minmax.minyyyymm + n.n <= minmax.maxyyyymm
)
select wxyz.yyyy, wxyz.mm, wxyz.w_id, wxyz.x_id, wxyz.y_id, wxyz.z_id,
<columns from t here>
from wxyz left join
t
on wxyz.w_id = t.w_id and wxyz.x_id = t.x_id and wxyz.y_id = t.y_id and
wxyz.z_id = t.z_id and wxyz.yyyy = t.yr and wxyz.mm = t.mnth;
Thank you for your help.
Your solution works, but I noticed it is not very good in terms of performance, but meanwhile I have managed to get a solution for my problem.
DECLARE #start_date DATE, #end_date DATE;
SET #start_date = (SELECT MIN(EOMONTH(DATEFROMPARTS(Yr , Mnth, 1))) FROM Table_Input);
SET #end_date = (SELECT MAX(EOMONTH(DATEFROMPARTS(Yr , Mnth, 1))) FROM Table_Input);
DECLARE #tdates TABLE (Period DATE, Yr INT, Mnth INT);
WHILE #start_date <= #end_date
BEGIN
INSERT INTO #tdates(PEriod, Yr, Mnth) VALUES(#start_date, YEAR(#start_date), MONTH(#start_date));
SET #start_date = EOMONTH(DATEADD(mm,1,DATEFROMPARTS(YEAR(#start_date), MONTH(#start_date), 1)));
END
DECLARE #pks TABLE (W_ID NVARCHAR(50), X_ID NVARCHAR(50)
, Y_ID NVARCHAR(50), Z_ID NVARCHAR(50)
, PerMin DATE, PerMax DATE);
INSERT INTO #pks (W_ID, X_ID, Y_ID, Z_ID, PerMin, PerMax)
SELECT W_ID, X_ID, Y_ID, Z_ID
, MIN(EOMONTH(DATEFROMPARTS(Ano, Mes, 1))) AS PerMin
, MAX(EOMONTH(DATEFROMPARTS(Ano, Mes, 1))) AS PerMax
FROM Table1
GROUP BY W_ID, X_ID, Y_ID, Z_ID;
INSERT INTO Table_Output(W_ID, X_ID, Y_ID, Z_ID
, ComprasLiquidas, RTV, DevManuais, ComprasBrutas, Vendas, Stock, ReceitasComerciais)
SELECT TP.DB, TP.Ano, TP.Mes, TP.Supplier_Code, TP.Depart_Code, TP.BizUnit_Code
, TA.ComprasLiquidas, TA.RTV, TA.DevManuais, TA.ComprasBrutas, TA.Vendas, TA.Stock, TA.ReceitasComerciais
FROM
(
SELECT W_ID, X_ID, Y_ID, Z_ID
FROM #tdatas CROSS JOIN #pks
WHERE Period BETWEEN PerMin And PerMax
) AS TP
LEFT JOIN Table_Input AS TA
ON TP.W_ID = TA.W_ID AND TP.X_ID = TA.X_ID AND TP.Y_ID = TA.Y_ID
AND TP.Z_ID = TA.Z_ID
AND TP.Yr = TA.Yr
AND TP.Mnth = TA.Mnth
ORDER BY TP.W_ID, TP.X_ID, TP.Y_ID, TP.Z_ID, TP.Yr, TP.Mnth;
I do the following:
Get the Min and Max date of the entire table - #start_date and #end_date variables;
Create an auxiliary table with all dates between Min and Max - #tdates table;
Get all the combinations of (W_ID, X_ID, Y_ID, Z_ID) along with the min and max dates of that combination - #pks table;
Create the cartesian product between #tdates and #pks, and in the WHERE clause I filter the results between the Min and Max of the combination;
Compute a LEFT JOIN of the cartesian product table with the input data table.

Summing By Count

I'm trying to create a Summation based on the Count number for a particular column. If you looks at the last line in the Select below you'll see that I tried implementing a CASE statement. However, it produces all NULL values. Which I believe I understand why (each row has a unique set of values) but I'm not sure how to fix my problem.
SELECT
TotalFilesProduced.ReviewDate,
TotalFilesProduced.FileReviewedByUserID,
TotalFilesProduced.FileSource,
TotalFilesProduced.FilesIndexed TotalIndexed,
TotalFilesProduced.FileNumberofPages TotalFileNumberofPages,
TotalFilesProduced.FilesProduced,
CASE WHEN COUNT(DISTINCT FileReviewedByUserID) > 1 THEN SUM(TotalFilesProduced.FilesIndexed) END
FROM
(SELECT
CAST(ibfp.FileReviewedDate AS DATE) ReviewDate,
ibfp.FileReviewedByUserID,
FileSource,
COUNT(*) FilesProduced,
COUNT(DISTINCT ibf.InboundFileID) FilesIndexed,
SUM(CASE WHEN ibfp.FromPage = ibfp.ToPage THEN 1
ELSE ibfp.ToPage-ibfp.FromPage + 1 END) [FileNumberofPages]
FROM
dbo.InboundFilePartitions ibfp
INNER JOIN dbo.InboundFiles ibf ON ibfp.InboundFileID = ibf.InboundFileID
WHERE
CAST(ibfp.FileReviewedDate AS DATE) >= '10/22/2014'
and CAST(ibfp.FileReviewedDate AS DATE) <= '10/22/2014'
and ibf.ProjectID in (110)
GROUP BY
CAST(ibfp.FileReviewedDate AS DATE),
ibfp.FileReviewedByUserID,
FileSource
) TotalFilesProduced
GROUP BY
TotalFilesProduced.ReviewDate,
TotalFilesProduced.FileReviewedByUserID,
TotalFilesProduced.FileSource,
TotalFilesProduced.FilesIndexed,
TotalFilesProduced.FileNumberofPages,
TotalFilesProduced.FilesProduced
Here is an example for further clarification - here the UserID 1036 producing a NULL is fine since it appear only once but for 804 - I would like to sum the TotalIndexed column so the NULL area should read 139 (for both instances that 804 appears)
ReviewDate | FilereviewedByUserID | FileSource | TotalIndexed | TotalFileNumberofPages | FilesProduced | (No Column Name) /*My Sum*/
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 804 | 1 | 1 | 67 | 1 | NULL
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 1036 | 1 | 1 | 17 | 1 | NULL
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 804 | 2 | 138 | 3322 | 184 | NULL
As stated in the comment
This will always be false
CASE WHEN COUNT(DISTINCT FileReviewedByUserID) > 1
Because of
GROUP BY ibfp.FileReviewedByUserID
And you have some other strange stuff
CAST(ibfp.FileReviewedDate AS DATE) >= '10/22/2014'
and CAST(ibfp.FileReviewedDate AS DATE) <= '10/22/2014'
is the same as
CAST(ibfp.FileReviewedDate AS DATE) = '10/22/2014'
More strange stuff
SUM(CASE WHEN ibfp.FromPage = ibfp.ToPage THEN 1
ELSE ibfp.ToPage-ibfp.FromPage + 1 END) [FileNumberofPages]
is the same as
SUM(ibfp.ToPage-ibfp.FromPage + 1) [FileNumberofPages]
not sure what you are trying to do but a group by on a group by is not common