代码之家  ›  专栏  ›  技术社区  ›  lxalln

插入SQL时应返回什么?

  •  1
  • lxalln  · 技术社区  · 14 年前

    几个月前,我开始为SQL Server使用CRUD脚本生成器。此生成器生成的默认INSERT语句选择存储过程末尾的插入行。更新也同样如此。

    前一种方法(也是我在网上看到的唯一一种方法)是将新插入的ID返回到业务对象,然后让业务对象更新记录的ID。

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

    当希望在事务中包装insert/update语句时,附加的select还会增加复杂性。

    我想知道人们认为什么是更好的方法来做这件事,我并不意味着这两种方法的实现。哪一个更好,只返回ID,还是返回整行?

    6 回复  |  直到 14 年前
        1
  •  3
  •   Randy Minder    14 年前

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

        2
  •  1
  •   zapping    14 年前

    只有在过程中生成数据时,select语句才具有某种优势。否则,您插入的数据通常已经对您可用,因此没有必要再次选择和返回,imho。如果它是针对ID的,那么您可以使用scope_identity(),它将返回在当前会话中为插入创建的最后一个标识值。

        3
  •  1
  •   Philip Kelley    14 年前

    根据我之前的经验,我的膝跳反应就是返回新生成的身份值。应用程序正在插入的其他所有内容,它已经知道了——名称、美元等等。但是几分钟的思考和阅读之前的6(hmm,使之5)回复,会导致一些__,这取决于__情况:

    • 在最基本的层次上,您插入的是您d得到的值,它们被写入表中的一行,然后您就完成了。

    • 稍微复杂一点,即在INSERT语句期间分配了简单的默认值。_156;datecreated_157;默认为当前日期时间的列,或_156;createdBy_157;默认为当前SQL登录,是一个主要示例。i_d在这里包含标识列,因为并非每个表都(或应该)包含它们。这些值是数据库在表插入时生成的,因此调用应用程序无法知道它们是什么。(不知道Web服务器时钟是否与数据库服务器时钟同步。如果应用程序需要知道刚刚生成的值,那么是的,您需要将这些值传递回去。

    • 还有一些情况,在将数据插入到表中之前,需要在数据库中进行额外的处理。这些工作可以在存储过程或触发器中完成。同样,如果应用程序需要知道这些计算的结果,那么需要返回数据。

    在我看来,你决定的主要问题是:你对数据库有多大的控制/理解?你说你正在使用一个工具来自动生成你的积垢程序。好的,这意味着您没有任何复杂的处理过程,您只需获取数据并将其载入。下一个问题:是否存在(任何类型的)触发器可以在数据写入表时修改数据?扩展到:是吗 知道 是否存在此类触发器?如果它们存在并且它们很重要,请相应地计划;如果您不知道或不知道,那么您可能需要对插入件执行后续操作,以查看是否发生了更改。最后一个问题:应用程序是否重要?是否需要通知它刚刚请求的插入操作的结果,如果是,需要知道多少?(新的标识值,添加日期时间,是否有什么东西将名称从__widget_157;更改为__widget U 201001270901_157;。)

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

        4
  •  0
  •   TLiebe    14 年前

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

        5
  •  0
  •   Quassnoi    14 年前
    INSERT
    INTO    mytable (col1, col2)
    OUTPUT  INSERTED.*
    VALUES  ('value1', 'value2')
    

    对于这个子句,返回整行不需要额外的 SELECT 在性能方面与只返回 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
    
        6
  •  0
  •   Cade Roux    14 年前

    我想我不会的 一般来说 返回整行,但这可能是一种有用的技术。

    如果您正在生成代码,那么可以生成两个进程(一个调用另一个进程),或者参数化一个进程,以确定通过线路返回它的原因。我怀疑数据库开销是显著的(单行,必须进行pk查找),但是当所有数据加起来时,从数据库到客户机的线路上的数据可能是显著的,如果在99%的情况下被丢弃,我看不到什么价值。当然,对于客户机来说,拥有一个返回不同参数的不同事物的SP是一个潜在的问题。

    我可以看到,如果您在由数据库管理的触发器或计算列中具有逻辑,那么在哪种情况下,选择实际上是在不复制客户机或SP本身的逻辑的情况下获取数据的唯一方法。当然,放置任何逻辑的地方都应该经过深思熟虑。

    在数据库中放置任何逻辑通常都是一个精心考虑的折衷方案,它从最小侵入性和最大有用的东西开始,如约束、唯一约束、引用完整性等,并逐渐发展为更具侵入性和极为有用的工具,如触发器。

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