sql - 行不属于子查询时的最后一个非空值
问题描述
考虑下表“演示”
Id Value
1 Sample 1
2 Sample 2
3 NULL
4 NULL
5 NULL
6 Value 4
7 NULL
8 Value5
9 NULL
10 value6
定义为
CREATE TABLE [dbo].[Demo](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Value] [nvarchar](max) SPARSE NULL,
CONSTRAINT [PK_Demo] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
在此表中,Value 字段(根据业务逻辑)应该只有在发生更改时才会更改。如果该值没有改变,它将用 NULL 表示(暗示它具有最后一个非空值)。
要检索遇到的每个 null 的最后一个 Known Value,我使用以下查询(灵感来自Link)。
WITH C AS
(
SELECT id, [Value],
MAX( CASE WHEN [Value] IS NOT NULL THEN id END )
OVER( ORDER BY id
ROWS UNBOUNDED PRECEDING ) AS grp
FROM demo
)
SELECT id, [value],
MAX([value]) OVER( PARTITION BY grp
ORDER BY id
ROWS UNBOUNDED PRECEDING ) AS LastValue
FROM C
这将根据需要检索所有值。
id value LastValue
1 Sample 1 Sample 1
2 Sample 2 Sample 2
3 NULL Sample 2
4 NULL Sample 2
5 NULL Sample 2
6 Value 4 Value 4
7 NULL Value 4
8 Value5 Value5
9 NULL Value5
10 value6 value6
正如屏幕截图所示,只要我检索整个表格,它就可以正常工作。但是,当我只检索一个子集时,它就成了一个问题。例如,如果我只需要在Id>2处获取信息,我会得到以下结果。
id value LastValue
3 NULL NULL
4 NULL NULL
5 NULL NULL
6 Value 4 Value 4
7 NULL Value 4
8 Value5 Value5
9 NULL Value5
10 value6 value6
如前所述,第一行 (ID=3) 的值为“NULL”。但是,在数据库中,它有一个Sample 2
来自行 (ID=2) 的值,由于我们添加的条件,它不是查询的一部分。
有人可以建议一种方法,即使子查询不包含特定行(该行不必是前一行,它应该具有最后一个非空值),我仍然可以获取 Last Non-Value 值?我对上述情况的预期结果如下。
id value LastValue
3 NULL Sample 2
4 NULL Sample 2
5 NULL Sample 2
6 Value 4 Value 4
7 NULL Value 4
8 Value5 Value5
9 NULL Value5
10 value6 value6
在实际场景中,可能有多个稀疏/可空列(如值),对于每个列,我都需要获取最后一个已知值。但是,为简单起见,以单列为例。
PS:但是表中的 first 是 NULL 的情况。从业务逻辑的角度来看,这被认为是异常值。
解决方案
只需使用子查询在您选择的范围之前提取第一个非空值,然后将其用于第一个Grp
如果为空。
WITH C AS
(
SELECT Id, [Value]
, MAX(CASE WHEN [Value] IS NOT NULL THEN Id END) OVER (ORDER BY Id ROWS UNBOUNDED PRECEDING) AS Grp
-- Find the first value prior to our resultset in case we start from null
, (SELECT TOP 1 [Value] FROM #demo D1 WHERE D1.Id < D.Id AND [Value] IS NOT NULL ORDER BY D1.Id DESC) InitialValue
FROM #demo D
WHERE Id > 2
)
SELECT Id, [value], Grp, InitialValue
, CASE WHEN Grp IS NULL THEN InitialValue ELSE MAX([value]) OVER (PARTITION BY Grp ORDER BY Id ROWS UNBOUNDED PRECEDING) END AS LastValue
FROM C;
回报:
ID | 价值 | 最后值 |
---|---|---|
3 | 空值 | 样品 2 |
4 | 空值 | 样品 2 |
5 | 空值 | 样品 2 |
6 | 价值 4 | 价值 4 |
7 | 空值 | 价值 4 |
8 | 价值 5 | 价值 5 |
9 | 空值 | 价值 5 |
10 | 价值 6 | 价值 6 |
推荐阅读
- r - 这种类型的情节可以用ggplot2完成吗?
- php - 在表单的标签中显示搜索到的数据
- java - java.lang.RuntimeException: android.os.TransactionTooLargeException: 数据包大小 1058220 字节
- r - 在 R 编程中动态访问变量名
- java - 一旦我运行自动化测试场景,有没有办法使用自动化测试场景本身检查 Linux 服务器日志错误消息和异常
- json - 使用 java 使用 jira rest
- amazon-emr - 在 postgresql 上为 EMR 设置远程配置单元元存储
- angular - 从html文本输入与路由器交互的角度最佳方式
- c++ - make_unique 和 make_shared 处理数组时的区别
- android - android.* vs androidx.* 包在android中的实现和使用的区别