如何将udtt单独传递给SQL中的另一个函数

时间:2011-12-07 04:49:56

标签: sql function parameters

假设我想从两个表中获得学生摘要:学生,年级:

CREATE PROCEDURE prc_get_student_grade_summaries
    @studentIds [Integer_udtt] READONLY
AS
BEGIN
SELECT Name,
    func_GetGradeAForStudent()
FROM tbl_student AS tS
    INNER JOIN
    @studentIds AS tSI
    ON tS.Id = tSI.studentId   

整数udtt定义如下:

CREATE TYPE [Integer_udtt] AS  TABLE (
    [Id] INT NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC));

func_GetGradeAForStudent类似于学生选择COUNT(*),其中studentId = id AND grade = 1 - 1:A

我想要的结果是摘要列表:

StudentId  Number of A
101   5
102   4
103   2

将studentId从@studentId传递给func_GetGradeAForStudent的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

您无法将表值参数传递给UDF:

MSDN:

  

表值参数的限制

     

表值参数有几个限制:

     

您不能将表值参数传递给用户定义的函数。

     

表值参数只能被索引以支持UNIQUE或PRIMARY KEY约束。 SQL Server不维护统计信息   表值参数。

     

表值参数在Transact-SQL代码中是只读的。您无法更新表值行中的列值   参数,您不能插入或删除行。修改数据   传递给存储过程或参数化语句   表值参数,必须将数据插入临时   表或表变量。

     

您不能使用ALTER TABLE语句来修改表值参数的设计。

由于这些只是学生ID的列表,一种可能性是将这些ID作为逗号分隔的id列表传递,并使用split函数从逗号分隔列表中重新创建表。在SO和其他地方有大量示例,您可以在其中找到拆分函数的示例实现。

甚至更好,在你的proc中做所有事情。如果一切都在select count(*)...,我真的没有看到对该函数的需要你应该能够内联所有内容,也许可以使用子选择:

CREATE PROCEDURE prc_get_student_grade_summaries
    @studentIds [Integer_udtt] READONLY
AS
BEGIN
SELECT Name,
    (select COUNT(*) from student where studentId = tSI.studentId AND grade = 1 ) as NumberOfAs
FROM tbl_student AS tS
    INNER JOIN
    @studentIds AS tSI
    ON tS.Id = tSI.studentId   

<强>更新

示例拆分函数,它以逗号分隔的列表并返回一个表:

CREATE FUNCTION [dbo].[fnSplit](
    @sInputList VARCHAR(8000) -- List of delimited items
  , @sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
) RETURNS @List TABLE (item VARCHAR(8000))

BEGIN
DECLARE @sItem VARCHAR(8000)
WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
 BEGIN
 SELECT
  @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))),
  @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))

 IF LEN(@sItem) > 0
  INSERT INTO @List SELECT @sItem
 END

IF LEN(@sInputList) > 0
 INSERT INTO @List SELECT @sInputList -- Put the last item in
RETURN
END

你这样称呼:select * from fnSplit(@CommaSeparetedList,',');