Compare getdate() with two different fields - sql

I have 2 tables:
T1 T2
id Effdate E_id DOB
-------------- ------------
1 20161212 2 1950-02-16 00:12:24
2 20130124 5 1978-01-16 10:14:30
I want to compare getdate() < Maxdate(effdate, DOB)?
I am getting datetime conversion error.
for example : getdate() < MAXDATE( 20161212 , 1950-02-16 00:12:24)
expected result should be from table T1:
id Effdate
--------------
1 20161212

If id in both tables are correspondent on id = E_id you can UNION them and GROUP BY id:
;WITH T1 AS (
SELECT 1 id,
CAST('20161212' as varchar(10)) Effdate
UNION ALL
SELECT 2,
'20130124'
), T2 AS (
SELECT 1 E_id,
CAST('1950-02-16 00:12:24' as datetime) DOB
UNION ALL
SELECT 2,
'1978-01-16 10:14:30'
)
SELECT id,
MAX(CAST(Effdate as datetime)) as MD
FROM (
SELECT *
FROM T1
UNION ALL
SELECT *
FROM T2
) t
GROUP BY id
HAVING MAX(CAST(Effdate as datetime)) >= GETDATE()
Will bring you expected result

Related

select distinct list of ids from table with earliest value in same table

I have the following table,
SDate Id Balance
2016-01-01 ABC 3
2016-01-01 DEF 7
2016-01-01 GHI 2
2016-02-01 ABC 6
2016-02-01 DEF 4
2016-02-01 GHI 8
2016-02-01 XYZ 12
I need to write a query that gives me a distinct list of Id's over a date range (so in this example SDate >= '2016-01-01' and SDate <= '2016-02-01') but also give me the earliest balance so the result from the table above I would like to see is,
Id Balance
ABC 3
DEF 7
GHI 2
XYZ 12
Is this possible?
UPDATE
Sorry I should have specified that for each date the Id is unique.
You can do this with a derived table that first works out the minimum SDate value for each Id value. Using this you then join back to your original table to find the Balance for the row that matches those values:
declare #t table(SDate date,Id nvarchar(3),Balance int);
insert into #t values ('2016-01-01','ABC',3),('2016-01-01','DEF',7),('2016-01-01','GHI',2),('2016-02-01','ABC',6),('2016-02-01','DEF',4),('2016-02-01','GHI',8),('2016-02-01','XYZ',12);
declare #StartDate date = '20160101';
declare #EndDate date = '20160201';
with d as
(
select Id
,min(SDate) as MinSDate
from #t
where SDate between #StartDate and #EndDate
group by id
)
select d.Id
,t.Balance
from d
inner join #t t
on(d.Id = t.Id
and d.MinSDate = t.SDate
);
Output:
Id | Balance
----+--------
ABC | 3
DEF | 7
GHI | 2
XYZ | 12
This should be possible with a window function - all you have to do is
partition by id
assign a row number, and
select the top row for each id
Example:
select id,
balance
from (
select id,
balance,
row_number() over( partition by id order by SDate ) as row_num
from table1
where SDate between '2016-01-01' and '2016-02-01'
) as a
where row_num = 1
Note: the advantage of this method is it is a lot more flexible. Say you wanted the 2 oldest records, you could just change to where row_num <= 2.
Analytic row_number() should be the fastest
select *
from (
select
t.*,
row_number() over (partition by Id order by SDate) rn
from your_table t
) t where rn = 1;
You can achieve this with a self join, which may not be the fastest or most elegant solution:
CREATE TABLE #SOPostSample
(
SDate DATE ,
Id NVARCHAR(5) ,
Balance INT
);
INSERT INTO #SOPostSample
( SDate, Id, Balance )
VALUES ( '2016-01-01', 'ABC', 3 ),
( '2016-01-01', 'DEF', 7 ),
( '2016-01-01', 'GHI', 2 ),
( '2016-02-01', 'ABC', 6 ),
( '2016-02-01', 'DEF', 4 ),
( '2016-02-01', 'GHI', 8 ),
( '2016-02-01', 'XYZ', 12 );
SELECT t1.Id ,
MIN(t2.Balance) Balance
FROM #SOPostSample t1
INNER JOIN #SOPostSample t2 ON t1.Id = t2.Id
GROUP BY t1.Id ,
t2.SDate
HAVING t2.SDate = MIN(t1.SDate);
DROP TABLE #SOPostSample;
Produces:
id Balance
============
ABC 3
DEF 7
GHI 2
XYZ 12
This works for the sample data, but please test with more data as I just wrote it quickly.
This should work, Top 1 just inserted for safety, should not be needed if SDate and Id are unique in combination
SELECT o.Id ,
( SELECT TOP 1
Balance
FROM tbl
WHERE Id = o.Id
AND SDate = MIN(o.SDate)
) Balance
FROM tbl o
GROUP BY Id
HAVING sDate BETWEEN '20160101' AND '20160201';
You can use sub-query
SELECT Id ,
( SELECT TOP 1
Balance
FROM [TableName] AS T1
WHERE T1.Id = [TableName].Id
ORDER BY SDate
) AS Balance
FROM [TableName]
GROUP BY Id;

