【问题标题】:Update different columns in a stored procedure更新存储过程中的不同列
【发布时间】:2013-09-22 02:19:13
【问题描述】:

我正在尝试移植一个我在 Java 代码中使用的概念,该概念用于 SQL 存储过程,但我不确定它是否可能。

基本上,如果我有一个包含 10 列的表,我希望能够每次都从同一个存储过程更新不同的列组合。 IE。在 Java 中,我会传递一个包含我想要更新的值的映射,并遍历它们并更新缓存中的每个键值。

这样做的好处是不必更改方法签名以包含每个列名,也不必让大量代码对每个变量进行空值检查以确定是否应该更新它。我不确定这是否可行,或者某些数据库服务器是否具备这种能力(即 PostgreSQL、Oracle、MySQL),或者它们都具备这种能力,但我就是不知道语法。

【问题讨论】:

  • 您能否发布一个 Java 代码示例,以便更清楚您想要实现的目标。
  • 这可以在您提到的任何 DBMS 中使用动态 SQL 来完成。

标签: mysql sql sql-server postgresql stored-procedures


【解决方案1】:

在 SQL Server 中,假设有这样的表,下面的过程将起作用:

CREATE TABLE MyBigTable(
    ID INT NOT NULL PRIMARY KEY,
    COLUMNA VARCHAR(100) NOT NULL,
    COLUMNB VARCHAR(100) NOT NULL
 )

GO

CREATE PROCEDURE UpdateMyBigTable(@ID INT, @ColumnAValue VARCHAR(100)=NULL, @ColumnBValue VARCHAR(100)=NULL)
AS BEGIN
UPDATE MyBigTable
    SET COLUMNA = CASE WHEN @ColumnAValue IS NULL THEN COLUMNA ELSE @ColumnAValue END,
    COLUMNB = CASE WHEN @ColumnBValue IS NULL THEN COLUMNB ELSE @ColumnBValue END
WHERE ID = @ID
    AND ((COLUMNA <> @ColumnAValue AND @ColumnAValue IS NOT NULL) OR (COLUMNB <> @ColumnBValue AND @ColumnBValue IS NOT NULL));
END

GO

但是,这实际上并没有枚举您所询问的字段。如果不进入动态 SQL,这在 SQL Server 中是很难做到的。

【讨论】:

  • 第二种情况,如何区分要设置为NULL的列和不想更改值的列?
  • 你是对的。我会把它拉出来。如果您要允许 NULL,则解决方案会变得更加复杂,因为我想您必须进入禁止值,例如发送低 ASCII 字符。重新阅读后,这两种解决方案都不适用于 OPs 声明的情况,这要求一种方法来遍历列。
  • 如果您这样做,您实际上会更新这些值——即使使用它自己现有的值。从内存中,这会导致重新计算索引,因此比在开始时找出条件语句要慢。
  • 问题是你只有两个选择——要么在单独的 UPDATE 语句中一次更新一个字段,在 WHERE 中使用单独的保护子句(此时你真的需要在一个事务加上 SQL Server 每次都必须重复工作才能找到所需的行),或者您在单个语句中更新所有字段,并冒着不得不更新非聚集索引的风险。
  • 一种选择是在 set 子句中传入位掩码和用例语句来检查该位是否已设置。
【解决方案2】:

为获得最佳性能,请对每个可能的查询参数组合使用动态 SQL 或带有 SQL 语句的 IF 语句。

如果您可以忍受为每个可能的解决方案制作 IF 语句,那就去做吧 - 它稳定、安全且高效。

如果您为此设置的参数过多,请使用动态 SQL - 您可以在存储过程或更早的时间生成动态 SQL,但请务必避免使用SQL injection issues

您的问题与 Erland Sommarskog 所涵盖的dynamic search 问题非常相似。

在性能方面,SQL Server 将为每个可能的动态查询类型创建一个执行计划,因此性能将与使用 IF 语句来选择每个可能的 SQL 语句一样好。

这与使用COLUMNB = CASE WHEN @COLUMNB IS NULL THEN COLUMNB ELSE @COLUMNB END 形成鲜明对比,COLUMNB = CASE WHEN @COLUMNB IS NULL THEN COLUMNB ELSE @COLUMNB END 只有一个执行计划,因此通常执行计划很差(取决于数据库中的 where 子句和索引)和性能差。

【讨论】:

    猜你喜欢
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多