【问题标题】:How to create a nullable record in SQL Server 2008 R2?如何在 SQL Server 2008 R2 中创建可为空的记录?
【发布时间】:2012-10-27 19:18:31
【问题描述】:

我在 SQL Server 2008 R2 中创建了一个Inline table function,我意识到一些查询会返回任何记录。所以我想当这种情况发生时,返回一个包含所有空列的记录。

举例:

Col1   Col2   Col3
NULL   NULL   NULL

更新:这里是函数

ALTER FUNCTION [dbo].[GetWorksheetSummaryByObjective](@objectiveId [smallint], @testTemplateId [smallint])
RETURNS @resultTable TABLE (
    [AnsweredWorksheetId] [smallint] NOT NULL,
    [LastDate] [date] NULL,
    [BestScore] [smallint] NULL,
    [ShouldBeMakeUp] [tinyint] NOT NULL
)
AS 
BEGIN

    INSERT @resultTable
    SELECT TOP 1 B.Id AS AnsweredWorksheetId, A.Date, CONVERT(smallint, B.Score * 100),
        CASE
        WHEN B.Score >= 0.7 THEN 0
        ELSE 1
        END AS ShouldBeMakeUp
    FROM AnsweredTest AS A
    RIGHT JOIN AnsweredWorksheet AS B ON (A.Id = B.AnsweredTestId)
    WHERE B.ObjectiveId = @objectiveId AND A.ExamTemplateId = @testTemplateId
    ORDER BY B.Score DESC

    RETURN
END

【问题讨论】:

  • 您的意思是说“我意识到一些查询返回任何记录。”? (即不是返回零行,而是要返回包含所有列的单行 NULL?)请发布函数。
  • 您必须帮助我们了解您是如何实现查询返回任何记录的,您知道的:)
  • @MartinSmith 对不起我的英语不好,你是对的
  • 您发布的功能是多语句 TVF,而不是内联 TVF。内联 TVF 有 RETURNS TABLE,不能有任何过程逻辑,并且通常比多语句更有效,因为它们内联到查询中并且可以在上下文中进行优化。
  • 为什么你想要一个全为 NULL 的行而不是没有行?也许您应该使用外部连接...

标签: sql-server sql-server-2008-r2 sql-function


【解决方案1】:

您发布的功能是不是内联 TVF。

鉴于基础查询最多返回 1 行,因为 TOP 1SELECT MAX() 没有 GROUP BYHAVING 始终返回单行,您可以将其作为内联 TVF 执行,但如下所示。

CREATE FUNCTION [dbo].[Getworksheetsummarybyobjective](@objectiveId    [SMALLINT],
                                                       @testTemplateId [SMALLINT])
RETURNS TABLE
AS
    RETURN
      (SELECT Max(AnsweredWorksheetId) AS AnsweredWorksheetId,
              Max([LastDate])          AS [LastDate],
              Max([BestScore])         AS [BestScore],
              Max(ShouldBeMakeUp)      AS ShouldBeMakeUp
       FROM   (SELECT TOP 1 B.Id                             AS AnsweredWorksheetId,
                            A.Date                           AS [LastDate],
                            CONVERT(SMALLINT, B.Score * 100) AS [BestScore],
                            CASE
                              WHEN B.Score >= 0.7 THEN 0
                              ELSE 1
                            END                              AS ShouldBeMakeUp
               FROM   AnsweredTest AS A
                      RIGHT JOIN AnsweredWorksheet AS B
                        ON ( A.Id = B.AnsweredTestId )
               WHERE  B.ObjectiveId = @objectiveId
                      AND A.ExamTemplateId = @testTemplateId
               ORDER  BY B.Score DESC) T) 

【讨论】:

  • @AndriyM - 不。如果子查询返回零行,则获取单行。
  • 是的,这就是我错过的,感谢您的解释。替代方案可能是SELECT T.* FROM (VALUES (NULL)) dummy (dummy) LEFT JOIN (SELECT TOP 1 ... ) T ON 1=1
【解决方案2】:

这样的东西有用吗?

declare @tbl table
(
  Col1 int, Col2 int, Col3 int
)

insert @tbl (Col1, Col2, Col3)
     select Col1, Col2, Col3 from SomeTable where blah = blah

if exists (select 1 from @tbl)
begin
    select Col1, Col2, Col3 from @tbl
end
else
begin
    select null Col1, null Col2, null Col3
end

【讨论】:

  • if ... else 不允许在内联 TVF 中
  • 请替换else部分中的begin
  • @MartinSmith 谢谢,不知道。
【解决方案3】:

好的,跳过我的其他答案 - 没有意识到表函数有多么严格。我有另一个想法 - 这个应该可以工作,但这意味着必须在函数中运行 WHERE 两次,所以要加倍资源来进行调用:

CREATE FUNCTION dbo.SomeTest
    ( @i int ) 
RETURNS TABLE
as
RETURN 
    select Col1, Col2 from SomeTable
    where Whatever = Whatever

    union all

    select null Col1, null Col2
    where not exists (select 1 from SomeTable where Whatever = Whatever)
go

编辑:想了另一种方法来做到这一点,而无需双重浸渍:

create function dbo.SomeTest
    ( @i int )
returns table
as
return
select t.Col1, t.Col2 from 
(
    select Col1, Col2
    from SomeTable
    where Whatever = Whatever
) t
right join
(
    select 1 testcol
) x on c.Col1 is not null
go

这假定 Col1 是一个非空列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多