【问题标题】:modify format of multiple database columns at once一次修改多个数据库列的格式
【发布时间】:2016-06-20 22:00:01
【问题描述】:

我已使用 phpmyadmin 将 csv 表导入 sql db。我猜默认格式是十进制(8,5),或者至少它是这样出来的。似乎矫枉过正,我想我可以减少到 4,1。问题是大约有 470 个字段。我知道如何一次更换一个,但这需要很长时间。有更快的方法吗?

【问题讨论】:

    标签: mysql phpmyadmin format multiple-columns


    【解决方案1】:

    我只有 Sql Server 2008 R2,但似乎 MySQL 解决方案可能类似。我已尝试尽可能将其与 MySQL 保持一致,但如果没有 MySQL 引擎,我无法对其进行检查……因此,对于它的价值,这是我的脚本(在 Sql Server 中测试):

    -- I believe this is 'CREATE TEMPORARY TABLE' in MySql
    create table #tbl
    (
        ownerName sysname -- `sysname` is nvarchar(128) the max identifier length
        , tableName sysname
        , colName sysname
        , colType sysname
        , colPrecision int
        , colScale int
    )
    insert #tbl
    select table_schema, table_name, column_name, data_type, numeric_precision, numeric_scale
    FROM information_schema.columns
    where data_type = 'decimal' and numeric_precision = 8 and numeric_scale = 5
    
    -- Note: It is 'MODIFY COLUMN' in MySQL
    declare @newPrecision int = 4, @newScale int = 1
    DECLARE @sql varchar(max) = ''
    select @sql = @sql + CHAR(13) + CHAR(10) + 'ALTER TABLE ' + ownerName + '.' + tableName + ' ALTER COLUMN ' 
        + colName + ' decimal(' + cast(@newPrecision as varchar(max)) + ',' + cast(@newScale as varchar(max)) + ')'
    from #tbl
    /**
        -- In MySql, GROUP_CONCAT() may work
        select @sql = GROUP_CONCAT( 'ALTER TABLE ' + ownerName + '.' + tableName + ' MODIFY COLUMN ' 
        + colName + ' decimal(' + cast(@newPrecision as varchar(max)) + ',' + cast(@newScale as varchar(max)) + ')' SEPARATOR ' ' )
        from #tbl
    **/
    
    print @sql
    execute ( @sql )
    

    【讨论】:

      【解决方案2】:

      我以前从未使用过 SqlFiddle,所以认为现在是开始的好时机,专门针对 MySQL 5.6 给出完整的答案。请看http://sqlfiddle.com/#!9/19f46/1

      在 Build Schema 面板的底部,选择 Delimiter = [ // ]。 SqlFiddle 使用它来决定何时将一段代码发送到 MySQL。这是必要的,因为 CREATE PROCEDURE 必须作为一个块发送出去。如果使用默认分隔符 = [ ; ],然后它将只发送部分 CREATE PROCEDURE,直到它找到的第一个 ;

      cols 选择decimal 类型的列,其中包含您要更改的精度和小数位数。目前按照 OP 的要求硬编码为 8 和 5,但根据需要进行更改以仅标识您要修改的列。在您进行表修改之前运行此选择以验证您将修改哪些列是一个好主意。

      存储过程exec_multiple 使用表cols 生成ALTER TABLE 语句,然后动态执行。

      EXECUTE 一次只处理一个语句,因此您需要遍历cols 的行并分别应用每个ALTER TABLEcols 中的 auto_increment 列 id 允许您在不使用游标的情况下依次选择每一行。

      test_log 表会捕获在构建模式完成后您可能想要检查的任何调试信息。

      以下内容位于左侧的 Build Schema 面板中。 所有逻辑都需要在此面板中,因为 SqlFiddle 不允许在运行 SQL 面板中使用数据定义语言或表插入/更新/删除语句。

      create table if not exists cols
      (
          id int auto_increment primary key
          , ownerName varchar(128)
          , tblName  varchar(128)
          , colName  varchar(128)
          , colType  varchar(128)
          , colPrecision int
          , colScale int
      ) //
      
      create table if not exists test_table
      (
          testDecimal1 decimal(8,5)
          , testDecimal2 decimal(8,5)
      ) //
      
      create table if not exists test_table2
      (
          testDecimal3 decimal(8,5)
          , testDecimal4 decimal(8,5)
      ) //
      
      create table if not exists test_log
      (
          msg varchar(1024)
      ) //
      
      INSERT INTO cols
      ( ownerName, tblName, colName, colType, colPrecision, colScale )
      SELECT TABLE_SCHEMA, `TABLE_NAME`, COLUMN_NAME, DATA_TYPE, NUMERIC_PRECISION, NUMERIC_SCALE
      FROM INFORMATION_SCHEMA.COLUMNS
      WHERE DATA_TYPE = 'decimal' AND NUMERIC_PRECISION = 8 AND NUMERIC_SCALE = 5 //
      
      insert test_log( msg) select database() //
      
      CREATE PROCEDURE `exec_multiple` ( newPrecision int, newScale int)
      BEGIN
          declare n int; 
          declare nrows int;
          declare sql_stmt varchar(1024);
          set n = 1;
          select count(*) from cols into nrows;
      
          while n <= nrows do
      
              select CONCAT('ALTER TABLE '
              , ownerName, '.', tblName, ' MODIFY COLUMN '
              , colName, ' decimal(', newPrecision, ','
              , newScale, ')') into sql_stmt from `cols` where id = n;
      
              SET @sql_stmt := sql_stmt;  -- not sure why this is necessary
      
              insert test_log( msg ) select @sql_stmt;
      
              PREPARE dynamic_statement FROM @sql_stmt;
              EXECUTE dynamic_statement;
              DEALLOCATE PREPARE dynamic_statement;
      
              set n = n + 1;
          end while;
      END //
      
      call exec_multiple(4, 1) //
      

      这在右侧的运行 SQL 面板中

      select * from test_log;
      
      SELECT TABLE_SCHEMA, `TABLE_NAME`, COLUMN_NAME, DATA_TYPE, NUMERIC_PRECISION, NUMERIC_SCALE
      FROM INFORMATION_SCHEMA.COLUMNS
      WHERE DATA_TYPE = 'decimal'
      ;
      
      select * from cols;
      

      【讨论】:

      • 您的报价:-- not sure why this is necessary ... 有两个原因:(1)您最初没有对用户变量进行连接。 (2) mysql 在您引用的那一行上很挑剔,它不喜欢局部变量但喜欢用户变量。
      • @Drew - 我希望有人对此发表评论!这是我的第一个 MySql 脚本。我只想在存储过程中使用局部变量,但感谢您确认在这种情况下需要用户变量。基本逻辑与 Sql Server 类似,但变量处理需要一段时间才能开始工作。
      • 是的,手册页也很精彩,对吧?!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多