Display Data as Ledger - sql-server

I am using SQL Server 2008. I have a table AdvanceEntry.
--------------------------------------------------------------------------------
Code | PaidDate | Amount | ReceiveDate | ReceiveAmount
--------------------------------------------------------------------------------
102 | 15-04-2004 | 3000 | 20-04-2004 | 2000
104 | 23-05-2006 | 1000 | NULL | 0.00
104 | 25-05-2005 | 1500 | 12-06-2005 | 500
When any person tack the Loan then Loan amount is stored in the Amount column and date is stored in PaidDate and person code is stored in Code column. When that person gives back the amount then that amount is stored in ReceiveAmount and date is stored in ReceiveDate.
Now I want to create a report like ledger of a specific code.
For example code 102
----------------------------------------------------------------------------
PaidDate / ReceiveDate | Amount | ReceiveAmount | Balance
----------------------------------------------------------------------------
15-04-2004 | 3000 | 0 | 3000
20-04-2004 | 0 | 2000 | 1000
And for code 104
----------------------------------------------------------------------------
PaidDate / ReceiveDate | Amount | ReceiveAmount | Balance
----------------------------------------------------------------------------
23-05-2006 | 1000 | 0 | 1000
25-05-2005 | 1500 | 0 | 2500
12-06-2005 | 0 | 500 | 2000
How can I do this? Please help me.. Thanks

Here's one way of doing it:
with Paid as
(
select Code
, PaidDate
, Amount
from AdvanceEntry
where PaidDate is not null
), Received as
(
select Code
, ReceiveDate
, ReceiveAmount
from AdvanceEntry
where ReceiveDate is not null
), Details as
(
select Code = coalesce(p.Code, r.Code)
, CodeDate = coalesce(p.PaidDate, r.ReceiveDate)
, Amount = sum(p.Amount)
, ReceiveAmount = sum(r.ReceiveAmount)
from Paid p
full join Received r on p.PaidDate = r.ReceiveDate and p.Code = r.Code
group by coalesce(p.Code, r.Code)
, coalesce(p.PaidDate, r.ReceiveDate)
)
select d.Code
, PayReceiveDate = d.CodeDate
, Amount = isnull(d.Amount, 0.0)
, ReceiveAmount = isnull(d.ReceiveAmount, 0.0)
, Balance = isnull(b.Balance, 0.0)
from Details d
outer apply (select Balance = sum(isnull(b.Amount, 0.0) - isnull(b.ReceiveAmount, 0.0))
from Details b where d.Code = b.Code and d.CodeDate >= b.CodeDate) b
order by d.Code, d.CodeDate
SQL Fiddle with demo.
It also looks like you had a slight typo in your data; I've changed it slightly in the fiddle to get your expected results.
Also worth mentioning that if you are only getting one pay/receive action per day per code you can get away without any GROUP BY in the query.

try this (untested):
;with cte as (
select Code, PaidDate as Date, Amount as Dr, 0 as Cr, Amount as Net
from Data where PaidDate is not null
union all
select Code, ReceivedData as Date, 0 as Dr, -ReceivedAmount as Cr, -ReceivedAmount as Net
from Data where ReceivedDate is not null
)
select
t1.*, sum(t2.Net) as Balance
from cte as t1
left join cte as t2 on t2.Code = t1.Code and t2.Date <= t1.Date
group by
t1.Code, t1.Date
having t1.Code = #Code

Related

How to get subselect to reference anothersub select in same query

