无法为sql server标量值函数中的变量赋值

时间:2015-04-13 19:03:48

标签: sql-server tsql

我有一张表,本质上是一个客户清单,包含许多'bit'和'datetime'字段。对于位字段,1表示已完成,0表示未完成,日期时间字段包含有关特定核对表项目何时完成的信息。每个核对表项目实际上都是一个单独的列。我知道这可能不是最干净的设计,但它是我提出的最好的。

现在,我正在尝试编写一个标量值函数,通过核对表评估客户端的进度。此函数循环遍历位类型的所有列,并查看有多少是1或0,并返回完成百分比。

请参阅以下代码

    ALTER FUNCTION [dbo].[Get_ClientProgress]
(
    -- ClientID parameter refers to ClientID column in CHECKLIST Table
    @ClientID int
)
RETURNS float
AS
BEGIN
    DECLARE
    @totalRows int,
    @fieldChecked bit, 
    @colBuffer nvarchar(50), 
    @intCounter int, 
    @valueBuffer int,   -- holds the cumulative total of bit fields that are marked true in CHECKLIST Table
    @sql nvarchar(max),
    @ClientProgress float

    -- temporary table to hold column names
    DECLARE @temp TABLE
            (
                Row int,
                Column_Name nvarchar(50)
            )
    -- First, get the total number of 'bit' fields in the CHECKLIST table
    SELECT @totalRows = Count(Data_type)
                        FROM information_schema.columns 
                        WHERE data_type = 'bit' AND Table_Name = 'CHECKLIST'

    -- the purpose of @temp is just to reorganize the CHECKLIST table in a top to bottom fashion instead of left to right
    -- This makes it easier to loop through each field
    INSERT INTO @temp
        SELECT row_number() OVER(ORDER BY Column_name) as Row, Column_name
        FROM information_schema.columns 
        WHERE data_type = 'bit' AND Table_Name = 'CHECKLIST'

    SET @intcounter= 1  -- counter used for the loop; will also hold row number
    SET @valueBuffer = 0    -- will hold the cumulative value

    -- begin loop to find how many fields are marked true
    WHILE (@intCounter <= @totalRows)
        BEGIN
            SET @colBuffer = (SELECT Column_Name FROM @temp WHERE Row = @intCounter)
            -- The next line is where I'm having trouble
            SET @fieldChecked = (SELECT (CASE WHEN @colBuffer = 1 THEN 1 ELSE 0 END) FROM [dbo].[CHECKLIST] WHERE ClientID = @ClientID)
            SET @valueBuffer = @valueBuffer + @fieldChecked
            SET @intCounter = @intCounter + 1
        END
    IF @valueBuffer is NULL
        SELECT @ClientProgress = 0
    ELSE
        SELECT @ClientProgress = CAST(@valueBuffer as float) / CAST(@totalRows as float)
    -- Return the result of the function
    RETURN @ClientProgress
END

在上面的代码中,我无法使用给定的SELECT语句为@fieldChecked赋值。我只是想获取@colBuffer中保存的特定列名的位值。我也尝试过以下陈述,但这些都没有奏效:

SELECT @colBuffer FROM BUYER_CHECKLIST WHERE ClientID = @ClientID
SELECT TOP 1 @colBuffer FROM BUYER_CHECKLIST WHERE ClientID = @ClientID
SELECT COUNT(CASE WHEN @colBuffer = 1 THEN 1 ELSE 0 END) FROM BUYER_CHECKLIST WHERE ClientID = @ClientID
SELECT SUM(CASE WHEN @colBuffer = 1 THEN 1 ELSE 0 END) FROM BUYER_CHECKLIST WHERE ClientID = @ClientID

我在这里做错了什么?

2 个答案:

答案 0 :(得分:0)

试试这个:(你似乎有太多的括号): 改变:

SET @fieldChecked = (SELECT (CASE WHEN @colBuffer = 1 THEN 1 ELSE 0 END) 

为:

SELECT @fieldChecked= CASE WHEN @colBuffer = 1 THEN 1 ELSE 0 END  tempname FROM  

答案 1 :(得分:0)

看起来你只是在@colBuffer中选择了值,而不是在该值之后命名的列中的任何内容。您需要创建动态sql。这是一个例子:

create table #sample (
        ID int,
        colA nvarchar(100),
        colB nvarchar(100)
    )

insert #sample values
    (1, 'xxx', 'yyy')

declare @colBuffer nvarchar(100) = 'colA'

-- ONE WAY:
declare @sql nvarchar(max) = '
    select ' + @colBuffer + ' from #sample
    '
exec(@sql)

-- ANOTHER WAY:
select  case
            when @colBuffer = 'colA' then colA
            when @colBuffer = 'colB' then colB
            else ''
        end
    from #sample

drop table #sample