如何用PHP从现有的MySQL列中探测最佳数据类型?

yrdbyhpb  于 2023-04-19  发布在  PHP
关注(0)|答案(4)|浏览(113)

我有一个MySQL表,有~400列
这些列是从外部数据中累积的,因此我至少在最初并不能真正控制计数
为了避免在生成列时出错,这些列只是TEXT数据类型,现在拥有它们可能需要的所有行
我现在正试图优化数据,我有一个想法,如何做,但再次,我想尽量避免错误,如果可能的话

TLDR:我想迭代每个列并确定数据类型(即TINYINT,INT,VARCHAR(?),CHAR(?),BOOLEAN,TEXT等)

我知道如何循环数据,但我更关心的是准确性和确保数据完整性,所以我想问的是,是否有人知道任何资源或链接到现有的代码,将执行这个确切的功能?
我不想错过这些数据类型的任何细微差别或特殊情况,如果资源存在,那么不重新发明轮子是有意义的吗?

wrrgggsh

wrrgggsh1#

这是information_schema的工作。
这个查询可以满足您的需要。

SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, COLUMN_DEFAULT
  FROM information_schema.COLUMNS
 WHERE TABLE_NAME = 'whatever_table_name'
   AND TABLE_SCHEMA = DATABASE() 
 ORDER BY ORDINAL_POSITION;

HeidiSQLMySQL Workbench这样的好的交互式工具也可以以有用的形式显示您需要的元数据(描述数据的数据)。
另一个可能的诡计:将随机选择的几千行导出到.csv文件中,然后将其导入Excel或LibreOffice Calc。2这些程序将尝试猜测数据类型。
交互式工具或命令行工具可以执行导出操作。

SELECT *
  FROM table
 WHERE id IN (SELECT id FROM table ORDER BY RAND() LIMIT 1000)
  INTO OUTFILE 'sample.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
 LINES TERMINATED BY '\n';

这里假设id是主键。
这会有点慢,所以不要经常这样做。

9nvpjoqh

9nvpjoqh2#

这是一个很难的问题-有几个options可供您使用。我找到的最完整的解决方案是在Python中,称为Tableschema。您向它提供数据- CSV是最简单的-然后要求它推断模式。
因此,您可以使用@o.jones的代码将随机的1000行导出到CSV,然后将其输入到Tableschema中,并使用它来创建具有更准确字段类型的表。

kx1ctssn

kx1ctssn3#

经过大量的浏览和研究Tableschema之后,解决这个问题的最快方法似乎是迭代数据
基本的概述,因为我不能提供实际的代码,但这应该足以保存人们在未来大量的时间-也要确保在每次循环列之前将所有内容置零或为空

ini_set('max_execution_time', 0);
ini_set('memory_limit','1G');

$stmt = $mysqli->query("SHOW COLUMNS FROM `table`");
//...

foreach($columns as $column){
    $int = true;
    $decimal = true;
    $boolean = true;
    $intmax = 0;
    $intneg = false;
    $integer_part = 0;
    $decimal_part = 0;
    $decimal_neg = false;
    $consistent_len = 0;
    $consistent_strlen = null;
    $nullable = false;
    $boolean_counter = 0;
    $boolean_array = array();
    $strlen = 0;

    $stmt = $mysqli->query("SELECT `$column` FROM `table`");
    //...
    foreach($rowdata as $line){
        if(empty($line)){
            $nullable = true;
            continue;
        }
        else{
            $data = trim($line);
        }
        // turn off $int, $decimal, $boolean to false based on criteria
        // mb_strlen($data, 'UTF-8'); helpful for varchar multibyte
    }
    // Check order of preference > BOOLEAN > INT (Variants) > DECIMAL > CHAR > VARCHAR > TEXT

    // define $type, $unsigned, $is_null

    $column_type = $type.$unsigned.$is_null;
    $alter_query = "ALTER TABLE `table` MODIFY COLUMN `$column` $column_type";
}
qojgxg4l

qojgxg4l4#

SELECT 
    MIN(col1), MAX(col1) MAX(CHAR_LENGTH(col1)),
    MIN(col2), MAX(col2) MAX(CHAR_LENGTH(col2)),
    ...
   FROM tbl;

这将给予您对数据类型和它们的大小有一些感觉。(请替换上面的实际列名。)

  • 如果max和min看起来都是数字,而max len很小,那么 * 可能 * 是某个数字类型。
  • 如果看到某些标点符号,请考虑DECIMAL/FLOAT
  • 考虑UNSIGNED,如果max和min都不为负。
  • 如果max或min不是数字,并且max len小于100,则在VARCHAR(...)中使用max len的两倍。
  • 如果max或min是非数字的,并且max len更大,则使用TEXT的一些变体。

毫无疑问,有一个REGEXP可以帮助区分数字和字符串。

col1 REGEXP '^[0-9]$'      -- some size of INT UNSIGNED
col1 REGEXP '^[-+0-9]$'    -- some size of INT SIGNED
col1 REGEXP '^[-+0-9.]$'   -- DECIMAL(..., ...)
col1 REGEXP '^[-+0-9.e]$'  -- FLOAT or DOUBLE

变化:

TINYINT  SMALLINT  MEDIUMINT  INT  BIGINT
TEXT  MEDIUMTEXT  LONGTEXT  (don't use TINYTEXT)

您可以查询information_schema.COLUMNS来查找列名,并自动生成上面的SELECT(除非您有很多列要研究,否则我不会打扰您)。
以上不包括BINARY/BLOB,字符集,(m,n)DECIMALENUM

相关问题