插入SQL时应该返回什么?

时间:2010-01-27 14:09:20

标签: sql-server stored-procedures insert code-generation

几个月前,我开始为SQL Server使用CRUD脚本生成器。此生成器生成的默认insert语句,SELECT存储过程末尾的插入行。对于UPDATE也是如此。

之前的方式(以及我在网上看到的唯一其他方式)是将新插入的Id返回给业务对象,然后让业务对象更新记录的Id。

有一个额外的SELECT显然是一个额外的数据库调用,并且更多的数据被返回给应用程序。但是,它允许存储过程中的额外灵活性,并允许应用程序反映表中的实际数据。

当想要在事务中包装insert / update语句时,附加的SELECT也会增加复杂性。

我想知道人们认为什么是更好的方法,我并不是指任何一种方法的实施。哪个更好,只返回Id,或返回整行?

6 个答案:

答案 0 :(得分:3)

我们总是在Insert和Update上返回整行。我们总是希望确保我们的客户端应用程序具有刚刚插入或更新的行的新副本。由于触发器和其他进程可能会修改实际插入/更新语句之外的列中的值,并且由于客户端通常需要新的主键值(假设它是自动生成的),因此我们发现最好返回整行。

答案 1 :(得分:1)

只有在过程中生成数据时,select语句才具有某种优势。否则,您已插入的数据通常已经可供您使用,因此无需选择并再次返回,恕我直言。如果它是id,则可以使用SCOPE_IDENTITY(),它将返回在当前会话中为插入创建的最后一个标识值。

答案 2 :(得分:1)

根据我之前的经验,我的下意识反应是返回新生成的身份值。应用程序插入的所有其他内容,它已经知道 - 名称,美元等等。但几分钟的反思和阅读之前的6(嗯,使那5)回复,导致了一些“依赖”的情况:

  • 在最基本的层面上,你输入的内容就是你得到的东西 - 你传入值,它们被写到表格中的一行,然后你就完成了。

  • 稍微复杂一点,就是在insert语句中分配了简单的默认值时。默认为当前日期时间的“DateCreated”列或默认为当前SQL登录名的“CreatedBy”是一个主要示例。我在这里包含了标识列,因为不是每个表都会(或应该)包含它们。这些值是在表插入时由数据库生成的,因此调用应用程序无法知道它们是什么。 (Web服务器时钟与数据库服务器时钟不同步并不为人所知。有趣的时间......)如果应用程序需要知道刚刚生成的值,那么是的,你需要将它们传回去。

    < / LI>
  • 然后,在将数据插入表中之前,有些情况会在数据库中完成其他处理。此类工作可能在存储过程或触发器中完成。再一次,如果应用程序需要知道此类计算的结果,则需要返回数据。

话虽如此,在我看来,你决定的主要问题是:你对数据库有多少控制/理解?您说您正在使用工具自动生成CRUD程序。好吧,这意味着你没有在其中进行任何复杂的处理,你只需要获取数据并加载它。下一个问题:是否存在可能修改数据的触发器(任何类型)写到桌子上?将其扩展为:知道是否存在此类触发器?如果他们在那里,他们很重要,相应地计划;如果您不知道或不知道,那么您可能需要在插入上“跟进”以查看是否发生了更改。最后:应用程序是否关心?是否需要告知它刚才要求的插入操作的结果,如果需要,需要知道多少? (新标识值,添加日期时间,是否将名称从“小部件”更改为“Widget_201001270901”。)

如果您对正在构建的系统有完全的理解和控制,我只会根据您的需要投入,因为不执行任何有用功能的额外代码会影响性能和可维护性。另一方面,如果我正在编写一个供他人使用的工具,我会尝试构建一些可以完成所有工作的东西(以增加我的市场份额)。如果你正在构建代码,你不知道它将如何以及为什么会被使用(应用程序目的),或者它将依次使用(数据库设计),那么我猜你必须是偏执狂和尝试为一切编程。 (我强烈建议不要那样做。只做有需要做的事。)

答案 3 :(得分:0)

INSERT
INTO    mytable (col1, col2)
OUTPUT  INSERTED.*
VALUES  ('value1', 'value2')

使用此子句,返回整行不需要额外的SELECT,性能方面与仅返回id相同。

“哪个更好”完全取决于您的应用需求。如果您需要整行,请返回整行,如果只需要id,则只返回id

您可以为业务对象添加一个额外的设置,该设置可以触发此选项并仅在对象需要时返回整行:

IF @return_whole_row = 1
        INSERT
        INTO    mytable (col1, col2)
        OUTPUT  INSERTED.*
        VALUES  ('value1', 'value2')
ELSE
        INSERT
        INTO    mytable (col1, col2)
        OUTPUT  INSERTED.id
        VALUES  ('value1', 'value2')
FI

答案 4 :(得分:0)

数据库通常会有一个属性,可以为您提供上一个插入项的ID,而无需进行额外的选择。例如,MS SQL Server具有@@ Identity属性(请参阅here)。您可以将其作为存储过程的输出参数传递回应用程序,并使用它来使用新ID更新数据。 MySQL有类似的东西。

答案 5 :(得分:0)

我认为一般不会返回整行,但它可能是一种有用的技术。

如果你是代码生成器,你可以生成两个触发器(一个可能调用另一个触发器)或参数化单个触发器以确定是否通过线路返回它。我怀疑数据库开销是否显着(单行,必须进行PK查找),但是当所有加起来并且如果它在99%的情况下被丢弃时,从数据库到客户端的数据都可能很重要,我看不到什么价值。当然,让SP以不同的参数返回不同的东西是客户的潜在问题。

如果您在数据库管理的触发器或计算列中有逻辑,我可以看到它将在哪里有用,在这种情况下,SELECT实际上是获取该数据而不重复客户端逻辑的唯一方法或SP本身。当然,应该仔细考虑放置任何逻辑的地方。

在数据库中放置任何逻辑通常是经过仔细考虑的权衡,从微创和最有用的事情开始,如约束,独特的约束,参照完整性等,并发展到更具侵入性和边缘有用的工具,如触发器

通常情况下,当您对数据库本身进行多模式访问时,我喜欢数据库中的逻辑,而且您不能强迫人们通过您的客户端程序集。在这种情况下,我仍然会尝试强制人们通过视图或SP来最小化错误,重复,逻辑同步问题或数据误解的可能性,从而尽可能提供干净,一致和连贯的边界。