Identify repeating raws (loans) in sql - sql

I have a table like this:
Client Branch Amount Date
1 2 1500 1.1.14
1 2 1400 3.1.14
1 3 1500 1.1.14
1 4 300 7.1.14
1 5 1500 1.1.14
------------------------------
2 2 300 1.1.14
2 2 300 1.1.14
2 5 300 1.1.14
2 3 400 4.1.14
------------------------------
3 2 300 1.1.14
3 2 300 1.1.14
3 5 300 1.1.14
3 5 300 1.1.14
3 3 400 4.1.14
4 2 300 1.1.14
4 2 300 1.1.14
4 5 300 1.1.14
4 5 300 1.1.14
4 5 300 1.1.14
And my desired output should be like this:
Client Branch Amount Date Ind Loan_Distinct_Num
1 2 1500 1.1.14 0 1
1 2 1400 3.1.14 0 2
1 3 1500 1.1.14 1 1
1 4 300 7.1.14 0 3
1 5 1500 1.1.14 1 1
-------------------------------------------------
2 2 300 1.1.14 0 1
2 2 300 1.1.14 0 2
2 5 300 1.1.14 1 2
2 3 400 4.1.14 0 3
--------------------------------------------------
3 2 300 1.1.14 0 1
3 2 300 1.1.14 0 2
3 5 300 1.1.14 1 1
3 5 300 1.1.14 1 2
3 3 400 4.1.14 0 3
------------------------------------------------
4 2 300 1.1.14 0 1
4 2 300 1.1.14 0 2
4 5 300 1.1.14 1 1
4 5 300 1.1.14 1 2
4 5 300 1.1.14 0 3
So what am I trying to do? (Comment: Those records are just a sample data)
Well, those are the rules:
A client has moved from one branch to another in the same bank. The problem is that the branches were writing the data for him several times. I want to identify loans that are repeating. Two steps needed:
Step1 :
Assumption : Same_Amount + Same_Date + Diffrent Date ---> Ind = 1 on the records that are after the first raw.
How Ind field works?
For example:
In the partition for client = 1 the amount 1500 is reapting 3 times for same date and diffrent branches but only the two last records for this details will get a "1" value for Ind, the first will get Ind = 0 because it is not a repeting loan, it is the first time that a record with this amount and date appears in the data.
In case like client = 2 there were two records for branch = 2 and only one for branch = 5 so in this case I will assum that the last record for the branch = 2 was being repeted.
In case like client = 3 there were two records in branch = 2 and two records for branch = 5 so in this case i will assume that both of the loans from branch 2 was repeted.
In Case client = 4, well it will be the same like client 3 but there was another record but I will consider it a new one because I have no extra past loan to communicate with her.
Step 2: I want to create my own distinct loan number for each client
Any help on how to approach for solving this nor simple problem?
comment : sql-server 2008.

First - set up your data into a table. I've added an identity column ID, so we have something to order by - you specified in a comment that your data was in a specific order.
declare #data table (ID int identity(1,1), Client int, Branch int, Amount int, [Date] date);
insert into #data values
(1,2, 1500,'2014-01-01'),
(1,2, 1400,'2014-03-01'),
(1,3, 1500,'2014-01-01'),
(1,4, 300,'2014-07-01'),
(1,5, 1500,'2014-01-01'),
(2,2, 300,'2014-01-01'),
(2,2, 300,'2014-01-01'),
(2,5, 300,'2014-01-01'),
(2,3, 400,'2014-04-01'),
(3,2, 300,'2014-01-01'),
(3,2, 300,'2014-01-01'),
(3,5, 300,'2014-01-01'),
(3,5, 300,'2014-01-01'),
(3,3, 400,'2014-04-01'),
(4,2, 300,'2014-01-01'),
(4,2, 300,'2014-01-01'),
(4,5, 300,'2014-01-01'),
(4,5, 300,'2014-01-01'),
(4,5, 300,'2014-01-01');
Here is where we do the query:
--In the first cte, we take all the data, and partition it up into individual loans (partition by Client, Amount, Date).
with cte1 as (
select *, ROW_NUMBER() over (partition by Client, Amount, Date order by ID) as rowno from #data
), cte2 as (
--in this cte, we get a list of distinct loans. We will use another rownumber in a bit to find our Loan_Distinct_Num
select distinct Client, Amount, [Date] from #data
)
select cte1.Client, cte1.Branch, cte1.Amount, cte1.[Date]
-- If rowno = 1, it's the first instance of that combination
, case when rowno = 1 then 0 else 1 end as ind
, b.Loan_Distinct_Num
from cte1
left join (select cte2.*, ROW_NUMBER() over (partition by Client order by [Date]) as Loan_Distinct_Num
-- This is where our distinct loan number comes from
from cte2
) as b
on b.Client = cte1.Client and b.Amount = cte1.Amount and b.[Date] = cte1.[Date]
order by ID

