Sql server 存储过程是声明式的还是命令式的?

Sql server 存储过程是声明式的还是命令式的?,sql-server,tsql,stored-procedures,Sql Server,Tsql,Stored Procedures,请先阅读下面的例子 我有一个名为Product的数据库表,该表有一个名为Id的列,其数据类型为INT 我正在编写一个添加新产品的存储过程。数据库的规则之一是,添加新产品时,分配给它的id必须是从1开始的最小整数,当然id是唯一的 例如,如果现有id为1、2、3、4、5、6,则新产品的id为7。但是,如果现有id是1、2、3、5、6、8,那么新id将是4 这是我的尝试: DECLARE @newId INT SET @newId = 1 WHILE EXISTS (SELECT * FROM Pr

请先阅读下面的例子

我有一个名为Product的数据库表,该表有一个名为Id的列,其数据类型为INT

我正在编写一个添加新产品的存储过程。数据库的规则之一是,添加新产品时,分配给它的id必须是从1开始的最小整数,当然id是唯一的

例如,如果现有id为1、2、3、4、5、6,则新产品的id为7。但是,如果现有id是1、2、3、5、6、8,那么新id将是4

这是我的尝试:

DECLARE @newId INT
SET @newId = 1
WHILE EXISTS (SELECT * FROM Product WHERE Product.id = @newId)
    SET @newId = @newId + 1
/*Then use this @newId to insert new item into table Product*/
但我的朋友告诉我,这段代码效率不高,因为while循环中的查询将在每次迭代中进行评估

这是他的代码的一部分:

DECLARE @currentId INT, @lastId INT, @newId INT
SET @lastId = 0

DECLARE idCursor CURSOR FOR SELECT Product.id FROM Product ORDER BY Product.id
OPEN idCursor
FETCH NEXT FROM idCursor INTO @currentId

WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @currentId <> @lastId + 1
            BREAK

        SET @lastId = @currentId
        FETCH NEXT FROM idCursor INTO @currentId
    END

SET @newId = @lastId + 1
CLOSE idCursor
DEALLOCATE idCursor
/*Then use this @newId to insert new item into table Product*/
在我看来,SQL是一种声明性语言,无论我们编写什么代码,DBMS都会重新安排代码以实现良好的执行计划,因此我为DBMS提供了优化部分,并试图使代码简单易读。此外,查找新id只是存储过程的一小部分

但在我的朋友看来,在编写存储过程时,它变成了一种命令式语言,代码作者对代码效率负责。他说我所做的是让事情对我来说简单,而不是对系统来说

因此,我的问题是:

当我们编写存储过程时,SQL仍然是声明性的还是不再是声明性的?还是在中间?

在编写存储过程时,什么被认为是更好的实践:保持存储过程的简单性还是充分考虑存储过程的效率


我认为每种语言都是你所说的陈述式和命令式的混合体

一个人可以用任何语言编写糟糕的代码或伟大的代码。在我看来,如果你想写伟大的代码,你必须知道你正在写代码的语言的优点和缺点

由于涉及到循环,您显示的两个代码块的性能都很差。解决此问题的基于集合的方法如下所示:

Declare @NewId Int

Select  Top 1 @NewId = RowId
From    (
        Select  Id, Row_Number() Over (Order By Id) As RowId
        From    Product
        ) As A
Where   Id <> RowId
Order By RowId

Select @NewId

TSQL在涉及循环时有一个弱点。在99.9%的情况下,最好避免循环。

简单的答案是,总是尝试编写基于集合的方法代码,而不是编写RBAR代码。它是否是声明性的并不重要。虽然循环和游标是逐行操作的纯粹示例,但我们应该始终避免它。这种假设在任何时候,在所有语言中都是完全错误的:在我看来,SQL是一种声明性语言,无论我们编写什么代码,DBMS都会重新排列它们以实现良好的执行计划,因此,我给出了DBMS的优化部分,并尽量使事情简单易懂。你必须学会根据你所使用的语言的优点进行编程,并克服它的缺点,这样引擎才能生成尽可能最好的编译计划。在我看来,应该避免使用SQL作为一种编程语言,使用声明的变量、循环和所有这些东西。SQL Server在基于集合的职责方面做得很好,但在其他方面做得很差。如果你想做一些声明性的事情,你可以考虑CLR,顺便说一句:这是一个真正的项目还是只是一个可以尝试的东西?仅仅因为删除后有一个空白就重复使用ID是非常危险的…谢谢大家,我明白了。我将尽我最大的努力使用基于集合的方法。如果你们能向我展示更多SQL的优点和缺点,我将不胜感激。看到一个具体的例子是很好的。我将尝试坚持基于集合的方法。顺便说一句,我刚刚在你的查询中发现了一个小错误。当id值中存在间隙时,它可以完美地工作,但如果没有间隙,它将无法工作。在这种情况下,@newId将为NULL,因为没有一行的id不等于rowId,但是不用担心,我已经使用推荐的基于集合的方法得到了自己的解决方案。非常感谢你的解释。