为啥我不能在计算列的 case 语句中使用子查询

Posted

技术标签:

【中文标题】为啥我不能在计算列的 case 语句中使用子查询【英文标题】:Why Can't I use sub-queries within a case statement in a calculated column为什么我不能在计算列的 case 语句中使用子查询 【发布时间】:2017-04-10 22:45:59 【问题描述】:

我正在尝试运行以下查询:

create table MyTable (
    TableIndex bigint primary key identity(1,1) not null,
    ForeignKey1 int not null,
    ForeignKey2 char(16) not null,
    fldSomeNumber float(24),
    fldScore as cast(case
            when fldSomeNumber is null or fldCSIPercentage=0 then 0
            when fldSomeNumber <= 0.09 then (select fldTenthScore from tblScores where ScorePrimaryKey=MyTable.ForeignKey2)
            when fldSomeNumber <= 0.9 then (select fld1Score from tblScores where ScorePrimaryKey=MyTable.ForeignKey2)
            ...
            else 100 end as float(24))
);

但我不断收到以下错误:“在此上下文中不允许子查询。只允许标量表达式。”不能将子选择放在这样的计算列中吗?

我正在运行 SQL Server Express 2016。

【问题讨论】:

【参考方案1】:

您根本无法使用单个表完成您的要求,您需要使用视图并将计算列放在视图上。

所以看起来像这样的视图

CREATE VIEW MyView AS

SELECT
 cast(case
            when fldSomeNumber is null or fldCSIPercentage=0 then 0
            when fldSomeNumber <= 0.09 then tblScores.fldTenthScore
            when fldSomeNumber <= 0.9 then tblScores.fld1Score
            ...
            else 100 end as float(24)) AS fldScore
FROM
MyTable 
INNER JOIN tblScores 
ON tblScores.ScorePrimaryKey = MyTable.ForeignKey2

查看此问题的第二个答案:

formula for computed column based on different table's column

【讨论】:

【参考方案2】:

使用CREATE TABLE时,必须分别使用列名和数据类型,但这里写fldScore列名时,插入的是值而不是数据类型。因为CASE 结构返回一个值,而您只将该值转换为浮点数。

但是,如果您的意思是计算列,则只能使用当前表中的列来定义计算列,而不是来自其他表。

【讨论】:

这是一个没有指定数据类型的计算列。【参考方案3】:

用函数解决这个问题的方法(mallan1121推荐的)如下:

IF EXISTS (
    SELECT * FROM sysobjects WHERE id = object_id('fnCalculateScore') 
    AND xtype IN ('FN', 'IF', 'TF')
)
    DROP FUNCTION fnCalculateScore
go

create function fnCalculateScore (
    @SomeNumber float(24),
    @SomeKey char(16)
)
returns float(24)
with schemabinding
as
begin
    return (select case
            when @SomeNumber is null or @SomeNumber=0 then 0
            when @SomeNumber <= 0.09 then (select fldTenthScore from dbo.tblScores where ScorePrimaryKey=@SomeKey)
            when @SomeNumber <= 0.9 then (select fld1Score from dbo.tblScores where ScorePrimaryKey=@SomeKey)
            ...
            else 100 end as float(24))
end
go

create table MyTable (
    TableIndex bigint primary key identity(1,1) not null,
    ForeignKey1 int not null,
    ForeignKey2 char(16) not null,
    fldSomeNumber float(24),
    fldScore as dbo.fnCalculateScore(fldSomeNumber, ForeignKey2)
);

【讨论】:

以上是关于为啥我不能在计算列的 case 语句中使用子查询的主要内容,如果未能解决你的问题,请参考以下文章

不使用 EXISTS 嵌套 case 语句引入子查询时,选择列表中只能指定一个表达式

为啥在 Oracle 中使用 CASE 进行子选择比 JOIN WITH OR 更快

如何在 caes 语句中使用子查询

SQL语句汇总——聚合函数分组子查询及组合查询

如何克服 Hive for CASE 语句中的子查询

SQL语句汇总(三)——聚合函数分组子查询及组合查询 - Darly