Here's an answer if ind should only be 1 if exists a previous record with a different branch # (see row 7). Also, uses dense_rank to group loans by amount/date in loan_distinct_num. The logic seems more complex for that column - if this is a one-time fix, I might use a cursor to loop through the table and apply some more complex logic to populate that one column, rather than try to calculate it in a query.
-- sample data
declare #data table (ID int identity(1,1), Client int, Branch int, Amount int, [Date] date);
insert into #data values
(1,2, 1500,'2014-01-01'),
(1,2, 1400,'2014-03-01'),
(1,3, 1500,'2014-01-01'),
(1,4, 300,'2014-07-01'),
(1,5, 1500,'2014-01-01'),
(2,2, 300,'2014-01-01'),
(2,2, 300,'2014-01-01'),
(2,5, 300,'2014-01-01'),
(2,3, 400,'2014-04-01'),
(3,2, 300,'2014-01-01'),
(3,2, 300,'2014-01-01'),
(3,5, 300,'2014-01-01'),
(3,5, 300,'2014-01-01'),
(3,3, 400,'2014-04-01'),
(4,2, 300,'2014-01-01'),
(4,2, 300,'2014-01-01'),
(4,5, 300,'2014-01-01'),
(4,5, 300,'2014-01-01'),
(4,5, 300,'2014-01-01');
-- query
select client, branch, amount, date,
case when exists (select * from #data t2 where client = tbl.client and branch <> tbl.branch and amount = tbl.amount and date = tbl.date and id < tbl.id) then 1 else 0 end as ind,
DENSE_RANK() over (partition by client order by date, amount asc) as loan_disinct_num
from #data tbl
order by id;

Related

Create Transaction Query From Order And Store Table

I have a table called "Store" with this sample data:
CREATE TABLE Store (
StoreID int
, ProductID int
,Quantity float
)
insert into
Store (StoreID,ProductID,Quantity) values
(1,1,1000),
(2,1,1000),
(3,2,500),
(4,2,700),
(5,3,300),
(6,3,400);
and an Order table
CREATE TABLE [Order] (
OrderID int
, ProductID int
,OutputQuantity float
)
insert into
[Order] (OrderID,ProductID,OutputQuantity
) values
(1,1,500),
(2,1,250),
(3,1,500),
(4,2,250),
(5,2,300),
(6,2,300),
(7,3,400),
(8,3,300);
Take the quantity of each row from the order table and subtract it from the store table according to the first arrival and inventory and create the following table.
OrderID StoreID ProductID Quantity OrderID_Inventory
1 1 1 500 500
2 1 1 250 250
3 1 1 250 0
3 2 1 250 750
4 3 2 250 250
5 3 2 250 0
5 4 2 50 650
6 4 2 300 350
7 5 3 300 0
7 6 3 100 300
8 6 3 300 0

Merge single column of first record with respective to duplicate record in SQLServer

I have this data in sqlserver
ID Phone
1 100
1 200
2 300
2 300
3 400
3 500
3 600
I want output like this
ID Phone
1 100,200
1 200
2 300
2 300
3 400,500,600
3 500
3 600
;with cte
as
(select id,phone,
stuff((select distinct','+cast(phone as varchar(20))
from #valuee t2 where t1.id=t2.id
for xml path('')),1,1,'') as nwphone
from #valuee t1
)
select id,
case when 1=dense_rank() over (partition by id,nwphone order by phone)
then cast(nwphone as varchar(20)) else cast(phone as varchar(20)) end as phone
from
cte
Output:
id phone
1 100,200
1 200
2 300
2 300
3 400,500,600
3 500
3 600

SQL Server: SELECT value with multiple criteria

Looking for a SQL solution to the following problem
Return USER and NUMBER combination WHERE PRIORITY = MIN(PRIORITY) [NULL is equivalent to MAX(PRIORITY + 1)] ... in the case of ties in PRIORITY, break using lowest LINEITEM
FIELDS:
USER,
LINEITEM,
NUMBER,
PRIORITY
VALUES: ('X' signifies desired combination)
USER LINEITEM NUMBER PRIORITY
-------------------------------------
1 1 12345 NULL
1 2 23456 2
1 3 34567 1 X
2 1 9876 3
2 2 98765 1 X
2 3 12345 2
2 4 23456 1
3 1 23456 NULL X
3 2 12345 NULL
4 1 34567 NULL
4 2 45678 NULL
4 3 12345 1 X
4 4 12345 2
4 5 23456 1
Thanks in advance.
In response to PM 77-1,
My current method:
SELECT table1.user,table1.number
FROM table1
JOIN (
SELECT user,
CAST(MIN((COALESCE(priority,999) *
(10 ^ (5 - LEN(COALESCE(CAST(priority AS VARCHAR),'999'))))) +
lineitem) AS VARCHAR) AS selector
FROM table1 GROUP BY user
) AS table2
ON table1.user = table2.user
AND table1.lineitem = CAST(RIGHT(table2.selector, 1) AS int)
ORDER BY table1.user;
Use ROW_NUMBER:
SQL Fiddle
;WITH Cte AS(
SELECT *,
ROW_NUMBER() OVER(
PARTITION BY [User]
ORDER BY
CASE WHEN Priority IS NULL THEN 1 ELSE 0 END,
Priority,
LineItem
) AS rn
FROM tbl
)
SELECT
[User], LineItem, Number, Priority
FROM Cte
WHERE rn = 1

Multiply newly entered row with another column value and find Total Sum in SQL

I have 4 tables here, I need to multiply newly entered row value in a table with another row and find the total sum using CustomerId:
CustomerTable:
CustomerId Name EmailId
-------------------------
1 Paul r#r.com
2 John J#j.com
LoyaltyPointTable:
LoyaltyPointsId LoyaltyType Points
---------------------------------------
1 Registration 10
2 Loginstatus 1
3 Downloading 10
4 Redemming 1
5 Sharing 20
6 Refer 10
LoyaltyDetailsTable:
LoyaltyDetailsId LoyaltyPointsId CustomerId Dates
-------------------------------------------------
1 1 1 2015-01-22
2 2 1 2015-01-22
3 3 2 2015-01-22
4 3 1 2015-01-22
5 4 1 2015-01-22
6 4 1 2015-01-24
7 5 1 2015-01-24
This query works fine for the total sum for each LoyaltyType
SELECT
LoayaltyPointsTable.LoyaltyType,
COUNT(CustomerTable.CustomerId) AS UserActions,
SUM(LoayaltyPointsTable.Points) AS TotalPoints
FROM
LoayaltyPointsTable
JOIN
LoyaltyDetailsTable ON LoayaltyPointsTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoayaltyPointsTable.LoyaltyType
below RedeemPointsTable is created with relation to row redeeming in LoyaltyPointTable:
RedeemPointsTable:
RedeemPointsId CustomerId ShopName BillNo Amount
------------------------------------------------
1 1 Mall x 4757 100
3 1 Mall y SH43 50
4 1 Mall x 7743 10
6 1 Mall x s34a 60
What I am expecting is before calculating the total sum, I want column Amount sum (100+50+10+60) * 1 in Redeeming in LoyaltyPointTable to be added with total points for each CustomerId
Expected output
LoyaltyType UserActions TotalPoints
-------------------------------------
Downloading 1 10
Loginstatus 1 1
Redemming 4 (100+50+10+60)*1(here using Amount in RedeemPointsTable)
Refer 1 10
Registration 1 10
Sharing 1 20
User actions count is 4, it is based on the Amount he entered in RedeemPointsTable
Should I need to make changes in adding a foreign key column in RedeemPointsTable or can you point out my mistake?
Any help would be great.
This is the query which returns desired result:
SELECT
LoyaltyPointTable.LoyaltyType,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT COUNT(amount) FROM RedeemPointsTable where CustomerId=1)
ELSE COUNT(CustomerTable.CustomerId)
END as UserActions,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT SUM(amount) FROM RedeemPointsTable where CustomerId=1)*Points
ELSE SUM(LoyaltyPointTable.Points)
END as TotalPoints
FROM
LoyaltyPointTable
JOIN
LoyaltyDetailsTable ON LoyaltyPointTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoyaltyPointTable.LoyaltyType
You can check it here