I have a (slow) query that almost does what I want. The bold section is the pseudo-code I am trying to add. The goal of this query is to get a single row per custnumber with 5 columns of data:
colA: MKT
colB: custnumber
colC: most recent apptdate WHERE src_id = Loss Recovery AND dsp_id = Sale
colD: most recent apptdate WHERE src_id NOT= Loss Recovery AND dsp_id NOT= Sale and this apptdate is earlier than LRSale
colE: days between NoSale and LRSale
This is what I have built so far, close to working. I have tried several different ways to get the last bit in but am having real trouble parsing the syntax to make it work right.
SELECT DISTINCT *, DATEDIFF(day,NoSale,LRSold) AS 'Diff'
FROM(SELECT a.MKT,
a.custnumber,
(SELECT TOP 1 CAST(apptdate AS DATE)
FROM prospectissues b
WHERE b.custnumber = a.custnumber
**AND b.apptdate < c.apptdate**
AND b.src_id <> 'Loss Recovery' AND b.dsp_id <> 'Sale'
ORDER BY apptdate DESC) AS 'NoSale',
(SELECT TOP 1 CAST(apptdate AS DATE)
FROM prospectissues c
WHERE c.custnumber = a.custnumber
AND c.src_id = 'Loss Recovery' AND c.dsp_id = 'Sale'
ORDER BY apptdate DESC) AS 'LRSold'
FROM prospectissues a
WHERE CAST(apptdate AS DATE) >= DATEADD(yy, DATEDIFF(yy,0,GETDATE())-3,0)) z
WHERE LRSold IS NOT NULL
Thank you, I appreciate any insight! I'm sure it's something simple that I'm just too tired to see right now. Been banging my head against this for too long.
-edit 7/25
I cannot write to the database, only run Select queries.
Here is a sample of the table I'm working with (rows numbered just for easy reference):
| MKT | custnumber | dsp_id | src_id | ApptDate |
----------------------------------------------------------
1 | CLE | 14675 | PMPrice | Email | 3/7/20 |
2 | CLE | 14675 | Sale | Radio | 3/9/20 |
3 | CLE | 246466 | NH | Prior Customer | 3/7/20 |
4 | PIT | 284747 | PMPrice | Show | 3/7/20 |
5 | PIT | 284747 | Sale | Loss Recovery | 3/12/20 |
6 | PIT | 384603 | Sale | SelfGen | 3/3/20 |
7 | PIT | 384603 | Sale | Loss Recovery | 3/8/20 |
8 | COL | 384764 | PMPrice | Website | 3/15/22 |
9 | COL | 384921 | Sale | Website | 3/22/20 |
10 | COL | 385052 | PMPrice | Show | 3/7/20 |
11 | COL | 385052 | Sale | Aggregates | 3/10/20 |
12 | COL | 385052 | Sale | Loss Recovery | 3/18/20 |
13 | PIT | 385662 | OVB | Aggregates | 3/12/20 |
14 | PIT | 385662 | Sale | Loss Recovery | 3/21/20 |
15 | PIT | 385662 | PMPrice | Store | 4/15/20 |
Sample of desired output:
| MKT | custnumber | NoSale | LRSold | Diff |
----------------------------------------------
| PIT | 284747 | 3/7/20 | 3/12/20 | 5 |
| COL | 385052 | 3/7/20 | 3/18/20 | 11 |
| PIT | 385662 | 3/12/20 | 3/21/20 | 9 |
The goal is to visualize how long a time gap (days) exists between Non-sale (NS) records and Loss Recovery - Sale (LR) records.
NS = anything with dsp_id NOT equal to 'Sale' AND src_id NOT equal to 'Loss Recovery' counts as an NS record
LR = anything with dsp_id = 'Sale' AND src_id = 'Loss Recovery'
criteria are:
MKT: simple text, this will always be consistent between records with the same custnumber
custnumber: the "key column", always an integer
NoSale: the most recent NS apptdate prior to a LR apptdate sharing the same custnumber
LRSale: the most recent LR record grouped by custnumber
Diff: days between NS and LR
Seems simple in theory, but giving me a hell of a time.
I think this will do it. We use conditional aggregation to help simplify the initial pass, including grabbing the first computed column (LRSold), but we still use a couple layers of nesting to get NoSale and then the Diff(). We could definitely eliminate one layer of nesting, but then we'd have to repeat the entire nested query from the SELECT clause to compute the diff, and it's a small result set, so this is probably better:
SELECT *,
DATEDIFF(day, NoSale, LRSold) [Diff]
FROM (
SELECT *,
(
SELECT MAX(pi0.apptdate)
FROM prospectissues pi0
WHERE pi0.custnumber = t.custnumber AND pi0.MKT = t.MKT AND pi0.apptdate < t.LRSold
AND pi0.src_id <> 'Loss Recovery' and pi0.dsp_id <> 'Sale'
GROUP BY pi0.custnumber, pi0.MKT
) NoSale
FROM (
SELECT pi.custnumber, pi.MKT,
MAX(CASE WHEN pi.src_id = 'Loss Recovery' and pi.dsp_id = 'Sale' THEN apptdate END) As LRSold
FROM prospectissues pi
WHERE apptdate >= DATEADD(yy, DATEDIFF(yy,0,GETDATE())-3,0)
GROUP BY pi.custnumber, pi.MKT
HAVING MAX(CASE WHEN pi.src_id = 'Loss Recovery' and pi.dsp_id = 'Sale' THEN apptdate ELSE NULL END) IS NOT NULL
) t
)d
WHERE NoSale IS NOT NULL
See it here:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=a41b9191cef92247b722788d6474edc2
I feel like we could do better with a lateral join (APPLY) to reduce the number of trips into the table, and often if that works there is also a Windowing function solution that will work even better. But this is what you get for free.
Finally, one thing I noticed is casting appdate into a DATE value. Given the reliance of the query on this field, this cast is very bad for performance, because it breaks any chance of using an index on the field and the way the query was structured forced the database you to run the conversion multiple times for every row in the table... even rows that will not be used for the results.
If the column is a datetime or datetime2 this is easily fixed: don't do the cast. It's not needed for the query to work properly. But if this is a varchar column, you need to FIX the schema, because it really is BROKEN. The performance issue here is just one of several reasons why, but it is effective at demonstrating why it's so important: just that one change to the column type would likely cut the execution time of the original query by more than an order of magnitude. NEVER use string-typed columns to store time-typed data.
I think this is what you are looking for. It should run quicker by using aggregates like Min instead of order by and top 1.
SELECT ns.MKT, ns.custnumber,
ns.MinDate AS NoSale, lr.MinDate AS LRSold
DATEDIFF(day, ns.MinDate, lr.MinDate) AS Diff
FROM (SELECT MKT, custnumber, min(apptdate) as MinDate
FROM prospectissues
WHERE src_id <> 'Loss Recovery' AND dsp_id <> 'Sale'
GROUP BY MKT, custnumber) ns
INNER JOIN --should be similar outcome as WHERE LRSold IS NOT NULL
(SELECT MKT, custnumber, min(apptdate) MinDate
FROM prospectissues b
WHERE src_id = 'Loss Recovery' AND dsp_id = 'Sale'
GROUP BY MKT, custnumber) lr
ON ns.custnumber = lr.custnumber AND ns.MKT = lr.MKT
AND ns.apptdate < lr.apptdate --The new part that you want
WHERE CAST(ns.MinDate AS DATE) >= DATEADD(yy, DATEDIFF(yy,0,GETDATE())-3,0)
I don't know if your data has any anomalies. You might want to consider an analytic approach.
with data1 as (
select MKT, custnumber, apptdate,
case when src_id <> 'Loss Recovery' and dsp_id <> 'Sale' then 'NS'
when src_id = 'Loss Recovery' and dsp_id = 'Sale' then 'LR'
end as flag
from prospectissues
where apptdate >= datefromparts(year(getdate()) - 3, 1, 1)
), data2 as (
select *,
case when flag = 'NS' then cast(apptdate as date) end NS,
case when flag = 'LR' then cast(apptdate as date) end LR,
count(case when flag = 'LR' then 1 end)
over (partition by MKT, custnumber order by apptdate) as LR_cnt
from data1
--where flag in ('NS', 'LR') /* possible optimization */
)
select MKT, custnumber,
max(NS) as NoSale, min(LR) as LRSold, datediff(day, max(NS), min(LR)) as Diff
from data2
where LR_cnt = 0 or flag = 'LR'
group by MKT, custnumber
having max(NS) is not null and min(LR) is not null;
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=9246435525b3ca67b3de6377b3a187be

