Select rows where value changed in column - sql

Currently I have this table in sql database sorted by Account#.
Account# Charge_code PostingDate Balance
12345 35 1/18/2016 100
**12345 35 1/20/2016 200**
12345 61 1/23/2016 250
12345 61 1/22/2016 300
12222 41 1/20/2016 200
**12222 41 1/21/2016 250**
12222 42 1/23/2016 100
12222 42 1/25/2016 600
How do I select last row prior to the change in the charge_code column for each Account#. I highlighted the rows that I am trying to return.
The query should execute quickly with the table having tens of thousands of records.

In SQL Server 2012+, you would use lead():
select t.*
from (select t.*,
lead(charge_code) over (partition by account order by postingdate) as next_charge_code
from t
) t
where charge_code <> next_charge_code;
In earlier versions of SQL Server, you can do something similar with apply.

Related

How to select the first row that met condition

I have the following View in PostgreSQL:
idshipment idorder quantity_order date quantity_in_shipment percent_sent
50 1 1020 1.1.16 432 42
51 1 1020 17.1.16 299 71
51 1 1020 20.1.16 144 85
51 1 1020 45.1.16 145 100
52 2 1 3.1.17 5 100
This View shows shipments per order.
For example:
idorder=1 was sent by 4 shipments:
quantity in first shipment is 432 which means 42% of order was sent
quantity in second shipment is 299 which means 71% of order was sent
quantity in third shipment is 144 which means 85% of order was sent
quantity in forth shipment is 145 which means 100% of order was sent
I need a query which will show me the first date where each order was sent above 75%. meaning each order shows only one row.
For the above data I should see:
idorder date
1 20.1.16 (cause its 85% first time above 75%)
2 3.1.17 (cause its 100% first time above 75%)
How can i do that?
You can use distinct on:
select distinct on (t.idshipment) t.*
from t
where t.percent_sent >= 75
order by t.idshipment, t.percent_sent asc;
Try something like this:
SELECT iorder, MIN("date") AS "date"
FROM your_view
WHERE percent_sent >= 75
GROUP BY iorder
use group by to get only one record per idorder and MIN() to aggregate date by selecting the earliest date
I created a table call shipment that has data like you provided:
and execute this query
SELECT s.idorder, MIN(s.date) as date
FROM shipment s
WHERE percent_sent >= 75
GROUP BY s.idorder
result:
idorder date
----------- ----------
1 2016-01-20
2 2017-03-01

How to use aggregate functions in my criteria in SQL Server?

I have table called VoucherEntry
These are my records,
ID VoucherOnlineID TransactionNumber Store Amount
-------------------------------------------------------------
120 137 26 1001 100
126 137 22 2000 -56
128 137 30 3000 -20
133 137 11 2000 -5
Now I want to add 2 columns which is having carry amount and Balance amount. If the VoucherEntry.Amount = 100 Then carry column should be 0, other wise it should display like below
Expecting output
ID VoucherOnlineID TransactionNumber Store Carry Amount Balance
---------------------------------------------------------------------------------
120 137 26 1001 0 100 100
126 137 22 2000 100 -56 44
128 137 30 3000 44 -20 24
133 137 11 2000 24 -5 19
Update
we can sort the record By ID column or Date column, after you sort the records will display in above order
You need two variations of a Cumulative Sum:
SELECT
VoucherOnlineID
,TransactionNumber
,Store
,Coalesce(Sum(Amount) -- Cumulative Sum of previous rows
Over (PARTITION BY VoucherOnlineID
ORDER BY DATE -- or whatever determines correct order
ROWS BETWEEN Unbounded Preceding AND 1 Preceding), 0) AS Carry
,Amount
,Sum(Amount) -- Cumulative Sum including current row
Over (PARTITION BY VoucherOnlineID
ORDER BY DATE -- or whatever determines correct order
ROWS Unbounded Preceding) AS Balance
FROM VoucherEntry
sql Server 2008 and below
declare #t table(ID int,VoucherOnlineID int,TransactionNumber int,Store int,Amount int)
insert into #t VALUES
(120,137,26,1001,100)
,(126,137,22,2000,-56)
,(128,137,30,3000,-20)
,(133,137,11,2000,-5 )
select *
,isnull((Select sum(Amount) from #t t1
where t1.VoucherOnlineID=t.VoucherOnlineID
and t1.id<t.id ) ,0)Carry
,isnull((Select sum(Amount) from #t t1
where t1.VoucherOnlineID=t.VoucherOnlineID
and t1.id<=t.id ) ,0)Balance
from #t t

Cumulative Compoud Interest Calculation(Oracle Database 11g Release 2)

