add column based on a column value in one row - sql

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.

Related

How to update a column in a table from another column in the same table one step back

Hi I have a table that has a structure like below
Id
oldid
newid
dateon
currentdate
code
1
NULL
636
2022-03-07 16:02:48.960
2022-03-25 10:27:56.393
777
2
636
202
2022-03-25 10:27:56.393
2022-05-11 14:34:48.153
777
3
202
203
2022-05-11 14:34:48.153
2022-05-12 14:35:42.957
777
4
203
273
2022-05-12 14:35:42.957
2022-05-14 14:35:42.957
777
5
273
189
2022-05-14 14:35:42.957
NULL
777
Currently the column in currentdate is empty. I want to update the column of current date like mentioned above i.e update column currentdate one step back from dateon column.
I tried this query, But it is updating random data
UPDATE a
SET a.currentdate = b.dateon
FROM Table a
LEFT JOIN Table b ON b.code = a.c aodend b.oldid = a.newid
You could use the lead function within CTE as the following:
with cte as
(
select *,
lead(dateon) over (partition by code order by dateon) ld
from table_name
)
update cte set currentdate = ld;
See demo

SQL update statement to sum column in one table, then add the total to a different column/table

Evening all, hoping for some pointers with an SQL Server query if possible.
I have two tables in a database, example as follows:
PostedTran
PostedTranID AccountID PeriodID Value TransactionDate
1 100 120 100 2019-01-01
2 100 120 200 2020-01-01
3 100 130 300 2021-01-01
4 101 120 400 2020-01-01
5 101 130 500 2021-01-01
PeriodValue
PeriodValueID AccountID PeriodID ActualValue
10 100 120 500
11 101 120 600
I have a mismatch in the two tables, and I'm failing miserably in my attempts. From the PostedTran table, I'm trying to select all transaction lines dated before 2021-01-01, then sum the Value for each AccountID from the results. I then need to add that value to the existing ActualValue in the PeriodValue table.
So, in the above example, the ActualValue on PeriodValueID 10 will update to 800, and 11 to 1000. The PeriodID in this example is constant and will always be 120.
Thanks in advance for any help.
Since RDMS not mentioned, pseudo-sql looks like:
with DataSum as
(
select AccountID, PeriodID, sum(Value) as TotalValue
from PostedTran
where TransactionDate<'1/1/2021'
group by AccountID, PeriodID
)
update PeriodValue set ActualValue = ActualValue + ds.TotalVaue
from PeriodValue pv inner join DataSum ds
on pv.accountid=ds.accountid and pv.periodid=ds.periodid
The following should do what you ask. I haven't included PeriodId in the correlation as you did not specify it in your description, however you can just include it if it's required.
update pv set pv.ActualValue=pv.ActualValue + t.Value
from PeriodValue pv
cross apply (
select Sum(value) value
from PostedTran pt
where pt.AccountId=pv.AccountId and pt.TransactionDate <'20210101'
)t

Select rows where value changed in column

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.

SQL Query to continuously bucket data

I have a table as follows:
Datetime | ID | Price | Quantity
2013-01-01 13:30:00 1 139 25
2013-01-01 13:30:15 2 140 25
2013-01-01 13:30:30 3 141 15
Supposing that I wish to end up with a table like this, which buckets the data into quantities of 50 as follows:
Bucket_ID | Max | Min | Avg |
1 140 139 139.5
2 141 141 141
Is there a simple query to do this? Data will constantly be added to the first table, it would be nice if it could somehow not recalculate the completed buckets of 50 and instead automatically start averaging the next incomplete bucket. Ideas appreciated! Thanks
You may try this solution. It should work even if "number" is bigger than 50 (but relying on fact that avg(number) < 50).
select
bucket_id,
max(price),
min(price),
avg(price)
from
(
select
price,
bucket_id,
(select sum(t2.number) from test t2 where t2.id <= t1.id ) as accumulated
from test t1
join
(select
rowid as bucket_id,
50 * rowid as bucket
from test) buckets on (buckets.bucket - 50) < accumulated
and buckets.bucket > (accumulated - number))
group by
bucket_id;
You can have a look at this fiddle http://sqlfiddle.com/#!7/4c63c/1 if it is what you want.

How to rank partitions by date order when values which I am partitioning on can repeat?

I have a query which looks for the number of different values of a key field over a period of time and assigns a rank to the values in the order they occur.
So, for example I might have:
ID Date Value
1 2010-01-01 125.00
1 2010-02-01 125.00
1 2010-03-01 130.00
1 2010-04-01 131.00
1 2010-05-01 131.00
1 2010-06-01 131.00
1 2010-07-01 126.00
1 2010-08-01 140.00
I am using
ROW_NUMBER() over(partition by [ID] order by [Date]) as [row]
to rank the different values of the Value column in the date order they occur. So I would get something like
Value row
125.00 1
130.00 2
131.00 3
126.00 4
etc
THe problem I am having is that sometimes a value might repeat. So in the above example if the value on 1st August was 125.00 for example. I want to treat this as a seperate occurance but using the ranking function I am using at the moment it obviously gets aggregated into a partition with the other instances of 125.00 when calculating the row number.
What's the easiest way for me to overcome this problem please? Thanks in advance!
This should work:
WITH A
AS
(SELECT ID, [Date], [Value], ROW_NUMBER() over(partition by [ID] order by [Value], [Date]) as [row]
FROM YourTable)
SELECT A.[Date], A.[Value], B.min_row as row
FROM A JOIN (SELECT ID, [Value], MIN([row]) AS min_row
FROM A) AS B
ON A.ID = B.ID AND A.[Value] = B.[Value]