如何从 SQL Server 存储过程中的 3 列中获取 MAX 值?

Posted

技术标签:

【中文标题】如何从 SQL Server 存储过程中的 3 列中获取 MAX 值?【英文标题】:How to get a MAX value from 3 columns in SQL Server stored procedures? 【发布时间】:2021-12-27 18:21:14 【问题描述】:

我正在开发一个使用 C# 和 SQL Server 数据库的项目。现在我必须编写一个存储过程,它需要从 3 个不同的列中获取一个 MAX 值。

我的代码如下所示:

CREATE PROCEDURE [dbo].[sp_GetClass]
    @surname nvarchar(50),
    @maxClass int OUT
AS
    SELECT @maxClass = MAX 
    FROM (VALUES (Programming), (Mathematics), (Physics)) 
    FROM MissLess 
    WHERE Surname LIKE '%' + @surname + '%'
GO

我收到第二个FROM 的错误,我不知道如何解决它。

这个想法是让它在输入姓氏时从这些列中获取最大值。当没有输入时(按回车键),它只显示所有姓氏中这 3 列的最大值。

对不起,如果格式或问题没有被问到,这是我在这里的第一篇文章。

编辑:@name 出错,应该是@surname;并且名称应该是姓氏。 编辑最终版:感谢您的出色帮助。我是所有这一切的超级新手,但这一切似乎都很有趣。差点就放弃了,但决定试一试。谢谢大家的回答!!!

【问题讨论】:

旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀! 感谢您提供的信息。我才刚开始,老师很可能会让我们知道这件事。感谢您的提醒。 或者,如果您使用的是 Azure SQL 数据库,请查看 GREATEST 函数 【参考方案1】:

您需要将所选行的这三个值放入存储过程中的表变量中,以便能够将MAX 应用于它们。

尝试这样的事情 - 我不知道这些值是什么 datatype - 只是假设 INT 在这里,根据需要进行调整:

CREATE PROCEDURE [dbo].[GetMaxValue]
    @surname NVARCHAR(50),
    @maxClass INT OUTPUT
AS
    DECLARE @IntTbl TABLE (AValue INT);
    
    INSERT INTO @IntTbl (AValue)
        SELECT Programming
        FROM MissLess 
        WHERE Name LIKE '%' + @name + '%'
        UNION ALL
        SELECT Mathematics
       FROM MissLess 
        WHERE Name LIKE '%' + @name + '%'
        UNION ALL
        SELECT Physics
        FROM MissLess 
        WHERE Name LIKE '%' + @name + '%';
        
    SELECT @maxClass = MAX(AValue)
    FROM @IntTbl;
GO

更新 - 好的,你要求它;-)

由于您的搜索条件可能匹配多行(至少您可能不能完全排除这种情况),您必须首先获取每列的 MAX(),基于搜索条件:

CREATE PROCEDURE [dbo].[GetMaxValue]
    @surname NVARCHAR(50),
    @maxClass INT OUTPUT
AS
    DECLARE @MaxMath INT, @MaxPhys INT, @MaxProgr INT;
    
    SELECT 
        @MaxMath = MAX(Mathematics),
        @MaxPhys = MAX(Physics),
        @MaxProgr = MAX(Programming)
    FROM 
        MissLess 
    WHERE 
        Name LIKE '%' + @name + '%';

    IF @MaxMath > @MaxPhys
    BEGIN       
        IF @MaxMath > @MaxProgr
            -- @MaxMath is bigger than both @MaxPhys AND @MaxProgr --> it's the overall MAX()
            SET @maxClass = @MaxMath;
        ELSE
            -- @MaxMath is bigger than @MaxPhys, but smaller than @MaxProgr 
            SET @maxClass = @MaxProgr;
    END
    ELSE BEGIN
        IF @MaxPhys > @MaxProgr
            -- @MaxPhys is bigger than both @MaxMath AND @MaxProgr --> it's the overall MAX()
            SET @maxClass = @MaxPhys;
        ELSE
            -- @MaxPhys is bigger than @MaxMath, but smaller than @MaxProgr 
            SET @maxClass = @MaxProgr;
    END;

    SELECT @maxClass = MAX(AValue)
    FROM @IntTbl;
GO

更新 #2:对于不使用表变量进行更新的更好、更简洁的解决方案 - 请参阅@AndrewCorrigan 的答案,使用CASE 表达式。

【讨论】:

不可能全部放在同一张表里吗?是的,所有这些数据类型值都是 INT 嵌套的 IF 语句会是什么样子? 这种更新是荒谬的——case 语句比 if 块简单得多。【参考方案2】:

你可以做 (Fiddle)

SELECT MAX(s) 
FROM MissLess      
CROSS APPLY (VALUES (Programming), (Mathematics), (Physics)) V(s)
WHERE Name LIKE '%' + @name + '%'

如果@name 谓词匹配多行,您将无法指出它来自哪一行

【讨论】:

【参考方案3】:

作为使用嵌套 CASE 语句的替代解决方案:

SELECT @maxClass = MAX(CASE 
                             WHEN Programming >= Mathematics
                                  AND Programming >= Physics
                                      THEN Programming
                             WHEN Mathematics >= Physics
                                  AND Mathematics >= Programming
                                      THEN Mathematics
                             ELSE Physics
                       END)
FROM MissLess
WHERE Surname LIKE '%' + @surname + '%';

【讨论】:

同意 - 这是一个更好、更简洁的解决方案,无需使用表变量 - 干杯!

以上是关于如何从 SQL Server 存储过程中的 3 列中获取 MAX 值?的主要内容,如果未能解决你的问题,请参考以下文章

我应该如何使用 sql server 中的存储过程将列名存储在变量中?

如何从 SQL Server 中的存储过程中检索参数列表

如何从 SQL Server Management Studio 中的表生成 CRUD 存储过程

将数据从 MS Sql Server 存储过程导出到 excel 文件

如何找出哪个存储过程正在使用 SQL Server 中特定表的特定列?

SQL Server2008 存储过程传入表名称和列名称,如何在语句中使用表明引用列名?