解释 Perl DBI MySQL column_info()

Posted

技术标签:

【中文标题】解释 Perl DBI MySQL column_info()【英文标题】:Interpreting Perl DBI MySQL column_info() 【发布时间】:2013-02-01 14:23:02 【问题描述】:

我正在尝试编写 Perl 代码,该代码接受 SQL INSERT 语句的绑定,并识别可能导致 INSERT 因错误数据而被拒绝的问题,并修复它们。为此,我需要获取并解释列元数据。

$dbh->column_info 方法以编码形式返回信息。我仔细阅读了官方 CPAN 文档,但仍然感到困惑。

my $sth_column_info
        = $dbh->column_info( $catalog, $schema, $table, undef );
    my $columns_aoh_ref = $sth_column_info->fetchall_arrayref(
           COLUMN_NAME      => 1,
            DATA_TYPE        => 1,
            NULLABLE         => 1,
            ORDINAL_POSITION => 1,
            COLUMN_DEF       => 1,
        
    );
    say $table;
    for my $href (@$columns_aoh_ref) 
        my @list;
        while ( my ( $k, $v ) = each %$href ) 
            push @list, "$k=" . ( $v // 'undef' );
        
        say join '|', @list;
    

输出是:

dw_phone
NULLABLE=0|COLUMN_DEF=undef|DATA_TYPE=4|ORDINAL_POSITION=1|COLUMN_NAME=phone_id
NULLABLE=0|COLUMN_DEF=undef|DATA_TYPE=4|ORDINAL_POSITION=2|COLUMN_NAME=phone_no
NULLABLE=1|COLUMN_DEF=undef|DATA_TYPE=4|ORDINAL_POSITION=3|COLUMN_NAME=phone_ext
NULLABLE=0|COLUMN_DEF=undef|DATA_TYPE=1|ORDINAL_POSITION=4|COLUMN_NAME=phone_type
NULLABLE=0|COLUMN_DEF=undef|DATA_TYPE=1|ORDINAL_POSITION=5|COLUMN_NAME=phone_location
NULLABLE=1|COLUMN_DEF=undef|DATA_TYPE=1|ORDINAL_POSITION=6|COLUMN_NAME=phone_status
NULLABLE=0|COLUMN_DEF=undef|DATA_TYPE=11|ORDINAL_POSITION=7|COLUMN_NAME=insert_date
NULLABLE=0|COLUMN_DEF=undef|DATA_TYPE=11|ORDINAL_POSITION=8|COLUMN_NAME=update_date

例如,在哪里可以找到数据类型代码到字符串的映射?我应该使用 DATA_TYPE、TYPE_NAME 还是 SQL_DATA_TYPE?我应该使用 NULLABLE 还是 IS_NULLABLE,为什么这两种口味?

我可以理解记录(更不用说实现)数据库通用接口的难度。但我想知道是否有人知道使用特定于 mysql 的 DBI 的参考手册?

更新 1:

试图通过使用 array 而不是哈希来检索 all 信息来揭示更多信息:

    my $sth_column_info
        = $dbh->column_info( $catalog, $schema, $table, undef );

    my $aoa_ref = $sth_column_info->fetchall_arrayref; # <- chg. to arrayref, no parms
    say $table;
    for my $aref (@$aoa_ref) 
        my @list = map $_ // 'undef', @$aref;
        say join '|', @list;
    

现在我可以看到很多潜在有用的信息混在其中。

dw_contact_source
undef|dwcust1|dw_contact_source|contact_id|4|BIGINT|20|undef|undef|10|0|undef|undef|4|undef|undef|1|NO|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|1|bigint(20)|undef|0
undef|dwcust1|dw_contact_source|company_id|4|SMALLINT|6|undef|undef|10|0|undef|undef|4|undef|undef|2|NO|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|1|smallint(6)|undef|0
undef|dwcust1|dw_contact_source|contact_type_id|4|TINYINT|4|undef|undef|10|0|undef|undef|4|undef|undef|3|NO|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef||tinyint(4)|undef|0
undef|dwcust1|dw_contact_source|insert_date|11|DATETIME|19|undef|0|undef|0|undef|undef|9|-79|undef|4|NO|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef||datetime|undef|0
undef|dwcust1|dw_contact_source|update_date|11|DATETIME|19|undef|0|undef|0|undef|undef|9|-79|undef|5|NO|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef|undef||datetime|undef|0

所以我的问题是:

如何获取这些元数据的相应名称/描述? 我如何fetchall_arrayref 使用符号而不是整数来满足我的需求? (我试过fetchall_arrayref([qw/COLUMN_NAME DATA_TYPE/]) 并找回了所有undefs;现在我只是在猜测。)

更新 2:

现在我在 DBD::mysql.pm 中挖掘,发现了一个非常有趣的数组:

my @names = qw(                                                                                                                                             
    TABLE_CAT TABLE_SCHEM TABLE_NAME COLUMN_NAME                                                                                                            
    DATA_TYPE TYPE_NAME COLUMN_SIZE BUFFER_LENGTH DECIMAL_DIGITS                                                                                            
    NUM_PREC_RADIX NULLABLE REMARKS COLUMN_DEF                                                                                                              
    SQL_DATA_TYPE SQL_DATETIME_SUB CHAR_OCTET_LENGTH                                                                                                        
    ORDINAL_POSITION IS_NULLABLE CHAR_SET_CAT                                                                                                               
    CHAR_SET_SCHEM CHAR_SET_NAME COLLATION_CAT COLLATION_SCHEM COLLATION_NAME                                                                               
    UDT_CAT UDT_SCHEM UDT_NAME DOMAIN_CAT DOMAIN_SCHEM DOMAIN_NAME                                                                                          
    SCOPE_CAT SCOPE_SCHEM SCOPE_NAME MAX_CARDINALITY                                                                                                        
    DTD_IDENTIFIER IS_SELF_REF                                                                                                                              
    mysql_is_pri_key mysql_type_name mysql_values                                                                                                           
    mysql_is_auto_increment                                                                                                                                 
);

这些与 fetchall_arrayref 返回的内容完全对应。现在我可以看到我有 四个 选择来学习数据类型,所以让我们看看是否有任何代码被记录在案。

更新 3:

DBI Recipes 是关于将信息检索回 Perl 的 CPAN DBI 文档的一个非常好的附件(尤其是 select|fetchrow|all_hash|array 方法。)

【问题讨论】:

metacpan.org/module/DBD::mysql 可能是一个不错的起点。 谢谢——如果我没看错的话,语句句柄部分与我最相关。但该技术似乎要求您首先在桌子上执行SELECT *。 (还没有检查它是否适用于空表。)对整个表使用 column_info 方法似乎是更好的方法,这就是为什么我更愿意学习如何使用它。跨度> 【参考方案1】:

这将帮助您确定 data_types 的值。我通常使用 data_type 来确定如何根据其类型处理列。

然后您需要查看下面的 MySQL 数据类型键并获取哈希值。然后查看下面的 DBI 表,匹配数据名称得到数据类型值。示例:BIGINT 是与 SQL_INTEGER 匹配的 INTEGER 类型,因此 DATA_TYPE 值为 4,

DBD::MySQL
### ANSI datatype mapping to mSQL datatypes
%DBD::mysql::db::ANSI2db = ("CHAR"          => "CHAR",
            "VARCHAR"       => "CHAR",
            "LONGVARCHAR"   => "CHAR",
            "NUMERIC"       => "INTEGER",
            "DECIMAL"       => "INTEGER",
            "BIT"           => "INTEGER",
            "TINYINT"       => "INTEGER",
            "SMALLINT"      => "INTEGER",
            "INTEGER"       => "INTEGER",
            "BIGINT"        => "INTEGER",
            "REAL"          => "REAL",
            "FLOAT"         => "REAL",
            "DOUBLE"        => "REAL",
            "BINARY"        => "CHAR",
            "VARBINARY"     => "CHAR",
            "LONGVARBINARY" => "CHAR",
            "DATE"          => "CHAR",
            "TIME"          => "CHAR",
            "TIMESTAMP"     => "CHAR"
           );

DBI.pm 类型 TYPE 属性包含对表示相应数据类型的国际标准值的整数值数组的引用。整数数组的长度等于在原始语句中选择的列数,并且可以通过与前面显示的 NAME 属性示例类似的方式引用。

常见类型的标准值为:

SQL_CHAR             1
SQL_NUMERIC          2
SQL_DECIMAL          3
SQL_INTEGER          4
SQL_SMALLINT         5
SQL_FLOAT            6
SQL_REAL             7
SQL_DOUBLE           8
SQL_DATE             9
SQL_TIME            10
SQL_TIMESTAMP       11
SQL_VARCHAR         12
SQL_LONGVARCHAR     -1
SQL_BINARY          -2
SQL_VARBINARY       -3
SQL_LONGVARBINARY   -4
SQL_BIGINT          -5
SQL_TINYINT         -6
SQL_BIT             -7
SQL_WCHAR           -8
SQL_WVARCHAR        -9
SQL_WLONGVARCHAR   -10

虽然这些数字相当标准,[61] 驱动程序将其本机类型映射到这些标准类型的方式差异很大。与这些类型之一不能很好对应的本机类型可能会映射到正式保留供 Perl DBI 使用的范围:-9999 到 -9000。

【讨论】:

你写“data_type”/“DATA_TYPE”/“data types”的变化让我很困惑。我只是试图从DATA_TYPE(一个整数,在我的例子中为4)向后移动。 4 =&gt; SQL_INTEGER,但我不知道如何从那里进入 %DBD::mysql::db::ANSI2db 哈希。我想我误解了你在说什么。 use DBI qw(:sql_types); 根据search.cpan.org/dist/DBI/DBI.pm,将导入一堆形式为 SQL_* 的常量,它们等同于这些整数。允许我写if ($the_data_type == SQL_INTEGER) ... 您的 DATA_TYPE 的值等于第二个列表中常见类型的标准值。你可以测试看看$name[4] 您的 DATA_TYPE 的值等于第二个列表中常见类型的标准值。你可以测试看看 ($name[4]== 1 || $name[4] == 12 || $name[4] == -1 || $name[4]

以上是关于解释 Perl DBI MySQL column_info()的主要内容,如果未能解决你的问题,请参考以下文章

Perl 连接 MySQL,DBI怎么安装?

在 Windows-7-x64 上使用 DBI Perl 和 MySql 的未定义 $DBI::errstr

perl dbi mysql 向表中插入数据速度很慢

Linux中perl-DBI和DBI有啥区别?

有没有办法使用 DBI 和 MySQL/MyISAM 将 @variables 与 Perl 中的占位符混合?

Perl 和 MySQL - 使用 DBI 从表的最后一行返回字段,可能带有 last_insert_id?