T-SQL LAG函数默认值

3

如果在联接表中没有记录并且您只引用联接表字段,则 LAG 函数的默认参数为什么只适用于返回结果的第一列?

为了更好地解释这一点,我创建了以下情境。

架构

  CREATE TABLE Blogs(
    Id int IDENTITY(1,1) CONSTRAINT PK_Blogs_Id PRIMARY KEY,
    Title NVARCHAR(1000)
  )
  
  CREATE TABLE Comments(
    Id int IDENTITY(1,1) CONSTRAINT PK_Comments_Id PRIMARY KEY,
    BlogId INT NOT NULL,
    CommentText NVARCHAR(max)
  )
  
  INSERT INTO Blogs (Title) VALUES ('Blog 1')
  INSERT INTO Blogs (Title) VALUES ('Blog 2')
  INSERT INTO Blogs (Title) VALUES ('Blog 3')
  INSERT INTO Blogs (Title) VALUES ('Blog 4')
  INSERT INTO Blogs (Title) VALUES ('Blog 5')
  
  INSERT INTO Comments (BlogId, CommentText) VALUES (4,'Some text')
  INSERT INTO Comments (BlogId, CommentText) VALUES (4,'Some text 2')

查询

SELECT *, 
  LAG(CommentText,1,'No comment') OVER (Partition by Comments.BlogId ORDER BY Comments.Id Desc) LastComment
FROM Blogs LEFT JOIN Comments on Blogs.Id = Comments.BlogId;

在上面的查询中,它将返回第一行“LastComment”为“无评论”的结果,并且在行具有其他评论的情况下,其余部分将为空。
我知道如果您在窗口函数中引用Blogs的键(以下查询),它会正确运行(所有为空的行将在LastComment字段中返回“无评论”),但我正试图理解为什么如果连接返回空值,则LAG函数中的默认参数不会应用于LastComment。
SELECT *, 
  LAG(CommentText,1,'No comment') OVER (Partition by Blogs.Id ORDER BY Comments.Id Desc) LastComment
FROM Blogs LEFT JOIN Comments on Blogs.Id = Comments.BlogId;

这是一个关于IT技术的SQL fiddle示例,链接为http://sqlfiddle.com/#!18/eb850/9
编辑说明:需要澄清的是,在这个SQL fiddle示例中,为什么Blog 1返回默认值“无评论”,而其他也没有评论的博客返回NULL。为什么第一行会被分配默认值,而其他行不会?既然LAG没有记录可读,Blog 1也应该返回NULL,为什么没有呢?

大多数情况下,Comments.BlogId 为空,而 Blogs.Id 不为空。 - Zohar Peled
1
@ZoharPeled 我知道它大多数时候是 null。问题是,当它仅引用 Comments 表中的字段时,为什么在 LAG 函数中它不会被默认值替换,以及为什么在这种情况下默认值仅适用于第一行。 - ClassyBear
因为分区不同... - Zohar Peled
2
重点是,默认情况下是针对未满足滞后行的情况...如果滞后行上有空值,那么你将得到空值。如果你想要除了空值之外的其他内容,请使用 Lag(isnull(CommentText,'No comment'),1,'No comment' ) - Clay
1个回答

0
在SQL Server中,LAG()函数用于访问结果集中基于排序列的前一行。它有一个可选的默认参数,如果没有前一行,则指定要返回的值。
如果您使用LAG()函数来访问连接表中的列,并且连接表中没有记录与第一个表中的当前行匹配,则默认参数仅适用于返回结果的第一列。这是因为LAG()函数旨在为结果集中的每一行返回单个值,如果连接表中没有匹配行,则不可能为单个行返回多个值。
例如,请考虑以下查询:
SELECT t1.id, t1.data, t2.data
FROM table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.id

如果在table1中的某一行没有匹配的table2行,那么该行的t2.data列将为NULL。如果您想使用LAG()函数访问t2.data的前一个值,则可以使用以下查询:
SELECT t1.id, t1.data, t2.data, LAG(t2.data) OVER (ORDER BY t1.id) AS prev_data
FROM table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.id

在这种情况下,LAG()函数将基于OVER()子句中指定的排序返回结果集中每一行t2.data的前一个值。如果没有前一行,则将使用LAG()函数中指定的默认值。由于只有使用LAG()函数访问的prev_data列,因此此默认值仅适用于prev_data列。结果集中的其他列(t1.id、t1.data和t2.data)不会受到默认值的影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接