how to return duplicate rows if date difference is equal or more than 4 days or 96 hours

I have to fetch duplicate record
if date difference between duplicate record is more than 96 hours or 4 days otherwise ignore the duplicate entry and return record with first entry or oldest date. My table look like this :
ID SDATE
----------- -----------------------
1 2016-04-13 14:54:18.983
1 2016-04-08 12:55:47.907
2 2016-04-13 14:54:18.983
3 2016-04-13 14:54:18.983
4 2016-04-13 14:54:18.983
5 2016-04-13 14:54:18.983
5 2016-04-11 12:55:47.907
6 2016-04-13 14:54:18.983
6 2016-04-13 14:54:18.983
Expected result:
ID SDATE
----------- -----------------------
1 2016-04-13 14:54:18.983
1 2016-04-08 12:55:47.907
2 2016-04-13 14:54:18.983
3 2016-04-13 14:54:18.983
4 2016-04-13 14:54:18.983
5 2016-04-11 12:55:47.907
6 2016-04-13 14:54:18.983
i tried following query but it is not working.
WITH tt AS (
SELECT 1 as ID, GETDATE() as SDATE
UNION ALL
SELECT 1 as ID, '2016-04-09 12:55:47.907' as SDATE
UNION ALL
SELECT 2 as ID, GETDATE() as SDATE
UNION ALL
SELECT 3 as ID, GETDATE() as SDATE
UNION ALL
SELECT 4 as ID, GETDATE() as SDATE
UNION ALL
SELECT 5 as ID, GETDATE() as SDATE
UNION ALL
SELECT 5 as ID, '2016-04-11 12:55:47.907' as SDATE
UNION ALL
SELECT 6 as ID, GETDATE() as SDATE
UNION ALL
SELECT 6 as ID, GETDATE() as SDATE
)
SELECT MIN(SDATE) as SDATE, ID FROM tt as tbl
GROUP BY ID, DATEADD(HH, DATEDIFF(HH,0,SDATE) + 96,0)
The below query returns the expected result, added the inline comments:
-- Simply grouping each ID and get unique row with minimum date
SELECT MIN(SDATE) [SDate], ID
FROM tt
GROUP BY ID
UNION
-- Get the row with each ID's difference is more than 96 hours
SELECT D.MaxDate [SDate], D.ID
FROM (
SELECT MIN(SDATE) [MinDate], MAX(SDATE) [MaxDate], ID
FROM tt
GROUP BY ID
) D
WHERE DATEDIFF(HH, D.MinDate, D.MaxDate) >= 96
Please try below query, I have tested it is working fine.
in ignore columns you can change period (HH or DAY)
-- drop table #temptbl
WITH tt AS (
SELECT 1 as ID, GETDATE() as SDATE
UNION ALL
SELECT 1 as ID, '2016-04-09 12:55:47.907' as SDATE
UNION ALL
SELECT 2 as ID, GETDATE() as SDATE
UNION ALL
SELECT 3 as ID, GETDATE() as SDATE
UNION ALL
SELECT 4 as ID, GETDATE() as SDATE
UNION ALL
SELECT 5 as ID, GETDATE() as SDATE
UNION ALL
SELECT 5 as ID, '2016-04-11 12:55:47.907' as SDATE
UNION ALL
SELECT 6 as ID, GETDATE() as SDATE
UNION ALL
SELECT 6 as ID, GETDATE() as SDATE
)
SELECT Id,SDATE,case when DATEDIFF(HH,SDATE,GETDATE()) >94 THEN 0 else 1 end AS ignore,
ROW_NUMBER() OVER ( PARTITION BY tt.ID ORDER BY tt.SDATE desc ) as Rowid
INTO #temptbl
FROM tt
SELECT Id, sdate from #temptbl
WHERE (#temptbl.ignore = 0) or (#temptbl.Rowid = 1)
declare #table table
(
ID int, SDATE datetime)
insert into #table
(
ID ,SDATE )
values
(1,'2016-04-13 14:54:18'),
(1,'2016-04-08 12:55:47'),
(2,'2016-04-13 14:54:18'),
(3,'2016-04-13 14:54:18'),
(4,'2016-04-13 14:54:18'),
(5,'2016-04-13 14:54:18'),
(5,'2016-04-11 12:55:47'),
(6,'2016-04-13 14:54:18'),
(6,'2016-04-13 14:54:18')
;with cte as
(
select id,min(sdate) mindate,max(sdate) maxdate, datediff(dd,min(sdate),max(sdate)) daysdiff,count(*) as Dups
from #table
group by id
)
select cte.id, t.sdate
from cte
join #table t on t.id = cte.id
where cte.dups > 1 and cte.daysdiff > 4
union all
select cte.id,
mindate
from cte
where (cte.dups > 1 and cte.daysdiff <= 4) or
cte.dups = 1

Is it possible to write a sql query that is grouped based on a running total of a column?

It would be easier to explain with an example. Suppose I wanted to get at most 5 items per group.
My input would be a table looking like this:
Item Count
A 2
A 3
A 3
B 4
B 4
B 5
C 1
And my desired output would look like this:
Item Count
A 5
A>5 3
B 4
B>5 9
C 1
An alternative output that I could also work with would be
Item Count RunningTotal
A 2 2
A 3 5
A 3 8
B 4 4
B 4 8
B 5 13
C 1 1
I can use ROW_NUMBER() to get the top X records in each group, however my requirement is to get the top X items for each group, not X records. My mind is drawing a blank as to how to do this.
declare #yourTable table (item char(1), [count] int)
insert into #yourTable
select 'A', 2 union all
select 'A', 3 union all
select 'A', 3 union all
select 'B', 4 union all
select 'B', 4 union all
select 'B', 5 union all
select 'C', 1
;with cte(item, count, row) as (
select *, row_number() over ( partition by item order by item, [count])
from #yourTable
)
select t1.Item, t1.Count, sum(t2.count) as RunningTotal from cte t1
join cte t2 on t1.item = t2.item and t2.row <= t1.row
group by t1.item, t1.count, t1.row
Result:
Item Count RunningTotal
---- ----------- ------------
A 2 2
A 3 5
A 3 8
B 4 4
B 4 8
B 5 13
C 1 1
Considering the clarifications from your comment, you should be able to produce the second kid of output from your post by running this query:
select t.Item
, t.Count
, (select sum(tt.count)
from mytable tt
where t.item=tt.item and (tt.creating_user_priority < t.creating_user_priority or
( tt.creating_user_priority = t.creating_user_priority and tt.created_date < t.createdDate))
) as RunningTotal
from mytable t
declare #yourTable table (item char(1), [count] int)
insert into #yourTable
select 'A', 2 union all
select 'A', 3 union all
select 'A', 3 union all
select 'B', 4 union all
select 'B', 4 union all
select 'B', 5 union all
select 'C', 1
;with cte(item, count, row) as (
select *, row_number() over ( partition by item order by item, [count])
from #yourTable
)
select t1.row, t1.Item, t1.Count, sum(t2.count) as RunningTotal
into #RunTotal
from cte t1
join cte t2 on t1.item = t2.item and t2.row <= t1.row
group by t1.item, t1.count, t1.row
alter table #RunTotal
add GrandTotal int
update rt
set GrandTotal = gt.Total
from #RunTotal rt
left join (
select Item, sum(Count) Total
from #RunTotal rt
group by Item) gt
on rt.Item = gt.Item
select Item, max(RunningTotal)
from #RunTotal
where RunningTotal <= 5
group by Item
union
select a.Item + '>5', total - five
from (
select Item, max(GrandTotal) total
from #RunTotal
where GrandTotal > 5
group by Item
) a
left join (
select Item, max(RunningTotal) five
from #RunTotal
where RunningTotal <= 5
group by Item
) b
on a.Item = b.Item
I've updated the accepted answer and got your desired result.
SELECT Item, SUM(Count)
FROM mytable t
GROUP BY Item
HAVING SUM(Count) <=5
UNION
SELECT Item, 5
FROM mytable t
GROUP BY Item
HAVING SUM(Count) >5
UNION
SELECT t2.Item + '>5', Sum(t2.Count) - 5
FROM mytable t2
GOUP BY Item
HAVING SUM(Count) > 5
ORDER BY 1, 2
select 'A' as Name, 2 as Cnt
into #tmp
union all select 'A',3
union all select 'A',3
union all select 'B',4
union all select 'B',4
union all select 'B',5
union all select 'C',1
select Name, case when sum(cnt) > 5 then 5 else sum(cnt) end Cnt
from #tmp
group by Name
union
select Name+'>5', sum(cnt)-5 Cnt
from #tmp
group by Name
having sum(cnt) > 5
Here is what I have so far. I know it's not complete but... this should be a good starting point.
I can get your second output by using a temp table and an update pass:
DECLARE #Data TABLE
(
ID INT IDENTITY(1,1) PRIMARY KEY
,Value VARCHAR(5)
,Number INT
,Total INT
)
INSERT INTO #Data (Value, Number) VALUES ('A',2)
INSERT INTO #Data (Value, Number) VALUES ('A',3)
INSERT INTO #Data (Value, Number) VALUES ('A',3)
INSERT INTO #Data (Value, Number) VALUES ('B',4)
INSERT INTO #Data (Value, Number) VALUES ('B',4)
INSERT INTO #Data (Value, Number) VALUES ('B',5)
INSERT INTO #Data (Value, Number) VALUES ('C',1)
DECLARE
#Value VARCHAR(5)
,#Count INT
UPDATE #Data
SET
#Count = Total = CASE WHEN Value = #Value THEN Number + #Count ELSE Number END
,#Value = Value
FROM #Data AS D
SELECT
Value
,Number
,Total
FROM #Data
There may be better ways, but this should work.

Coalesce over Rows in MSSQL 2008,

I'm trying to determine the best approach here in MSSQL 2008.
Here is my sample data
TransDate Id Active
-------------------------
1/18 1pm 5 1
1/18 2pm 5 0
1/18 3pm 5 Null
1/18 4pm 5 1
1/18 5pm 5 0
1/18 6pm 5 Null
If grouped by Id and ordered by the TransDate, I want the last Non Null Value for the Active Column, and the MAX of TransDate
SELECT MAX(TransDate) AS TransDate,
Id,
--LASTNonNull(Active) AS Active
Here would be the results:
TransDate Id Active
---------------------
1/18 6pm 5 0
It would be like a Coalesce but over the rows, instead of two values/columns.
There would be many other columns that would also have this similiar method applied, so I really don't want to make a seperate join for each of the columns.
Any ideas?
I'd probably use a correlated sub query.
SELECT MAX(TransDate) AS TransDate,
Id,
(SELECT TOP (1) Active
FROM T t2
WHERE t2.Id = t1.Id
AND Active IS NOT NULL
ORDER BY TransDate DESC) AS Active
FROM T t1
GROUP BY Id
A way without
SELECT
Id,
MAX(TransDate) AS TransDate,
CAST(RIGHT(MAX(CONVERT(CHAR(23),TransDate,121) + CAST(Active AS CHAR(1))),1) AS BIT) AS Active,
/*You can probably figure out a more efficient thing to
compare than the above depending on your data. e.g.*/
CAST(MAX(DATEDIFF(SECOND,'19500101',TransDate) * CAST(10 AS BIGINT) + Active)%10 AS BIT) AS Active2
FROM T
GROUP BY Id
Or following the comments would cross apply work better for you?
WITH T (TransDate, Id, Active, SomeOtherColumn) AS
(
select GETDATE(), 5, 1, 'A' UNION ALL
select 1+GETDATE(), 5, 0, 'B' UNION ALL
select 2+GETDATE(), 5, null, 'C' UNION ALL
select 3+GETDATE(), 5, 1, 'D' UNION ALL
select 4+GETDATE(), 5, 0, 'E' UNION ALL
select 5+GETDATE(), 5, null,'F'
),
T1 AS
(
SELECT MAX(TransDate) AS TransDate,
Id
FROM T
GROUP BY Id
)
SELECT T1.TransDate,
Id,
CA.Active AS Active,
CA.SomeOtherColumn AS SomeOtherColumn
FROM T1
CROSS APPLY (SELECT TOP (1) Active, SomeOtherColumn
FROM T t2
WHERE t2.Id = T1.Id
AND Active IS NOT NULL
ORDER BY TransDate DESC) CA
This example should help, using analytical functions Max() OVER and Row_Number() OVER
create table tww( transdate datetime, id int, active bit)
insert tww select GETDATE(), 5, 1
insert tww select 1+GETDATE(), 5, 0
insert tww select 2+GETDATE(), 5, null
insert tww select 3+GETDATE(), 5, 1
insert tww select 4+GETDATE(), 5, 0
insert tww select 5+GETDATE(), 5, null
select maxDate as Transdate, id, Active
from (
select *,
max(transdate) over (partition by id) maxDate,
ROW_NUMBER() over (partition by id
order by case when active is not null then 0 else 1 end, transdate desc) rn
from tww
) x
where rn=1
Another option, quite expensive, would be doing it through XML. For educational purposes only
select
ID = n.c.value('#id', 'int'),
trandate = n.c.value('(data/transdate)[1]', 'datetime'),
active = n.c.value('(data/active)[1]', 'bit')
from
(select xml=convert(xml,
(select id [#id],
( select *
from tww t
where t.id=tww.id
order by transdate desc
for xml path('data'), type)
from tww
group by id
for xml path('node'), root('root'), elements)
)) x cross apply xml.nodes('root/node') n(c)
It works on the principle that the XML generated has each record as a child node of the ID. Null columns have been omitted, so the first column found using xpath (child/columnname) is the first non-null value similar to COALESCE.
You could use a subquery:
SELECT MAX(TransDate) AS TransDate
, Id
, (
SELECT TOP 1 t2.Active
FROM YourTable t2
WHERE t1.id = t2.id
and t2.Active is not null
ORDER BY
t2.TransDate desc
)
FROM YourTable t1
I created a temp table named #temp to test my solution, and here is what I came up with:
transdate id active
1/1/2011 12:00:00 AM 5 1
1/2/2011 12:00:00 AM 5 0
1/3/2011 12:00:00 AM 5 null
1/4/2011 12:00:00 AM 5 1
1/5/2011 12:00:00 AM 5 0
1/6/2011 12:00:00 AM 5 null
1/1/2011 12:00:00 AM 6 2
1/2/2011 12:00:00 AM 6 3
1/3/2011 12:00:00 AM 6 null
1/4/2011 12:00:00 AM 6 2
1/5/2011 12:00:00 AM 6 null
This query...
select max(a.transdate) as transdate, a.id, (
select top (1) b.active
from #temp b
where b.active is not null
and b.id = a.id
order by b.transdate desc
) as active
from #temp a
group by a.id
Returns these results.
transdate id active
1/6/2011 12:00:00 AM 5 0
1/5/2011 12:00:00 AM 6 2
Assuming a table named "test1", how about using ROW_NUMBER, OVER and PARTITION BY?
SELECT transdate, id, active FROM
(SELECT transdate, ROW_NUMBER() OVER(PARTITION BY id ORDER BY transdate desc) AS rownumber, id, active
FROM test1
WHERE active is not null) a
WHERE a.rownumber = 1

SQL Server query without using loops

I have a Payment table that looks a little like this:
Id (int identity)
CustomerId (int)
PaymentDate (SmallDateTime)
Now I want to write a query that will find those customers that have made three payments within a period of three months. Given the following data:
Id CustomerId PaymentDate (YYYY-MM-DD)
------------------------------------------
1 1 2010-01-01
2 1 2010-02-01
3 1 2010-03-01
4 1 2010-06-01
5 2 2010-04-01
6 2 2010-05-01
7 2 2010-06-01
8 2 2010-07-01
I would like to produce the following result:
CustomerId LastPaymentDateInPeriod
-------------------------------------
1 2010-03-01
2 2010-07-01
Where LastPaymentDateInPeriod is the PaymentDate with the highest value within a three-month period. If there is more than one three-month period for a given customer it would have to return the highest value from the most recent period (this is what I tried to illustrate for customer 2 in the above example). Note that three payments on three consecutive days would also meet the criteria. The payments just have to fall within a three-month period.
I know how to do this with a cursor and a lot of smaller queries but this is slow (and, I've come to understand, should only be a last resort). So do any of you SqlServer geniuses know how to do this with a query?
Thanks in advance.
This should do the job:
select
CustomerID,
max(LastPaymentDateInPeriod) as LastPaymentDateInPeriod
from
(
select
LastPaymentInPeriod.CustomerID,
LastPaymentInPeriod.PaymentDate as LastPaymentDateInPeriod
from Payment LastPaymentInPeriod
inner join Payment RelatedPayment on
LastPaymentInPeriod.CustomerID = RelatedPayment.CustomerID and
LastPaymentInPeriod.PaymentDate > RelatedPayment.PaymentDate and
datediff(m, RelatedPayment.PaymentDate, LastPaymentInPeriod.PaymentDate) < 3
group by
LastPaymentInPeriod.CustomerID,
LastPaymentInPeriod.PaymentDate
having
count(*) > 1
) as PaymentPeriods
group by
CustomerID
update: I've tested this now and it seems to work for #Martin's data
update2: If it's a requirement that Jan 31 and Apr 1 should be considered as less than 3 months apart then the DATEDIFF function call can be replaced with something like this:
create function fn_monthspan
(
#startdate datetime,
#enddate datetime
)
returns int
as
begin
return datediff(m, #startdate, #enddate) - case when datepart(d, #startdate) > datepart(d, #enddate) then 1 else 0 end
end
Bit of a rushed job as I'm off out.
declare #T TABLE
(
Id int,
CustomerId int,
PaymentDate SmallDateTime
)
insert into #T
SELECT 1, 1,'2010-01-01' UNION ALL
SELECT 2, 1,'2010-02-01' UNION ALL
SELECT 3, 1,'2010-03-01' UNION ALL
SELECT 4, 1,'2010-06-01' UNION ALL
SELECT 5, 2,'2010-04-01' UNION ALL
SELECT 6, 2,'2010-05-01' UNION ALL
SELECT 7, 2,'2010-06-01' UNION ALL
SELECT 8, 2,'2010-07-01'
;with CTE1 AS
(
SELECT Id, CustomerId, PaymentDate, ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY PaymentDate) RN
FROM #T
), CTE2 AS
(
SELECT C1.Id, C1.CustomerId, MAX(C2.PaymentDate) AS LastPaymentDateInPeriod
FROM CTE1 C1 LEFT JOIN CTE1 C2 ON C1.CustomerId = C2.CustomerId AND C2.RN BETWEEN C1.RN AND C1.RN + 2 and C2.PaymentDate <=DATEADD(MONTH,3,C1.PaymentDate)
GROUP BY C1.Id, C1.CustomerId
HAVING COUNT(*)=3
)
SELECT CustomerId, MAX(LastPaymentDateInPeriod) LastPaymentDateInPeriod
FROM CTE2
GROUP BY CustomerId
This gives you all three payments within a 3 month span.
;
WITH CustomerPayments AS
(
SELECT 1 Id, 1 CustomerId, Convert (DateTime, '2010-01-01') PaymentDate
UNION SELECT 2, 1, '2010-02-01'
UNION SELECT 3, 1, '2010-03-01'
UNION SELECT 4, 1, '2010-06-01'
UNION SELECT 5, 2, '2010-04-01'
UNION SELECT 6, 2, '2010-05-01'
UNION SELECT 7, 2, '2010-06-01'
UNION SELECT 8, 2, '2010-07-01'
UNION SELECT 9, 3, '2010-07-01'
UNION SELECT 10, 3, '2010-07-01'
),
FirstPayment AS
(
SELECT Id, CustomerId, PaymentDate
FROM CustomerPayments
where Id IN
(
SELECT Min (Id) Id
FROM CustomerPayments
Group by CustomerId
)
),
SecondPayment AS
(
SELECT Id, CustomerId, PaymentDate
FROM CustomerPayments
where Id IN
(
SELECT Min (Id) Id
FROM CustomerPayments
WHERE ID NOT IN
(
SELECT ID
from FirstPayment
)
Group by CustomerId
)
),
ThirdPayment AS
(
SELECT Id, CustomerId, PaymentDate
FROM CustomerPayments
where Id IN
(
SELECT Min (Id) Id
FROM CustomerPayments
WHERE ID NOT IN
(
SELECT ID
from FirstPayment
UNION
SELECT ID
from SecondPayment
)
Group by CustomerId
)
)
SELECT *
FROM
FirstPayment FP
Left JOIN SecondPayment SP
ON FP.CustomerId = SP.CustomerId
Left JOIN ThirdPayment TP
ON SP.CustomerId = TP.CustomerId
WHERE 1=1
AND SP.PaymentDate IS NOT NULL
AND TP.PaymentDate IS NOT NULL
AND ABS (DATEDIFF (mm, SP.PaymentDate, TP.PaymentDate)) <3
I thought of:
select customerId,max(PaymentDate) from payment where customerId in
(select case when count(*)<3 then null else customerId end as customerId from payment
where paymentdate>dateadd(month,-3,getdate()) group by customerId)
group by customerId;