【问题标题】:SQL Function not working the way I wantSQL 函数没有按我想要的方式工作
【发布时间】:2017-12-04 12:52:01
【问题描述】:

我写了这两个函数:

USE muziekdatabase
GO
CREATE FUNCTION fnSpecNivAantal
    (
        @Niveau as char(1)
    )

RETURNS char(1)
AS 

BEGIN

    DECLARE @Aantal AS int

    IF @Niveau = 'A'
    SET @Aantal = (SELECT COUNT(*) FROM STUK WHERE niveaucode = 'A')

    ELSE IF @Niveau = 'B' 
    SET @Aantal = (SELECT COUNT(*) FROM STUK WHERE niveaucode = 'B')

    ELSE IF @Niveau = 'C'
    SET @Aantal = (SELECT COUNT(*) FROM STUK WHERE niveaucode = 'C')

RETURN @Aantal

END

USE muziekdatabase
GO

ALTER FUNCTION fnHoogsteNummer 
    (
        @EersteNummer as numeric,
        @TweedeNummer as numeric
    )
RETURNS numeric 
AS 
BEGIN

    DECLARE @HoogsteNummer as VARCHAR(MAX)

    IF MAX(@Eerstenummer) > MAX(@TweedeNummer)
    SET @HoogsteNummer = @EersteNummer
    ELSE IF
    MAX(@Tweedenummer) > MAX(@Eerstenummer)
    SET @HoogsteNummer = @TweedeNummer
    ELSE IF
    @EersteNummer = @TweedeNummer
    SET @HoogsteNummer = 'Nummers zijn gelijk' 
    ELSE
    SET @HoogsteNummer = 'Er is iets fout gegaan'

    RETURN @HoogsteNummer
END

现在它们几乎可以正常工作了。但有一件事不太对劲。当我在函数中插入一个值时,结果是一个具有相同答案的整个列表。就像 10 行只有 3,它应该只有 1 行,数字 3。我知道我可以使用 DISTINCT,但我认为该函数有问题。我尝试使用CASE / WHEN,但这也不起作用..

【问题讨论】:

  • 标记您正在使用的 dbms。 (该代码是特定于产品的。)
  • MS SQL Server 2017
  • @MrEmper 。 . .您的代码有很多错误,我投票结束时过于宽泛。 (使用MAX()不带SELECT,设置字符串等于数字,函数定义为返回数字时返回字符串,毫无疑问更多)。
  • 它运行没有任何错误,你能说重点吗?
  • 您能否包含使用这些函数的查询以及一些输入样本和所需的输出?

标签: sql sql-server sql-server-2017


【解决方案1】:
CREATE FUNCTION fnSpecNivAantal
(
 @Niveau as char(1)
)
RETURNS INT  --<-- since you are returning count use INT variable not char
AS 
BEGIN

    DECLARE @Aantal AS int; 

    IF (@Niveau IN ('A' , 'B', 'C'))
     BEGIN
       SELECT @Aantal = COUNT(*) 
       FROM STUK WHERE niveaucode = @Niveau
     END

RETURN @Aantal

END

抱歉,您的第二个功能无法理解。

【讨论】:

  • 非常感谢!尽管它看起来好多了,但它仍然给出了相同的结果。 i.imgur.com/XKMtrgI.png
  • 对表中的每一行执行该函数。如果你想要一个简单的计数,你不应该使用函数,绝对不能使用SELECT *
  • 我的英雄,这就是解决方案!感谢大家的反馈和努力寻找正确的答案,我学到了很多东西,也是我使用这个论坛的方式!
【解决方案2】:

将这些函数更改为内联表值函数将提供一些性能优势。它们在考虑功能方面略有不同,但值得付出努力。您需要养成的一个习惯是定义变量和参数的大小和精度。不要偷懒,不要做数字之类的事情。您应该精确并定义大小。 SQL Server 不会自动调整小数位数和精度以满足它找到的值。相反,它使用默认大小,可能适合也可能不适合您的数据。

你的第一个函数可以大大简化为这个。

CREATE FUNCTION fnSpecNivAantal
(
    @Niveau as char(1)
)RETURNS TABLE AS RETURN

    SELECT Niveau = COUNT(*) 
    FROM STUK 
    WHERE niveaucode = @Niveau
        AND niveaucode IN ('A', 'B', 'C')

第二个有点不同。您将函数定义为返回数字(无比例或精度),但您的代码可以返回数字或字符串文字。这不起作用,因为函数的所有部分都必须返回相同的数据类型。没什么大不了的,您只需意识到您的返回数据类型在这里是 varchar 而不是数字。该函数可以像这样转换为内联表值函数。

ALTER FUNCTION fnHoogsteNummer 
    (
        @EersteNummer as numeric, --need to define scale and precision
        @TweedeNummer as numeric --need to define scale and precision
    )
RETURNS TABLE AS RETURN

    SELECT CASE WHEN @Eerstenummer > @TweedeNummer THEN convert(varchar(25), @EersteNummer)
            WHEN @TweedeNummer > @EersteNummer THEN convert(varchar(25), @TweedeNummer)
            WHEN @TweedeNummer = @EersteNummer THEN 'Nummers zijn gelijk' 
            ELSE 'Er is iets fout gegaan'
            END

请注意,这两个函数都是一个语句。这就是使它们成为内联表值函数的原因。如果你开始定义变量并有多个语句,它会变成一个多语句表值函数,性能甚至可能比标量函数更差。

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 2021-12-15
    • 2019-01-18
    • 1970-01-01
    • 2023-01-23
    • 1970-01-01
    • 2018-02-03
    • 2011-04-18
    相关资源
    最近更新 更多