【问题标题】:how to add new column if it's not exist如果新列不存在,如何添加
【发布时间】:2019-04-22 17:37:32
【问题描述】:

如果该列不存在,我想编写一个向表添加新列的过程。我一开始是为 MySQL 编写的,它运行成功,但是当我尝试为 SQL SERVER 编写相同的过程时,我遇到了一些语法错误,我也不确定 SQL SERVER 过程是否正确并且会做同样的工作MySQL 的一个。

MySQL 程序:

SET @dbname = DATABASE();
SET @tablename = "my_table";
SET @columnname = "my_field";
SET @preparedStatement = (SELECT IF(
  (
    SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
    WHERE
      (table_name = @tablename)
      AND (table_schema = @dbname)
      AND (column_name = @columnname)
  ) > 0,
  "SELECT 1",
  CONCAT("ALTER TABLE ", @tablename, " ADD ", @columnname, " INT UNSIGNED NOT NULL;")
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;

SQL SERVER 过程:

DECLARE @dbname varchar(128), @tablename varchar(11), @columnname varchar(11), @preparedStatement varchar(max);
SET @dbname = DB_NAME();
SET @tablename = "my_table";
SET @columnname = "my_field";
SET @preparedStatement = (SELECT CASE(
  (
    SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
    WHERE
      (table_name = @tablename)
      AND (table_schema = @dbname)
      AND (column_name = @columnname)
  ) > 0,
  "SELECT 1",
  CONCAT("ALTER TABLE ", @tablename, " ADD ", @columnname, " INT UNSIGNED NOT NULL;")
));
EXEC sp_prepare @preparedStatement;

我在第 12 行遇到 GREATER THAN 运算符的语法错误:

消息 102,级别 15,状态 1,第 12 行 '>' 附近的语法不正确。

【问题讨论】:

  • 您使用的是哪个版本的 SQL Server?
  • @StuartGrant 版本 14

标签: mysql sql-server stored-procedures


【解决方案1】:

你的 SQL 有很多错误:

首先,SQL Server 对文字字符串使用单引号 (')。

CASE 表达式使用CASE WHEN {expr} THEN {expr} ELSE [WHEN {expr} THEN {expr}] [THEN {expr}] ENDCASE {expr} WHEN ... 格式;您的版本格式错误。

UNSIGNED 数据类型在 SQL Server 中不存在。你只签了名(除了tinyint,即0-255)。

另外,sp_prepare 不是正确的函数,您需要sp_executesql

最后,我用QUOTENAME 包装了对象名称以避免注入,并将数据类型更改为sysname(又名nvarchar(128))并将文字字符串设为nvarcharN'' 而不是@ 987654334@)。这让你:

DECLARE @dbname sysname,
        @tablename sysname,
        @columnname sysname,
        @preparedStatement nvarchar(MAX);
SET @dbname = DB_NAME();
SET @tablename = N'my_table';
SET @columnname = N'my_field';
SET @preparedStatement = CASE
                              WHEN (SELECT COUNT(*)
                                    FROM INFORMATION_SCHEMA.COLUMNS
                                    WHERE (TABLE_NAME = @tablename)
                                      AND (TABLE_SCHEMA = @dbname)
                                      AND (COLUMN_NAME = @columnname)) = 0 THEN CONCAT(N'ALTER TABLE ', QUOTENAME(@tablename), N' ADD ', QUOTENAME(@columnname), N' INT NOT NULL;')
                         END;
EXEC sp_executesql @preparedStatement;

【讨论】:

  • 谢谢,因为我没有使用 SQL SERVER 的经验,所以我预计我的代码中会出现很多错误。上面的过程成功执行,但不幸的是,没有改变表。
  • @Mohammad 这是因为 CASE 语句中的逻辑被颠倒了。应该很容易修复将 >0 更改为 =0
  • 好地方@t-clausen.dk
【解决方案2】:

查看 SQL 和在 IMO 中使其更易于阅读的另一种方法是将 CASE 语句转换为存在检查

DECLARE @dbname varchar(128), @SchemaName varchar(30),  @tablename varchar(30), @columnname varchar(30), @preparedStatement nvarchar(max);
    SET @dbname = DB_NAME();
    SET @SchemaName = 'dbo';
    SET @tablename = 'myTable';
    SET @columnname = 'myColumn';


    IF NOT EXISTS(
        SELECT * FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_SCHEMA LIKE @SchemaName
        AND TABLE_NAME LIKE @tablename
        AND COLUMN_NAME LIKE @columnname
    )
    BEGIN
     SET @preparedStatement =  CONCAT('ALTER TABLE ', @tablename, ' ADD ', @columnname, ' INT UNSIGNED NOT NULL;')
     EXEC sp_executesql @preparedStatement;
    END

【讨论】:

  • 变量需要是 nvarchar 才能使用 sp_executesql
  • 考虑到 SQL 的性质,您应该考虑注入。甚至可以注入varchar(30)
猜你喜欢
  • 2011-03-15
  • 2012-09-17
  • 2018-02-02
  • 2019-03-12
  • 2013-01-01
  • 2014-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多