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

时间:2017-04-10 22:46:00

标签: sql-server

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

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。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

使用CREATE TABLE时,必须分别使用列名和数据类型,但是当您编写fldScore列名时,会插入值而不是数据类型。因为CASE结构返回一个值,并且您只将此值作为浮点数转换。

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

答案 2 :(得分:0)

使用函数解决此问题的方法(如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)
);