Join created table under condition

I am creating a code to join two different tables under a certain condition. The tables look like this
(TABLE 2)
date | deal_code | originator | servicer | random |
-----------------------------------------------------
2011 | 001 | commerzbank | SPV1 | 1 |
2012 | 001 | commerzbank | SPV1 | 12 |
2013 | 001 | commerzbank | SPV1 | 7 |
2013 | 005 | unicredit | SPV2 | 7 |
and another table
(TABLE 1)
date | deal_code | amount |
---------------------------
2011 | 001 | 100 |
2012 | 001 | 100 |
2013 | 001 | 100 |
2013 | 005 | 200 |
I would like to have this as the final result
date | deal_code | amount | originator | servicer | random |
--------------------------------------------------------------
2013 | 001 | 100 | commerzbank | SPV1 | 7 |
2013 | 005 | 200 | unicredit | SPV2 | 7 |
I created the following code
select q1.deal_code, q1.date
from table1 q1
where q1.date = (SELECT MAX(t4.date)
FROM table1 t4
WHERE t4.deal_code = q1.deal_code)
that gives me:
(TABLE 3)
date | deal_code | amount |
---------------------------
2013 | 001 | 100 |
2013 | 005 | 200 |
That is the latest observation for table 1, now I would like to have the originator and servicer information given the deal_code and date. Any suggestion? I hope to have been clear enough. Thanks.
This should do what you are looking for. Please be careful when naming columns. Date is a reserved word and is too ambiguous to be a good name for a column.
declare #Something table
(
SomeDate int
, deal_code char(3)
, originator varchar(20)
, servicer char(4)
, random int
)
insert #Something values
(2011, '001', 'commerzbank', 'SPV1', 1)
, (2012, '001', 'commerzbank', 'SPV1', 12)
, (2013, '001', 'commerzbank', 'SPV1', 7)
, (2013, '005', 'unicredit ', 'SPV2', 7)
declare #SomethingElse table
(
SomeDate int
, deal_code char(3)
, amount int
)
insert #SomethingElse values
(2011, '001', '100')
, (2012, '001', '100')
, (2013, '001', '100')
, (2013, '005', '200')
select x.SomeDate
, x.deal_code
, x.originator
, x.servicer
, x.random
, x.amount
from
(
select s.SomeDate
, s.deal_code
, s.originator
, s.servicer
, s.random
, se.amount
, RowNum = ROW_NUMBER()over(partition by s.deal_code order by s.SomeDate desc)
from #Something s
join #SomethingElse se on se.SomeDate = s.SomeDate and se.deal_code = s.deal_code
) x
where x.RowNum = 1
Looks like this would work:
DECLARE #MaxYear INT;
SELECT #MaxYear = MAX(date)
FROM table1 AS t1
INNER JOIN table2 AS t2
ON t1.deal_code = t2.deal_code;
SELECT t1.date,
t1.deal_code,
t1.amount,
t2.originator,
t2.servicer,
t2.random
FROM table1 AS t1
INNER JOIN table2 AS t2
ON t1.date = #MaxYear
AND t1.deal_code = t2.deal_code;
I agree with Sean Lange about the date column name. His method gets around the dependency on the correlated sub-query, but at the heart of things, you really just need to add an INNER JOIN to your existing query in order to get the amount column into your result set.
select
q2.date,
q2.deal_code,
q1.amount,
q2.originator,
q2.servicer,
q2.random
from
table1 q1
join
table2 q2
on q1.date = q2.date
and q1.deal_code = q2.deal_code
where q1.date = (SELECT MAX(t4.date)
FROM table1 t4
WHERE t4.deal_code = q1.deal_code)