I have a requirement to calculate rolling compound interest on several accounts in pl/sql. I was looking for help/advice on how to script calculate these calculations. The calculations I need are in the last two columns of the output below (INTERESTAMOUNT AND RUNNING TOTAL). I found similar examples of this on here, but nothing specifically fitting these requirements in pl/sql. I am also new to CTE/Recursive Techniques and the Model technique I found required a specific iteration which would be variable in this case. Please see my problem below:
Calculations:
INTERESTAMOUNT = (Previous Year RUNNING TOTAL+ Current Year AMOUNT) * INTEREST_RATE
RUNNINGTOTAL = (Previous Year RUNNING TOTAL+ Current Year AMOUNT) * (1 + INTEREST_RATE) - CURRENT YEAR EXPENSES
Input Table:
YEAR ACCT_ID AMOUNT INTEREST_RATE EXPENSES
2002 1 1000 0.05315 70
2003 1 1500 0.04213 80
2004 1 800 0.03215 75
2005 1 950 0.02563 78
2000 2 750 0.07532 79
2001 2 600 0.06251 75
2002 2 300 0.05315 70
Desired Output:
YEAR ACCT_ID AMOUNT INTEREST_RATE EXPENSES INTERESTAMOUNT RUNNINGTOTAL
2002 1 1000 0.05315 70 53.15 983.15
2003 1 1500 0.04213 80 104.62 2507.77
2004 1 800 0.03215 75 106.34 3339.11
2005 1 950 0.02563 78 109.93 4321.04
2000 2 750 0.07532 79 56.49 727.49
2001 2 600 0.06251 75 82.98 1335.47
2002 2 300 0.05315 70 86.93 1652.4
One way to do it is with a recursive cte.
with rownums as (select t.*
,row_number() over(partition by acct_id order by yr) as rn
from t) -- t is your tablename
,cte(rn,yr,acct_id,amount,interest_rate,expenses,running_total,interest_amount) as
(select rn,yr,acct_id,amount,interest_rate,expenses
,(amount*(1+interest_rate))-expenses
,amount*interest_rate
from rownums
where rn=1
union all
select t.rn,t.yr,t.acct_id,t.amount,t.interest_rate,t.expenses
,((c.running_total+t.amount)*(1+t.interest_rate))-t.expenses
,(c.running_total+t.amount)*t.interest_rate
from cte c
join rownums t on t.acct_id=c.acct_id and t.rn=c.rn+1
)
select * from cte
Sample Demo
Generate row numbers using row_number function
Calculate the interest and running total of the first row for each acct_id (anchor in the recursive cte).
Join every row to the next one (ordered by ascending order of year column) for each account_id and compute the running total and interest for the subsequent rows.

add column based on a column value in one row

I've this table with the following data
user Date Dist Start
1 2014-09-03 150 12500
1 2014-09-04 220 null
1 2014-09-05 100 null
2 2014-09-03 290 18000
2 2014-09-04 90 null
2 2014-09-05 170 null
Based on the value in Start Column i need to add another column and repeat the value if not null for the same user
The resultant table should be as below
user Date Dist Start StartR
1 2014-09-03 150 12500 12500
1 2014-09-04 220 null 12500
1 2014-09-05 100 null 12500
2 2014-09-03 290 18000 18000
2 2014-09-04 90 null 18000
2 2014-09-05 170 null 18000
Can someone please help me out with this query? because i don't have any idea how can i do it
For the data you have, you can use a window function:
select t.*, min(t.start) over (partition by user) as StartR
from table t
You can readily update using the same idea:
with toupdate as (
select t.*, min(t.start) over (partition by user) as new_StartR
from table t
)
update toupdate
set StartR = new_StartR;
Note: this works for the data in the question and how you have phrased the question. It would not work if there were multiple Start values for a given user, or if there were NULL values that you wanted to keep before the first non-NULL Start value.
You can use COALESCE/ISNULL and a correlated sub-query:
SELECT [user], [Date], [Dist], [Start],
StartR = ISNULL([Start], (SELECT MIN([Start])
FROM dbo.TableName t2
WHERE t.[User] = t2.[User]
AND t2.[Start] IS NOT NULL))
FROM dbo.TableName t
I have used MIN([Start]) since you haven't said what should happen if there are multiple Start values for one user that are not NULL.

Sql get latest records of the month for each name

This question is probably answered before but i cant find how to get the latest records of the months.
The problem is that I have a table with sometimes 2 row for the same month. I cant use the aggregate function(I guess) cause in the 2 rows, i have different data where i need to get the latest.
Example:
name Date nuA nuB nuC nuD
test1 05/06/2013 356 654 3957 7033
test1 05/26/2013 113 237 399 853
test3 06/06/2013 145 247 68 218
test4 06/22/2013 37 37 6 25
test4 06/27/2013 50 76 20 84
test4 05/15/2013 34 43 34 54
I need to get a result like:
test1 05/26/2013 113 237 399 853
test3 06/06/2013 145 247 68 218
test4 05/15/2013 34 43 34 54
test4 06/27/2013 50 76 20 84
** in my example the data is in order but in my real table the data is not in order.
For now i have something like:
SELECT Name, max(DATE) , nuA,nuB,nuC,nuD
FROM tableA INNER JOIN
Group By Name, nuA,nuB,nuC,nuD
But it didn't work as i want.
Thanks in advance
Edit1:
It seems that i wasn't clear with my question...
So i add some data in my example to show you how i need to do it.
Thanks guys
Use SQL Server ranking functions.
select name, Date, nuA, nuB, nuC, nuD from
(Select *, row_number() over (partition by name, datepart(year, Date),
datepart(month, Date) order by Date desc) as ranker from Table
) Z
where ranker = 1
Try this
SELECT t1.* FROM Table1 t1
INNER JOIN
(
SELECT [name],MAX([date]) as [date] FROM Table1
GROUP BY [name],YEAR([date]),MONTH([date])
) t2
ON t1.[date]=t2.[date] and t1.[name]=t2.[name]
ORDER BY t1.[name]
Can you not just do an order
select * from tablename where Date = (select max(Date) from tablename)
followed by only pulling the first 3?