I have a table Test with AcctNbr, Balance and Date columns. This table contains data as below
Acctnbr Balance LastUpdatedDt
123 100 May 08
456 200 May 08
222 300 May 07
333 400 May 07
123 50 May 06
222 120 May 05
678 70 May 04
Am trying to achieve daily balance as below
AcctNbr Balance LastUpdatedDt
123 100 May 08
456 200 May 08
222 300 May 08
333 400 May 08
123 50 May 08
678 70 May 08
123 50 May 07
456 0 May 07
222 300 May 07
333 400 May 07
123 50 May 07
678 70 May 07
123 50 May 06
456 0 May 06
222 120 May 06
333 0 May 06
123 50 May 06
678 70 May 06
123 0 May 05
456 0 May 05
222 120 May 05
333 0 May 05
123 0 May 05
678 70 May 05
123 0 May 04
456 0 May 04
222 0 May 04
333 0 May 04
123 0 May 04
678 70 May 04
Here is my query
SELECT
A.Accountnbr,
dt AS CalendarDate,
A.Balance
FROM
dbo.GetDates('20150504',GETDATE())
cross APPLY
(
SELECT TOP 1 Accountnbr,Balance
FROM dbo.Test
WHERE LastUpdateDt <= dt
ORDER BY LastUpdateDt DESC
) A
This is working fine when i use TOP and Order BY inside CROSS APPLY. But i want to get balances for all accounts. I cannot use TOP inside CROSS APPLY as Test table will be getting updated every day with new accounts, but i need Order By to get correct balances from To and End dates in GetDates function. My question is how to use Order by without using TOP in the above query. Any help is appreciated.
I would use a cte with a row number and partition on account number and date (assuming you want the latest by account and day).
You can then join any tables onto the cte table if you need to.
with balance_cte as (
SELECT Accountnbr,
LastUpdatedDt,
Balance,
row_number() over (partition by Accountnbr. mydate order by LastUpdateDt DESC) as rn
FROM dbo.Test
)
select Accountnbr,
LastUpdatedDt,
Balance
from join balance_cte
where rn = 1
Related
I have a table that looks something like this:
Agency Year Total PopGroup
01 2017 3467 3C
01 2018 3444 3C
01 2019 3567 3C
02 2017 1000 1C
02 2018 1354 1C
02 2019 1333 1C
03 2017 6784 2C
03 2018 3453 2C
04 2017 3333 2C
If an agency has a row for year 2019, I want to duplicate this row and call it 2020 (basically, an estimate population for 2020). Desired result:
Agency Year Total PopGroup
01 2017 3467 3C
01 2018 3444 3C
01 2019 3567 3C
01 2020 3567 3C
02 2017 1000 1C
02 2018 1354 1C
02 2019 1333 1C
02 2020 1333 1C
03 2017 6784 2C
03 2018 3453 2C
04 2017 3333 2C
I think I should use something like:
INSERT INTO table
WHERE Year = 2019
but I'm a little stuck. What can I try next?
You are on the right track:
INSERT INTO table (Agency, Year, Total, PopGroup)
SELECT Agency, 2020 as Year, Total, PopGroup
FROM table t
WHERE Year = 2019 ;
you can use the following insert to add a new row exactly same as another one but with some modified data.
insert into table (select agency, 2020, total, popgroup from table where year = 2019)
this will insert a new record exactly same as 2019 but with year 2020
I have a table with a million records. This is the structure of the table with some example data points -
INPUT
patient claim thru_dt cd start
322 65 20200201 42 20181008
322 65 20200202 42
322 95 20200203 52
122 05 20200105 23
122 05 20200115 42 20190102
122 05 20200116 42
I need to write a query that would produce this output -
OUTPUT
patient claim thru_dt cd start
322 65 20200201 42 20181008
322 65 20200202 42 20181008
322 95 20200203 52 20181008
122 05 20200105 23
122 05 20200115 42 20190102
122 05 20200416 42
This is the query that does that -
SELECT t.*, s.*,
CASE
WHEN ISNULL(t.start, '') = '' AND (
s.cd = t.cd
OR
(
ROW_NUMBER() OVER(PARTITION BY t.patient ORDER BY t.thru_dt DESC) = 1
)
)
THEN s.start
ELSE t.start
END new_start
FROM table t
OUTER APPLY (
SELECT top (1) s.*
FROM table s
WHERE
s.patient = t.patient
AND ISNULL(s.start, '') <> ''
AND s.thru_dt >= DATEADD(DAY, -30, t.thru_dt)
ORDER BY s.thru_dt DESC
) s
ORDER BY t.patient DESC, t.thru_dt
This query produces the output I need but it doesn't work for this edge case -
INPUT
patient claim thru_dt cd start
322 65 20200201 42 20181008
322 65 20200202 45
322 95 20200203 52
122 05 20200105 23
122 05 20200115 42 20190102
122 05 20200416 42
The difference between the first input and the second input is the cd value of the second row. When I run the above query, the output I get is -
OUTPUT
patient claim thru_dt cd start
322 65 20200201 42 20181008
322 65 20200202 45 NULL
322 95 20200203 52 20181008
122 05 20200105 23
122 05 20200115 42 20190102
122 05 20200416 42
However, I don't want the third record to have a start value if the second record for patient 322 was given a NULL.
Here is a DBFiddle outlining my issue - https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=10842c7e66e148dbaad58ccb71cd6c11
UPDATE
This is the explanation for the first output data block -
The reason the second claim of patient 322 was given 20181008 is because both the first and the second one have the same cd value.
The reason the third claim of patient 322 was also given 20181008 value even though it doesn't have the same cd value is because it is the last claim for the patient.
The reason the first claim of patient 122 is still a NULL is because that claim's cd value is not equal to 42.
The reason the third claim of patient 122 was NOT given a value of 20190102 even though it has the same cd value is because the thru_dt in their prior claim is more than 30 days apart.
I would like to get the first and the last value in the column Status1 of each sequence of the same value!
This is an example of my table:
time Status1 Eficiencia Lote
----------------------------------------------------
2020 06 14 18:03:48.457 70 80 95
2020 06 14 18:04:47.693 70 80 95
2020 06 14 18:06:58.203 55 80 95
2020 06 14 18:08:19.900 55 80 95
2020 06 14 18:09:45.537 55 80 95
2020 06 14 18:10:06.670 100 80 13
2020 06 14 18:10:27.297 100 80 13
2020 06 14 18:10:31.810 100 80 13
2020 06 14 18:10:43.187 100 80 13
2020 06 14 18:11:30.303 55 80 14
2020 06 14 18:12:07.563 55 80 14
2020 06 14 18:18:54.997 55 80 14
I tried this but using this I didn't get by each sequence but in the hole table!
;with cte as
(
select
*,
RnAsc = row_number() over (partition by [Status1] order by time),
RnDesc = row_number() over (partition by [Status1] order by time desc)
from
[VALORES_DB].[dbo].[OEE_TESTE]
)
select time, [Status1], Eficiencia, Lote, Status1
from cte
where RnAsc = 1 or RnDesc = 1
I would like to get the follow:
time Status1 Eficiencia Lote
------------------------------------------------------
2020 06 14 18:03:48.457 70 80 95
2020 06 14 18:04:47.693 70 80 95
2020 06 14 18:06:58.203 55 80 95
2020 06 14 18:09:45.537 55 80 95
2020 06 14 18:10:06.670 100 80 13
2020 06 14 18:10:43.187 100 80 13
2020 06 14 18:11:30.303 55 80 14
2020 06 14 18:18:54.997 55 80 14
I would suggest lag() and lead():
select t.*
from (select t.*,
lag(status1) over (order by time) as prev_status1,
lead(status1) over (order by time) as next_status1
from t
) t
where (prev_status1 is null or prev_status1 <> status1) or
(next_status1 is null or next_status1 <> status1);
These comparisons determine where the value changes -- which is really what you are asking for.
I have
ID ID2 Amount
-------- -------- ------
01 02 20
01 03 30
02 04 40
02 06 30
03 05 70
03 06 60
03 07 60
04 08 100
04 09 110
I want to query the data above into 2 resultset (return max 5 rows) which are:
result 1:
ID1 ID2 Amount
-------- -------- ------
01 02 20
01 03 30
02 04 40
02 06 30
result 2:
ID1 ID2 Amount
-------- -------- ------
03 05 70
03 06 60
03 07 60
04 08 100
04 09 110
How should I construct my query?
use row_number() to generate a sequential no. (row_number() over (order by ID1) - 1) / 5 + 1 will gives you set of 5 per each result
; WITH CTE AS
(
SELECT result_no = (row_number() over (order by ID1) - 1) / 5 + 1,
ID1, ID2, Amount
FROM yourtable
)
SELECT *
FROM CTE
WHERE result_no = #result_no
I have the following table (simplified):
RecordID bigint IDENTITY
ItemID bigint
ConfigID varchar
Status varchar
StatusDate date
Sample Data:
001 04 1E 10 2007-08-14 13:57:54
002 04 1E 12 2007-08-21 16:10:21
003 04 1D 10 2007-09-27 17:14:13
004 04 1D 43 2011-01-10 13:44:50
005 04 1B 50 2008-06-20 09:09:51
006 05 1A 17 2007-12-18 14:04:56
007 05 1A 11 2007-10-17 08:23:52
008 05 1A 12 2007-10-19 12:54:18
009 05 1B 12 2007-11-02 09:23:54
010 05 1B 40 2010-06-17 09:34:33
011 07 1A 12 2007-11-19 14:48:06
012 07 1A 12 2007-11-19 15:02:48
013 07 1B 40 2011-01-10 14:36:16
014 08 1B 10 2009-05-22 11:14:42
015 08 1B 12 2007-11-20 17:02:44
016 08 1A 12 2007-12-12 16:11:57
017 08 1A 10 2009-11-12 11:12:45
018 08 1C 35 2011-01-10 18:30:10
019 08 1D 12 2009-10-14 14:34:47
020 08 1D 10 2009-10-14 14:35:09
Herein lies my problem:
I need to be able to have end-users query this data to return records that will display the latest status and statusdate for each unique combination of itemid and config. So, using the above sample I want to return a record set matching the following:
002 04 1E 12 2007-08-21 16:10:21
004 04 1D 43 2011-01-10 13:44:50
005 04 1B 50 2008-06-20 09:09:51
006 05 1A 17 2007-12-18 14:04:56
010 05 1B 40 2010-06-17 09:34:33
012 07 1A 12 2007-11-19 15:02:48
013 07 1B 40 2011-01-10 14:36:16
017 08 1A 10 2009-11-12 11:12:45
018 08 1C 35 2011-01-10 18:30:10
020 08 1D 10 2009-10-14 14:35:09
In plain english: I need to be able to return the latest status and status date for each item's configuration(s).
Any help in this regard would be extremely appreciated. Thank you in advance.
You can do the GROUP BY clause in a subquery. Try,
SELECT a.*
FROM yourtable a
INNER JOIN
(
SELECT ItemID, ConfigID, MAX([StatusDate]) maxStat
FROM yourtable
GROUP BY ItemID,ConfigID
) b on a.configID = b.configID AND
a.[statusDate] = b.MaxStat AND
a.ItemID = b.ItemID
Order by RecordID
SQLFiddle Demo
in SQL server 2005+, you can use CTE for this:
;with cte as
(
select recordid,
itemid,
configid,
status,
statusdate,
row_number() over(partition by itemid, configid
order by statusdate desc) rn
from yourtable
)
select *
from cte
where rn = 1
order by recordid
see SQL Fiddle with Demo
SELECT
RecordID,
ItemID,
ConfigID,
Status,
StatusDate
FROM
(SELECT
RecordID,
ItemID,
ConfigID,
Status,
StatusDate,
ROW_NUMBER() OVER(PARTITION BY ItemId,ConfigID ORDER BY StatusDate DESC) As StatusOrder
FROM
MyTable) Statuses
WHERE
StatusOrder= 1