February 26, 2009 at 6:57 am
Hi All,
I have a table that has more than 3 Million rows. I preferably do not want to do a RBAR 😀
Let me first put the Scripts in and then explain what I need.
CREATE TABLE [dbo].[TranTable](
[TranID] [int] NOT NULL,
[CustomerID] [int] NOT NULL,
[DateEntered] [datetime] NOT NULL,
[Amount] [float] NOT NULL,
[CreditDebit] [varchar](1) NOT NULL,
[Type] [varchar](50) NOT NULL
) ON [PRIMARY]
GO
--Here is the sample insert script
insert into dbo.trantable
(TranID,CustomerID,Dateentered,Amount,CreditDebit,[Type])
Select 1, 1023,'01-Jan-2009 08:25:25',50.5,'C','Dep'
UNION ALL
Select 2, 1023,'02-Jan-2009 01:15:45',50.8,'D','With'
UNION ALL
Select 3, 1023,'05-Jan-2009 07:15:45',65.0,'C','Dep'
UNION ALL
Select 4, 1023,'05-Jan-2009 09:25:45',67.25,'D','With'
UNION ALL
Select 6, 1524,'12-Feb-2009 14:00:25',125.0,'C','Dep'
UNION ALL
Select 8, 1524,'13-Feb-2009 01:01:25',125.0,'D','With'
UNION ALL
Select 9, 1524,'16-Feb-2009 08:03:25',150.0,'C','Dep'
UNION ALL
Select 12, 1524,'16-Feb-2009 09:01:25',125.0,'D','With'
GO
If I do a select * from dbo.trantable This is what I get.
TranIDCustomerIDDateEnteredAmountCreditDebitType
110232009-01-01 08:25:25.00050.5CDep
210232009-01-02 01:15:45.00050.8DWith
310232009-01-05 07:15:45.00065CDep
410232009-01-05 09:25:45.00067.25DWith
615242009-02-12 14:00:25.000125CDep
815242009-02-13 01:01:25.000125DWith
915242009-02-16 08:03:25.000150CDep
1215242009-02-16 09:01:25.000125DWith
If you look at the data, you will see thee are two instances where there was a deposit one day and WithDrawal the next day. (TranID 1,2, 6,8). The other four records are Deposit and withdrawal the same day. I want to get only the TranID 1,2,6,8. That is the Deposit one day and the WithDrawal is the next day. Is this possible?
Thanks
Roy
PS : Sorry about the formatting of the output of Select *
-Roy
February 26, 2009 at 7:39 am
It is hard to join because there is a very loose relationship between the two records (no transaction id to link them). However, this might give you a good starting point:
SELECT t1.TranID AS FirstTrans,t2.TranID AS SecondTran
FROM
(
SELECT *,ROW_NUMBER() OVER(ORDER BY TranID ASC) AS Row_Num
FROM TranTable
) t1,
(
SELECT *,ROW_NUMBER() OVER(ORDER BY TranID ASC) AS Row_Num
FROM TranTable
) t2
WHERE t1.Row_Num+1 = t2.Row_Num
AND t1.Row_Num % 2 = 1
AND t2.Row_Num % 2 = 0
AND t1.CreditDebit = 'C'
AND t2.CreditDebit = 'D'
AND DAY(t1.DateEntered) = DAY(DATEADD(d,-1,t2.DateEntered))
AND t1.CustomerID = t2.CustomerID;
The basic concept is that I'm setting up a join based on the row number (joining a current row to the next row). The assumption is that for a given row, the debit will ALWAYS follow the credit transaction.
Cheers,
Brian
February 26, 2009 at 7:45 am
Thanks for the input. Unfortunately the Credit will not always follow a Debit. Maybe another Customer made a deposit between the Credit and Debit. Also maybe there is only a Credit and no Matching Debit for that customer. The money was used for something else.
I am going to see if I can work with your Base query and try to do something.
-Roy
February 26, 2009 at 7:49 am
I don't know how this will perform on large number of records (As row_number is used, the above query requires sort operation.)
But it works even if you have multiple debits and multiple credits in the same day.
[/code]
SELECT t.* FROM trantable t
INNER JOIN
(
SELECT agg.tranid as aggtranid,agg1.tranid as agg1tranid
FROM
(SELECT *,
row_number() over (partition by customerID,CreditDebit order by customerID,dateentered) rownum
FROM trantable)agg
INNER JOIN
(SELECT *,
row_number() over (partition by customerID,CreditDebit order by customerID,dateentered) rownum
FROM trantable)agg1
ON agg.rownum = agg1.rownum
AND agg.customerID = agg1.customerID
WHERE datediff(dd,agg.dateentered,agg1.dateentered) = 1
)Z
ON Z.aggtranid = t.tranid
OR Z.agg1tranid = t.tranid
[/code]
-Vikas Bindra
February 26, 2009 at 7:58 am
Try this:
select t1.*, t2.TranID
from dbo.TranTable t1
inner join dbo.TranTable t2
on t1.CustomerID = t2.CustomerID
and t2.Type = 'With'
and t1.Type = 'Dep'
and t2.DateEntered between
dateadd(day, datediff(day, 0, t1.DateEntered)+1, 0)
and
dateadd(day, datediff(day, 0, t1.DateEntered)+2, 0);
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
February 26, 2009 at 9:00 am
Thanks both of you for queries.
GSquared, I liked your method, It is simple. But here it runs into a small complication.
Let us say Customer 1023 Deposited one amount yesterday (TranID 1) and he also made a deposit today (tranID 3). He also did one withdrawal yesterday (tranID 2) and did another one today (tranID 4), then it will still link TranID 1 with tranID 4.
The TranID I am giving here is just an example and does not relate to the data inserted. I am sorry I missed this point when giving the sample data.
Vikas, Yours too has the same issue.
-Roy
February 26, 2009 at 9:32 am
Maybe this?
select t1.*, t2.TranID
from dbo.TranTable t1
inner join dbo.TranTable t2
on t1.CustomerID = t2.CustomerID
and t2.Type = 'With'
and t1.Type = 'Dep'
and t2.DateEntered between
dateadd(day, datediff(day, 0, t1.DateEntered)+1, 0)
and
dateadd(day, datediff(day, 0, t1.DateEntered)+2, 0)
where not exists(select * from dbo.TranTable t3
where t1.CustomerID = t3.CustomerID
and t3.Type = 'With'
and t3.DateEntered between
dateadd(day, datediff(day, 0, t1.DateEntered), 0)
and
dateadd(day, datediff(day, 0, t1.DateEntered)+1, 0));
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537February 26, 2009 at 9:42 am
select *
from #TranTable t1
inner join #TranTable t2
on t1.CustomerID = t2.CustomerID
and t2.Type = 'With'
and t1.Type = 'Dep'
and t2.DateEntered between
dateadd(day, datediff(day, 0, t1.DateEntered)+1, 0)
and
dateadd(day, datediff(day, 0, t1.DateEntered)+2, 0)
left outer join #TranTable t3
on t1.CustomerID = t3.CustomerID
and t1.Type = 'Dep'
and t3.Type = 'With'
and t3.DateEntered between
t1.DateEntered
and
dateadd(day, datediff(day, 0, t1.DateEntered)+1, 0)
where t3.tranid is null;
I tested it like this:
set nocount on;
go
if object_id(N'tempdb..#TranTable') is not null
drop table #TranTable;
CREATE TABLE #TranTable(
[TranID] [int] NOT NULL,
[CustomerID] [int] NOT NULL,
[DateEntered] [datetime] NOT NULL,
[Amount] [float] NOT NULL,
[CreditDebit] [varchar](1) NOT NULL,
[Type] [varchar](50) NOT NULL
) ON [PRIMARY]
GO
--Here is the sample insert script
insert into #trantable
(TranID,CustomerID,Dateentered,Amount,CreditDebit,[Type])
Select 1, 1023,'01-Jan-2009 08:25:25',50.5,'C','Dep'
UNION ALL
Select 2, 1023,'02-Jan-2009 01:15:45',50.8,'D','With'
UNION ALL
Select 3, 1023,'05-Jan-2009 07:15:45',65.0,'C','Dep'
UNION ALL
Select 4, 1023,'05-Jan-2009 09:25:45',67.25,'D','With'
UNION ALL
Select 6, 1524,'12-Feb-2009 14:00:25',125.0,'C','Dep'
UNION ALL
Select 8, 1524,'13-Feb-2009 01:01:25',125.0,'D','With'
UNION ALL
Select 9, 1524,'16-Feb-2009 08:03:25',150.0,'C','Dep'
UNION ALL
Select 12, 1524,'16-Feb-2009 09:01:25',125.0,'D','With'
UNION ALL
select 13, 1, '2/25/09 1 pm',1, 'C','Dep'
union all
select 14, 1, '2/25/09 1:30 pm',1,'D','With'
union all
select 15, 1, '2/26/09 1 am',1,'C','Dep'
union all
select 16, 1,'2/26/09 1:30 am',1,'D','With'
GO
select *
from #TranTable t1
inner join #TranTable t2
on t1.CustomerID = t2.CustomerID
and t2.Type = 'With'
and t1.Type = 'Dep'
and t2.DateEntered between
dateadd(day, datediff(day, 0, t1.DateEntered)+1, 0)
and
dateadd(day, datediff(day, 0, t1.DateEntered)+2, 0)
left outer join #TranTable t3
on t1.CustomerID = t3.CustomerID
and t1.Type = 'Dep'
and t3.Type = 'With'
and t3.DateEntered between
t1.DateEntered
and
dateadd(day, datediff(day, 0, t1.DateEntered)+1, 0)
where t3.tranid is null;
Transactions 13-16 fit the exception pattern you mentioned, and the query doesn't return them. Will that work?
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
February 26, 2009 at 10:06 am
That worked fine.... Thank You all for helping me out. Appreciate it very much. 🙂
Roy
-Roy
February 26, 2009 at 1:30 pm
You're welcome.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
February 26, 2009 at 9:22 pm
Roy Ernest (2/26/2009)
That worked fine.... Thank You all for helping me out. Appreciate it very much. 🙂Roy
How's the performance, Roy?
--Jeff Moden
Change is inevitable... Change for the better is not.
February 27, 2009 at 12:26 am
Roy Ernest (2/26/2009)
Thanks both of you for queries.But here it runs into a small complication.
Let us say Customer 1023 Deposited one amount yesterday (TranID 1) and he also made a deposit today (tranID 3). He also did one withdrawal yesterday (tranID 2) and did another one today (tranID 4), then it will still link TranID 1 with tranID 4.
Vikas, Yours too has the same issue.
My query doesn't relate transID1 with TransID4. Here is the sample code:
set nocount on;
go
if object_id(N'tempdb..#TranTable') is not null
drop table #TranTable;
CREATE TABLE #TranTable(
[TranID] [int] NOT NULL,
[CustomerID] [int] NOT NULL,
[DateEntered] [datetime] NOT NULL,
[Amount] [float] NOT NULL,
[CreditDebit] [varchar](1) NOT NULL,
[Type] [varchar](50) NOT NULL
) ON [PRIMARY]
GO
insert into #trantable
(TranID,CustomerID,Dateentered,Amount,CreditDebit,[Type])
Select 1, 1023,'01-Jan-2009 08:25:25',50.5,'C','Dep'
UNION ALL
Select 2, 1023,'01-Jan-2009 11:15:45',50.8,'D','With'
UNION ALL
Select 3, 1023,'02-Jan-2009 08:25:25',50.5,'C','Dep'
UNION ALL
Select 4, 1023,'02-Jan-2009 11:15:45',50.8,'D','With'
UNION ALL
Select 5, 1023,'05-Jan-2009 07:15:45',65.0,'C','Dep'
UNION ALL
Select 6, 1023,'06-Jan-2009 09:25:45',67.25,'D','With'
UNION ALL
Select 7, 1524,'12-Feb-2009 14:00:25',125.0,'C','Dep'
UNION ALL
Select 8, 1524,'13-Feb-2009 01:01:25',125.0,'D','With'
UNION ALL
Select 9, 1524,'16-Feb-2009 08:03:25',150.0,'C','Dep'
UNION ALL
Select 12, 1524,'16-Feb-2009 09:01:25',125.0,'D','With'
UNION ALL
select 13, 1, '2/25/09 1 pm',1, 'C','Dep'
union all
select 14, 1, '2/25/09 1:30 pm',1,'D','With'
union all
select 15, 1, '2/26/09 1 am',1,'C','Dep'
union all
select 16, 1,'2/26/09 1:30 am',1,'D','With'
GO
SELECT t.* FROM #TranTable t
INNER JOIN
(
SELECT agg.tranid as aggtranid,agg1.tranid as agg1tranid
FROM
(SELECT *,
row_number() over (partition by customerID,CreditDebit order by customerID,dateentered) rownum
FROM #TranTable)agg
INNER JOIN
(SELECT *,
row_number() over (partition by customerID,CreditDebit order by customerID,dateentered) rownum
FROM #TranTable)agg1
ON agg.rownum = agg1.rownum
AND agg.customerID = agg1.customerID
WHERE datediff(dd,agg.dateentered,agg1.dateentered) = 1
)Z
ON Z.aggtranid = t.tranid
OR Z.agg1tranid = t.tranid
-Vikas Bindra
February 27, 2009 at 6:03 am
Jeff Moden (2/26/2009)
Roy Ernest (2/26/2009)
That worked fine.... Thank You all for helping me out. Appreciate it very much. 🙂Roy
How's the performance, Roy?
Actually performance is not so bad. This is not going to be run every day. This was a one time query that I had to run to find out who all were abusing the fluctuating Currency Rate. So I had to run for the past 5 months data. I thought it would be worse. But since it was a one time shot, I did not mind and was much better than I expected.
Vikas, I have not checked yours yet. I will check it out today I will let you know if it was performing better.
-Roy
February 27, 2009 at 5:16 pm
Cool... thanks for the feedback, Roy.
--Jeff Moden
Change is inevitable... Change for the better is not.
February 27, 2009 at 7:05 pm
Hi Roy,
I may be bit late for your query, but hope even this code gives you the result you are expecting :).
Have a look on this and let me know whether it solves your problem...
SELECT * FROM TRANTABLE
WHERE TRANID NOT IN
(
SELECT CREDIT.TRANID FROM
(SELECT
TRANID, CUSTOMERID, CONVERT(VARCHAR(10), DATEENTERED, 110) DATEENTERED, CREDITDEBIT
FROM
TRANTABLE
WHERE
CREDITDEBIT = 'C') CREDIT,
(SELECT
TRANID, CUSTOMERID, CONVERT(VARCHAR(10), DATEENTERED, 110) DATEENTERED, CREDITDEBIT
FROM
TRANTABLE
WHERE
CREDITDEBIT = 'D') DEBIT
WHERE
CREDIT.DATEENTERED = DEBIT.DATEENTERED
AND CREDIT.CUSTOMERID = DEBIT.CUSTOMERID
)
AND TRANID NOT IN
(
SELECT DEBIT.TRANID FROM
(SELECT
TRANID, CUSTOMERID, CONVERT(VARCHAR(10), DATEENTERED, 110) DATEENTERED, CREDITDEBIT
FROM
TRANTABLE
WHERE
CREDITDEBIT = 'C') CREDIT,
(SELECT
TRANID, CUSTOMERID, CONVERT(VARCHAR(10), DATEENTERED, 110) DATEENTERED, CREDITDEBIT
FROM
TRANTABLE
WHERE
CREDITDEBIT = 'D') DEBIT
WHERE
CREDIT.DATEENTERED = DEBIT.DATEENTERED
AND CREDIT.CUSTOMERID = DEBIT.CUSTOMERID
)
This will give you the TRANID that has different DATEENTERED.
If you want to get the records that fall in same date, then you can use this ...
SELECT * FROM
(SELECT
TRANID, CUSTOMERID, CONVERT(VARCHAR(10), DATEENTERED, 110) DATEENTERED, CREDITDEBIT
FROM
TRANTABLE
WHERE
CREDITDEBIT = 'C') CREDIT,
(SELECT
TRANID, CUSTOMERID, CONVERT(VARCHAR(10), DATEENTERED, 110) DATEENTERED, CREDITDEBIT
FROM
TRANTABLE
WHERE
CREDITDEBIT = 'D') DEBIT
WHERE
CREDIT.DATEENTERED = DEBIT.DATEENTERED
AND CREDIT.CUSTOMERID = DEBIT.CUSTOMERID
I'm still trying to figure out some other logic 🙂 for your query. Hope I can get few more logic.
Regards,
Ashok S
Viewing 15 posts - 1 through 14 (of 14 total)
You must be logged in to reply to this topic. Login to reply