Need hierarichal data from 3 tables in SQL Server

I have following tables:
UserMaster:
UserId Int, UserName Varchar(200),AddedBy Int
UserId EmpName AddedBy
1 admin 0
2 SubAdmin1 1
3 SubAdmin2 1
4 Vikas 2
5 Mohit 4
6 Atul 5
7 Vishal 6
8 Mani 3
9 Sunny 8
SalesMaster:
SalesId Int, UserId Int (FK_UserMaster_UserId) , Price Int
SalesId UserId Price
1 1 100
2 2 200
3 3 300
4 4 500
5 5 100
6 6 200
7 7 111
8 8 222
9 9 333
Case 1: Now I want the price total of all the users who are under the one particular user and its own price also.
Means If i consider UserId=1 , Then the price will be calculated for all users where Column value in AddedBy=1
and their lower level employees.
Means the total Price of users will be calulated for the users having UserId are: 1,2,3,4,5,6,7,8,9.
Case 2: Similarly, If i want to calculate the total price under UserId=3(SubAdmin2) then the total price from the salesMaster will be calculated for the Users having UserId are: 3,8,9
The Result of first Case should be:
UserId Price
1 2066
The Result of Second Case should be:
UserId Price
3 300+222+333
Please Help
Thanks & Regards
Nitin
with cte as (
select #UserId as UserId
union all
select um.UserId
from UserMaster as um
inner join cte as c on c.UserId = um.AddedBy
)
select sum(s.Price)
from cte as c
inner join SalesMaster as s on s.UserId = c.UserId
sql fiddle demo