SQL Server: Limit filling NULL values up to row with specific text - sql

I have a CTE on which i am filling null values with the previous value before row 100 available by using the following script
SELECT [YearMonth],grp,
CASE WHEN grp>grp
THEN (FIRST_VALUE([Value 1]) over (partition by grp order by [YearMonth]))
The problem is that i want the rows after the "Latest" to be null but i dont want these rows to be deleted cause there are values in other columns which i need to show. I would appreciate of any help.
EDIT
Current Table
YearMonth
Value 1
2021-01
0.9575
2021-02
NULL
2021-03
NULL
2021-04
NULL
2021-05
NULL
2021-06
0.9875
Expected table
YearMonth
Value 2
2021-01
0.9575
2021-02
0.9575
2021-03
0.9575
2021-04
0.9575
2021-05
0.9575
2021-06
0.9875

Related

I am going bonkers with this one simple SQL question

Input table:
STAGE_NO
STAGE_ENTERED_DATE
0
2015-12-01 14:16:47
1
null
2
null
3
null
4
null
5
null
6
2017-02-12 0:00:00
7
2017-12-12 0:00:00
I want a new column that will give me the next stage_no where "stage_entered_date" is not-null.
This is the result that I am expecting:
STAGE_NO
STAGE_ENTERED_DATE
Next_Stage
0
2015-12-01 14:16:47
6
1
null
6
2
null
6
3
null
6
4
null
6
5
null
6
6
2017-02-12 0:00:00
7
7
2017-12-12 0:00:00
null
Disclaimer: Next_Stage column means next_stage where date is not null.
You can do this using the lead window function, ignoring nulls, and redefining nulls as the null in a different column using the IFF function:
with T1 as
(
select
COLUMN1::int as "STAGE_NO",
COLUMN2::timestamp as "STAGE_ENTERED_DATE"
from (values
('0','2015-12-01 14:16:47'),
('1',null),
('2',null),
('3',null),
('4',null),
('5',null),
('6','2017-02-12 0:00:00'),
('7','2017-12-12 0:00:00')
)
)
select STAGE_NO
,STAGE_ENTERED_DATE
,lead(iff(STAGE_ENTERED_DATE is not null, STAGE_NO, null))
ignore nulls over (partition by null order by STAGE_NO) as NEXT_STAGE
from T1
;
STAGE_NO
STAGE_ENTERED_DATE
NEXT_STAGE
0
2015-12-01 14:16:47.000000000
6
1
null
6
2
null
6
3
null
6
4
null
6
5
null
6
6
2017-02-12 00:00:00.000000000
7
7
2017-12-12 00:00:00.000000000
null
This will perform the stage calculation across the entire table. You probably have something like a customer, company, or some other "thing" that goes through these stages. You can specify what that is using a partition by clause in the window function. It's currently set to null, but you can simply change it to the column that defines the sets of rows for the phases.

Find the max value from previous row

I want to find in the below rows the maximum "book_type" value:
book_id
book_type
book_time
uniq_step
book_ordered
1
2022-10-13 00:00:00
800
0
1
2022-10-13 00:00:00
801
0
1
poetry
2022-10-13 00:00:00
802
1
1
2022-10-13 00:00:00
803
0
1
2022-10-13 01:00:00
804
0
1
poetry
2022-10-13 01:00:00
802
1
I want in the line with uniq_step = 804 to have as book_type = poetry but when I use the LAG window function I am getting ' ' (the space string).
So is there any way to take from the partition by book_time the max value as a lag?
You could try using the LAST_VALUE window function in place of the LAG one. Since your "book_type" values can't be NULL in your specific case, you can use a CASE statement inside the window function to make them NULL.
LAST_VALUE(CASE WHEN book_type <> "" THEN book_type END) OVER(
PARTITION BY book_id
ORDER BY uniq_step
)
Side Note: Empty spaces/strings are still values in a DBMS. If you have the possibility of refactoring the empty values in your db to NULL values, that will make the DBMS handle your data better than how it does now.

How do I select / identify a row based on criteria in a different row in SQL