SQL: How to join two tables by their date ranges

I have a table with a history of assigning Eployee Type to a Work item, like follows:
| WorkItemID | EmployeeTypeID | ValidFrom | ValidTo |
| 1 | 1 | 2017-03-01 12:19:20.000 | 2017-03-05 14:11:20.000 |
| 1 | 1 | 2017-03-10 17:00:20.000 | NULL |
| 1 | 2 | 2017-05-12 12:19:20.000 | 2017-05-29 14:11:20.000 |
| 1 | 2 | 2017-07-01 12:19:20.000 | NULL |
| 2 | 1 | 2017-01-01 15:19:20.000 | 2017-03-01 11:29:20.000 |
| 2 | 1 | 2017-04-03 16:19:20.000 | NULL |
NULL means that there's no End date for the last assignment and it is still valid.
I also have a table with a history of assigning Eployee Type to an Employee:
| EmployeeID | EmployeeTypeID | ValidFrom | ValidTo |
| 1 | 1 | 2017-01-01 12:19:20.000 | 2017-03-05 14:11:20.000 |
| 1 | 2 | 2017-03-05 14:11:20.000 | NULL |
| 2 | 1 | 2016-05-05 15:19:20.000 | 2017-03-01 11:29:20.000 |
| 2 | 2 | 2017-03-01 11:29:20.000 | NULL |
For a given EmployeeID and WorkItemID, I need to select a minimum date within these date ranges where their EmployeeTypeID matched (if there is any).
For example, for EmployeeID = 1 And WorkItemID = 1 the minimum date when their Employeetypes matched is 2017-03-01 (disregard the time part).
How do I write an SQL query to join these two tables correctly and select the desired date?
The following way appeared to be correct for me:
Firstly, I select Min Date from table 1 that match with table 2 by date ranges and they should overlap as well:
DECLARE #MinDate1 datetime
DECLARE #MinDate2 datetime
SELECT #MinDate1 =
(SELECT MIN(t1.ValidFrom)
FROM Table1 t1
JOIN Table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID
WHERE t1.WorkItemID = 1 AND t2.EmployeeID = 1
AND (t1.ValidFrom <= t2.ValidTo OR t2.ValidTo IS NULL)
AND (t1.ValidTo >= t2.ValidFrom OR t1.ValidTo IS NULL))
Then I select Min Date from table 2 that match with table 1 by date ranges and they should overlap as well:
SELECT #MinDate2 =
(SELECT MIN(t2.ValidFrom)
FROM Table1 t1
JOIN Table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID
WHERE t1.WorkItemID = 1 AND t2.EmployeeID = 1
AND (t1.ValidFrom <= t2.ValidTo OR t2.ValidTo IS NULL)
AND (t1.ValidTo >= t2.ValidFrom OR t1.ValidTo IS NULL))
And finaly, I select the max date of two which would be the min date when the two ranges actually overlap and have the same EmployeeTypeID
SELECT CASE WHEN #MinDate1 > #MinDate2 THEN #MinDate1 ELSE #MinDate2 END AS MinOverlapDate
The output would be:
| MinOverlapDate |
| 2017-03-01 12:19:20.000 |
So it should be something like this:
SELECT MIN(Date)
FROM table1 t1
JOIN table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID
WHERE t1.EmployeeID = givenValue AND t2.WorkitemID = givenValue
But again if you dont know from which table the result goes you cant write a query for that.
What you should do is do at least 3 tables or maybe more
Would contain Employee informations
Items jobs dates whatever is connected to WORK
Some connection between them (Emp 1 has Work 2) (Emp 2 has Work 4) and so on
You CANNOT have same values in two tables without knowing from which one you want to get tha data!
OR .. You can do it into one table.
Columns: WorkItem | EmployeeID | EmployeeType | Date | Date
Actually, my variant still does not work correctly. The #MinDate1 and #MinDate2 should be compared by each EmployeeTypeID one by one. There it was compared independently.
Here is correct variant of solving this problem:
SELECT MIN(CASE WHEN t1.ValidFrom > t2.ValidFrom THEN t1.ValidFrom ELSE t2.ValidFrom END) AS MinOverlapDate
FROM Table1 t1
JOIN Table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID
WHERE t1.WorkItemID = 1 AND t2.EmployeeID = 1
AND (t1.ValidFrom <= t2.ValidTo OR t2.ValidTo IS NULL)
AND (t1.ValidTo >= t2.ValidFrom OR t1.ValidTo IS NULL)
Don't use >=, <=, = or between when comparing datetime fields. Since all of the mention operator would check against time as well. You would want to use datediff to check against the smallest interval according to your needs
select
Min_Overlap_Per_Section = (select MAX(ValidFrom)
FROM (VALUES (t1.ValidFrom), (t2.ValidFrom)) as ValidFrom(ValidFrom))
, Section_From = (select MAX(ValidFrom)
FROM (VALUES (t1.ValidFrom), (t2.ValidFrom)) as ValidFrom(ValidFrom))
, Section_To = (select MIN(ValidTo)
FROM (VALUES (t1.ValidTo), (t2.ValidTo)) as ValidTo(ValidTo))
from Table1
JOIN Table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID
where (
datediff(day, t1.ValidFrom, t2.ValidTo) >= 0
or t2.ValidTo IS NULL
)
and (
datediff(day, t2.ValidFrom, t1.ValidTo) >= 0
or t1.ValidTo IS NULL
)

