【问题标题】:Duplicate index names with DBIx::Class and PostgreSQLDBIx::Class 和 PostgreSQL 的重复索引名称
【发布时间】:2013-04-26 16:36:53
【问题描述】:

我有一个现有的 MySQL 数据库,我正在尝试使用以下步骤迁移到 PostgreSQL。数据库相当简单——它有一些外键和其他约束,但没有触发器、过程等。

  1. 使用 DBIx::Class::Schema::Loader 从现有 MySQL 数据库中生成一组 Result 类。
  2. 使用Result 类为PostgreSQL 生成一组CREATE TABLE 语句。
  3. 使用psql 运行CREATE TABLE 语句来设置表(我还没有导入数据)。

我使用的脚本如下(删除了凭据和数据库名称):

#!/usr/bin/perl

use Modern::Perl;
use DBIx::Class::Schema::Loader qw/ make_schema_at /;

my $dsn = 'dbi:mysql:dbname=database';
my $user = '';
my $pass = '';

make_schema_at(
  'MyDB::Schema',
  { debug => 1, dump_directory => './lib' },
  [ $dsn, $user, $pass
  ],
);

my $schema = MyDB::Schema->connect($dsn, $user, $pass);
$schema->create_ddl_dir(['PostgreSQL'], '0.1', './', undef, { add_drop_table => 0 });

脚本成功运行,Result 类和.sql 文件(包含所有CREATE TABLE 语句)看起来都符合我的预期。

但是,有几个表有一个 slug 列,在原始 MySQL 架构中标记为 UNIQUE,并导致以下行作为 CREATE TABLE 语句的一部分:

"slug" character varying(50) NOT NULL,
CONSTRAINT "slug" UNIQUE ("slug")

当我尝试导入数据(使用psql < tables.sql)时,我在每个表上都收到以下错误,第一个表后面有一个唯一的slug 列:

NOTICE:  CREATE TABLE / UNIQUE will create implicit index "slug" for table "mytable"
ERROR:  relation "slug" already exists

我的理解是索引名称在给定数据库中必须是唯一的。 MySQL 没有这个问题,因为我只是声明 slug VARCHAR(50) NOT NULL UNIQUE 而不指定索引名称。

有没有办法让DBIx::Class(或SQL::Translatorcreate_ddl_dir 函数使用)在其输出的数据中生成唯一的索引名称?我并不特别关心索引的名称——尽管基于表名的东西是明智的。我查看了文档,但看不到任何允许这样做的参数。

我可以在导入 .sql 文件之前手动编辑每个约束,但是有超过 250 个表和很多冲突 - 而且每次我调整迁移过程并且必须重新生成类时我都必须这样做和 SQL。

【问题讨论】:

  • 您是否尝试过直接在您的 MySQL 架构上运行 SQL::Translator 而无需通过 DBIx::Class::Schema::Loader
  • 同样的问题 - 它输出相同的 SQL 导致重复的索引名称。
  • 您似乎在 MySQL 模式中创建了命名的唯一约束。它应该可以通过在列定义中简单地使用UNIQUE 来使用未命名的约束。
  • 这就是我在 MySQL 中创建约束的方式(即仅使用 UNIQUE),但是当您获取数据库转储并通过 SQL::Translator 传递它时,它会生成命名的唯一约束。

标签: perl postgresql dbix-class


【解决方案1】:

最后,解决此问题的唯一自动方法是使用 Perl 脚本,通过解析来自 SQL::Translator 的输出并将 _$i 附加到每个名称,强制每个约束名称(以及自动索引)是唯一的,其中$i 会在每次看到新约束时递增。

代码如下 - 假设您将通过管道将架构输入STDIN

#!/usr/bin/perl

use Modern::Perl;

my $i = 1;

while (my $line = <>)
{
  if ($line =~ m/CONSTRAINT\s+"([a-zA-Z_]+)"\s+UNIQUE\s+\("([a-zA-Z_]+)"\)/)
  {    
    my $constraint_name = $1 . '_' . $i;
    my $column_name = $2;

    my $replace_str = 'CONSTRAINT "' . $constraint_name . '" UNIQUE ("' . $column_name . '")';

    $line =~ s/CONSTRAINT\s+"([a-zA-Z_]+)"\s+UNIQUE\s+\("([a-zA-Z_]+)"\)/$replace_str/;
    $i++;
  }

  print $line;
}

【讨论】:

    猜你喜欢
    • 2013-03-08
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    • 2011-07-09
    • 1970-01-01
    相关资源
    最近更新 更多