I've never posted on here before but, I am really stumped on this and looking for any assistance I get! I am not the best SQL code writer and I do not understand every concept but I am quick learner. So, I am not sure this is best way to accomplish my goal and if there is a more efficient way to complete this, I would be open to learning. I appreciate any help that can be provided.
Task:
I am attempting to write a SQL code that will help me place a number under the "Grab" column that allows me to exclude other rows out that are not needed.
Issue:
Pricing has a timeframe when it is applicable. The [PriceBookTable] captures the time frame range for each price book that is listed. However, as time goes on, some price books become outdated and do not need to be reviewed.
Based on today's date, I am trying to identify the previous version price book as well as the next version (if there is one).
Table Used: [PriceBookTable]
ID
Description
CategoryID
ParentID
StartDate
EndDate
412
56 MSRP
56
NULL
NULL
NULL
413
3 MSRP
3
NULL
NULL
NULL
414
61 MSRP
61
NULL
NULL
NULL
415
63 MSRP
63
NULL
NULL
NULL
419
58 MSRP
58
NULL
NULL
NULL
420
62 MSRP
62
NULL
NULL
NULL
430
67 MSRP
67
NULL
NULL
NULL
431
68 MSRP
68
NULL
NULL
NULL
505
2020 Version 1
56
412
2020-08-31
2020-12-31
537
2021 Version 1
56
412
2021-01-01
2021-03-31
586
2021 Version 2
56
412
2021-04-01
2021-04-13
622
2021 Version 3
56
412
2021-04-14
2021-07-31
688
2021 Version 4
56
412
2021-08-01
2021-12-31
Current Code:
USE [Database]
DECLARE #PriceBookID AS VARCHAR(10)
SET #PriceBookID = '412' --Parent Price Book ID
SELECT A.*,
[Grab] = CASE WHEN A.ParentID IS NULL AND A.StartDate IS NULL AND A.EndDate IS NULL THEN 1 -- Always needs to be #1
WHEN CAST(GETDATE() AS DATE) BETWEEN A.StartDate AND A.EndDate THEN 3 --Currently Active Price Book based on Today's Date
ELSE NULL END
FROM( SELECT ID,
ParentID,
[PriceBookDescription] = Description,
StartDate,
EndDate,
[ActivePriceBook] = CASE WHEN CAST(GETDATE() AS DATE) BETWEEN StartDate AND EndDate THEN 'Active' ELSE NULL END,
[PBOrder] = ROW_NUMBER() OVER (ORDER BY ID ASC)
FROM [PriceBookTable]
WHERE 1=1 AND ID IN (#PriceBookID) OR ParentID IN (#PriceBookID)) A
Current Output:
ID
ParentID
PriceBookDescription
StartDate
EndDate
ActivePriceBook
PBOrder
Grab
412
Null
MSRP
NULL
NULL
NULL
1
1
505
412
2020 Version 1
2020-08-31
2020-12-31
NULL
2
NULL
537
412
2021 Version 1
2021-01-01
2021-03-31
NULL
3
NULL
586
412
2021 Version 2
2021-04-01
2021-04-13
NULL
4
NULL
622
412
2021 Version 3
2021-04-14
2021-07-31
Active
5
3
688
412
2021 Version 4
2021-08-01
2021-12-31
NULL
6
NULL
Notes:
I originally was hoping that the "PBOrder" column would be useful for me but, as time goes on the list becomes bigger as more price books are created and, for example, row #4 [ID 586] will not always be relevant.
I would have just placed a "WHERE ID IN ('412','586','622','688')" statement but the ID's change based on different categories (not shown). So, I am stuck to the date range.
Desired Output:
ID
ParentID
PriceBookDescription
StartDate
EndDate
ActivePriceBook
PBOrder
Grab
412
Null
MSRP
NULL
NULL
NULL
1
1
586
412
2021 Version 2
2021-04-01
2021-04-13
NULL
4
2
622
412
2021 Version 3
2021-04-14
2021-07-31
Active
5
3
688
412
2021 Version 4
2021-08-01
2021-12-31
NULL
6
4
I hope this makes sense and please let me know if you have any questions regarding this.
Thank you again for any help!
Took me awhile to understand what you wanted, but after figuring it out I was able to address what you need. Basically, you want:
To identify a single active record within a category based on the current date.
Then get the adjacent inactive records, with respect to time, that share a parent record.
Then get the record for the parent category and include it in the result set.
The 'pbOrder' and 'grab' columns seem to be throughputs to achieve this goal. You don't need them in the output.
If this is all correct, then you can delegate your identification of an active record to a cross apply calculation, and then use lead and lag in addition to the raw result to identify the active record as well as the adjacent ones in time.
declare #PriceBookID int = 412; -- why varchar, I would use int
with rowsToGrab as (
select pbt.*,
ap.activePriceBook,
grab =
case
when pbt.ParentID is null then 1
when lead(ap.ActivePriceBook) over(order by pbt.startDate) is not null then 1
when lag(ap.ActivePriceBook) over(order by pbt.startDate) is not null then 1
when ap.ActivePriceBook is not null then 1
end
from #PriceBookTable pbt
cross apply (select ActivePriceBook =
case
when cast(getdate() as date) between startdate and enddate then 'Active'
end
) ap
where #PriceBookID in (ID, ParentID)
)
select id, ParentID, description as PriceBookDescription, StartDate, EndDate, ActivePriceBook
from rowsToGrab
where grab is not null
order by id, StartDate
This produces:
id
ParentID
PriceBookDescription
StartDate
EndDate
ActivePriceBook
412
56 MSRP
586
412
2021 Version 2
2021-04-01
2021-04-13
622
412
2021 Version 3
2021-04-14
2021-07-31
Active
688
412
2021 Version 4
2021-08-01
2021-12-31

SQL Order By on multiple columns containing Nulls

I have a table containing multiple columns, and I want to order by three of the columns within the table. I want to order by lot, then unit, and lastly number. Lot and Unit can contain nulls (need them listed at the bottom) whereas Number column does not contain Null. I've tried a bunch of case statements but its not giving the desired result. - Order by ... Nulls last is not an option.
Lot
Unit
Number
Null
Null
500
Null
Null
425
Null
Null
424
Null
7
419
Null
9
450
25
Null
475
22
Null
486
22
Null
485
19
7
465
19
9
432
Desired result:
Lot
Unit
Number
19
7
465
19
9
432
22
Null
485
22
Null
486
25
Null
475
Null
7
419
Null
9
450
Null
Null
424
Null
Null
425
Null
Null
500
you can do order by checking the nulls:
SELECT *
FROM yourtable
ORDER BY CASE WHEN lot IS NULL THEN 1 ELSE 0 END
, lot
, CASE WHEN unit IS NULL THEN 1 ELSE 0 END
, unit
, number
You have tagged your question SQL, but not mentioned the database. Standard SQL has a very convenient way to do what you want:
order by Lot nulls last, Unit nulls last, Number
Not all databases support nulls last and nulls first, but this is the standard SQL solution.

SQL: Create a new id column that changes based on the values of other three columns? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have a table with three columns named cid, orderdate, and priororderdate among others.
Here is how the table looks:
cid orderdate priororderdate position
12 NULL NULL 1
12 NULL NULL 2
12 NULL NULL 3
12 2014-08-08 23:25 NULL 1
12 2014-08-08 23:25 NULL 2
12 2014-08-08 23:25 NULL 3
12 2014-08-08 23:25 NULL 4
12 2014-09-06 17:19 2014-08-08 23:25 1
12 2014-09-06 17:19 2014-08-08 23:25 2
12 2014-09-06 17:19 2014-08-08 23:25 3
13 NULL NULL 1
13 NULL NULL 2
13 NULL NULL 3
The combination of the columns cid, orderdatetime, and priororderdatetime defines a unique fpid (a new column I want to create). Hence, the final result would be:
cid orderdate priororderdate position fpid
12 NULL NULL 1 1
12 NULL NULL 2 1
12 NULL NULL 3 1
12 2014-08-08 23:25 NULL 1 2
12 2014-08-08 23:25 NULL 2 2
12 2014-08-08 23:25 NULL 3 2
12 2014-08-08 23:25 NULL 4 2
12 2014-09-06 17:19 2014-08-08 23:25 1 3
12 2014-09-06 17:19 2014-08-08 23:25 2 3
12 2014-09-06 17:19 2014-08-08 23:25 3 3
13 NULL NULL 1 4
13 NULL NULL 2 4
13 NULL NULL 3 4
How can I create the fpid column?
You can do this using dense_rank() in a select query:
select t.*,
dense_rank() over (order by cid, orderdate, priororderdate) as fpid
from table t;
If you have the column fpid already in the table and want to update it:
with toupdate as (
select t.*,
dense_rank() over (order by cid, orderdate, priororderdate) as new_fpid
from table t
)
update toupdate
set fpid = new_fpid;
(If you want to add it, you can use an alter table statement.)
It's a little bit confusion that you say that fpid is unique, but looking at your desired output, it looks like you want to use ROW_NUMBER().
UPDATE tab2 t SET fpid =
(SELECT ROW_NUMBER () OVER (ORDER BY cid)
FROM tab2
GROUP BY cid, orderdate, priororderdate
WHERE t.cid = cid
AND t.orderdate = orderdate
AND t.priororderdate = priororderdate)