The highest value from list-distinct

Can anyone help me with query, I have table
vendorid, agreementid, sales
12001 1004 700
5291 1004 20576
7596 1004 1908
45 103 345
41 103 9087
what is the goal ?
when agreemtneid >1 then show me data when sales is the highest
vendorid agreementid sales
5291 1004 20576
41 103 9087
Any ideas ?
Thx
Well you could try using a CTE and ROW_NUMBER something like
;WITH Vals AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY AgreementID ORDER BY Sales DESC) RowID
FROM MyTable
WHERE AgreementID > 1
)
SELECT *
FROM Vals
WHERE RowID = 1
This will avoid you returning multiple records with the same sale.
If that was OK you could try something like
SELECT *
FROM MyTable mt INNER JOIN
(
SELECT AgreementID, MAX(Sales) MaxSales
FROM MyTable
WHERE AgreementID > 1
) MaxVals ON mt.AgreementID = MaxVals.AgreementID AND mt.Sales = MaxVals.MaxSales
SELECT TOP 1 WITH TIES *
FROM MyTable
ORDER BY DENSE_RANK() OVER(PARTITION BY agreementid ORDER BY SIGN (SIGN (agreementid - 2) + 1) * sales DESC)
Explanation
We break table MyTable into partitions by agreementid.
For each partition we construct a ranking or its rows.
If agreementid is greater than 1 ranking will be equal to ORDER BY sales DESC.
Otherwise ranking for every single row in partition will be the same: ORDER BY 0 DESC.
See how it looks like:
SELECT *
, SIGN (SIGN (agreementid - 2) + 1) * sales AS x
, DENSE_RANK() OVER(PARTITION BY agreementid ORDER BY SIGN (SIGN (agreementid - 2) + 1) * sales DESC) AS rnk
FROM MyTable
+----------+-------------+-------+-------+-----+
| vendorid | agreementid | sales | x | rnk |
+----------|-------------|-------+-------+-----+
| 0 | 0 | 3 | 0 | 1 |
| -1 | 0 | 7 | 0 | 1 |
| 0 | 1 | 3 | 0 | 1 |
| -1 | 1 | 7 | 0 | 1 |
| 41 | 103 | 9087 | 9087 | 1 |
| 45 | 103 | 345 | 345 | 2 |
| 5291 | 1004 | 20576 | 20576 | 1 |
| 7596 | 1004 | 1908 | 1908 | 2 |
| 12001 | 1004 | 700 | 700 | 3 |
+----------+-------------+-------+-------+-----+
Then using TOP 1 WITH TIES construction we leave only rows where rnk equals 1.
you can try like this.
SELECT TOP 1 sales FROM MyTable WHERE agreemtneid > 1 ORDER BY sales DESC
I really do not know the business logic behind agreement_id > 1. It looks to me you want the max sales (with ties) by agreement id regardless of vendor_id.
First, lets create a simple sample database.
-- Sample table
create table #sales
(
vendor_id int,
agreement_id int,
sales_amt money
);
-- Sample data
insert into #sales values
(12001, 1004, 700),
(5291, 1004, 20576),
(7596, 1004, 1908),
(45, 103, 345),
(41, 103, 9087);
Second, let's solve this problem using a common table expression to get a result set that has each row paired with the max sales by agreement id.
The select statement just applies the business logic to filter the data to get your answer.
-- CTE = max sales for each agreement id
;
with cte_sales as
(
select
vendor_id,
agreement_id,
sales_amt,
max(sales_amt) OVER(PARTITION BY agreement_id) AS max_sales
from
#sales
)
-- Filter by your business logic
select * from cte_sales where sales_amt = max_sales and agreement_id > 1;
The screen shot below shows the exact result you wanted.

Combine Record by Id

I am Using SQLServer2008.
Output of My Stored Procedure is :
--------------------------------------------------------
BrokerCode | MemberId | FY | SY | TY |
--------------------------------------------------------
104 | 24 | 1140 | 0.00 | 0.00 |
--------------------------------------------------------
104 | 24 | 1140 | 570 | 0.00 |
--------------------------------------------------------
104 | 30 | 500 | 0.00 | 0.00 |
--------------------------------------------------------
104 | 30 | 500 | 360 | 0.00 |
--------------------------------------------------------
And I want to result like :
--------------------------------------------------------
BrokerCode | MemberId | FY | SY | TY |
--------------------------------------------------------
104 | 24 | 1140 | 570 | 0.00 |
--------------------------------------------------------
104 | 30 | 500 | 360 | 0.00 |
--------------------------------------------------------
So i have tried using :
WITH CTE AS (
SELECT BrockerCode,
MemberId,
RN=ROW_NUMBER()OVER(PARTITION BY MemberId ORDER BY MemberID),
FY=MIN(FY)OVER(PARTITION BY MemberId),
SY=MIN(SY)OVER(PARTITION BY MemberId),
TY=MIN(TY)OVER(PARTITION BY MemberId)
FROM #tablePromotee )
SELECT MemberId,BrockerCode,FY,SY,TY FROM CTE WHERE RN = 1
but still it display wrong result...please help me..where i am wrong? Thanks.
Common Table Expression isn't really required here. A much simpler query:
SELECT
BrokerCode,
MemberId,
MAX(FY) AS FY,
MAX(SY) AS SY,
MAX(TY) AS TY
FROM YourTable
GROUP BY BrokerCode, MemberId
SQL FIDDLE DEMO
You can simply use "GROUP BY " in your query
Like,
SELECT BrockerCode,
MemberId,
MIN(FY)
MIN(SY)
MIN(TY)
FROM #tablePromotee GROUP BY BrockerCode, MemberId
There are multiple aggregate function on sql server you can use from them as per your requirement.
Try this,
SELECT BrockerCode,
MemberId, FY,SUM(SY),SUM(TY) FROM #tablePromotee Group By BrockerCode,
MemberId, FY
Simply using group by wont work as you may end up in getting o.oo values
change last line of your existing code as below, hope you want this.
SELECT MemberId,BrockerCode,FY,SY,TY FROM CTE WHERE RN = 1 and SY<>0
ROUP BY BrockerCode, MemberId
Try this one -
SELECT
MemberId
, BrockerCode
, FY = MAX(FY)
, SY = MAX(SY)
, TY = MAX(TY)
FROM (
SELECT
BrockerCode
, MemberId
, RN = ROW_NUMBER()OVER(PARTITION BY MemberId ORDER BY MemberID)
, FY = MIN(FY)OVER(PARTITION BY MemberId)
, SY = MIN(SY)OVER(PARTITION BY MemberId)
, TY = MIN(TY)OVER(PARTITION BY MemberId)
FROM #tablePromotee
)
WHERE RN = 1
GROUP BY
BrokerCode
, MemberId
Or try this -
SELECT TOP 1
BrockerCode
, MemberId
, FY = MAX(MIN(FY)OVER(PARTITION BY MemberId))
, SY = MAX(MIN(SY)OVER(PARTITION BY MemberId))
, TY = MAX(MIN(TY)OVER(PARTITION BY MemberId))
FROM #tablePromotee
GROUP BY
BrokerCode
, MemberId
ORDER BY MemberId

Resources