Varchar 值到数值分类

Posted

技术标签:

【中文标题】Varchar 值到数值分类【英文标题】:Varchar values to numerical classification 【发布时间】:2011-09-26 15:48:44 【问题描述】:

我有一个包含三个表的数据库:

    实践 - 8 个领域 患者 - 47 个字段 加重 - 11 个字段

这些表中的大部分字段都以 varchar 格式记录,其他字段包括整数、双精度和日期。

我必须将此数据转换为数字分类数据,以便统计学家可以使用它来推断数据中的任何模式。为了实现这一点,我必须将 varchar 字段转换为表示字符串所属分类的整数,例如“Severity”,它具有以下可能的字符串值:

    温和 中等 严重 非常严重

患者表中的这个字段有一个可以出现的字符串值的有限列表,其他字段有无限可能的字符串值在我的数据库遇到它们之前无法分类(除非我实现某种形式的智能方法) .

目前,我只是在尝试构建将 3 个表中所有条目的每个字段转换为数值的最佳方法。目前我脑子里的伪代码如下(不完整):

 function profileDatabase 
   for each table in database 
     for each field that is of type varchar
       select all distinct values and insert into classfication table for that field
     end for
   end for

 function classifyDatabase
   for each table in database 
     for each field that is of type varchar
       // do something efficient to build an insert string to place into new table
     end for
   end for

如果系统中目前有超过 100 次实践、15,000 名患者和 55,000 次恶化,有人可以建议执行此过程的最佳方法,以便高效。我不需要在 php 中实现它,构建我更愿意这样做。任何关于如何构建它的指针都会很棒,因为我不确定我的方法是最好的方法。

随着数据库增长到总共有 100,000 名患者,这个过程必须在接下来的两年中每月运行一次。

【问题讨论】:

对于那些具有有限值集的字段,我建议您使用enums,因为它们可以很容易地转换为数字。 @afaolek 感谢您的提示。我会调查他们。 【参考方案1】:

我已经设法在合理的时间内为这个问题构建了自己的解决方案。对于任何有兴趣的人,或者任何可能遇到类似问题的人,这里都是我使用的方法:

通过调用 php scriptName.php [database-name] 作为 cron 作业运行的 PHP 脚本。该脚本为数据库中的每个表名构建一个分类表(这不是此过程的查找表)。每个分类的设置都会创建一个新表,该表模仿基表的格式,但将所有字段设置为允许 NULL 值。然后它为在基表中找到的每一行创建空白行。然后该过程通过逐个字段分析每个表字段并使用该字段的正确类更新每一行来继续。

我确信我可以优化这个函数来改善当前的复杂性,但现在我将使用这种方法,直到脚本的运行时间超出可接受的范围。

脚本代码:

include ("../application.php");

profileDatabase("coco");
classifyDatabase("coco");

function profileDatabase($database) 
    mysql_select_db($database);
    $query = "SHOW TABLES";
    $result = db_query($query);
    $dbProfile = array();
    while ($obj = mysql_fetch_array($result)) 
        if (!preg_match("/_/", $obj[0])) 
            $dbProfile[$obj[0]] = profileTable($obj[0]);
        
    
    return $dbProfile;


function profileTable($table) 
    $tblProfile = array();
    $query = "DESCRIBE $table";
    $result = db_query($query);
    while ($obj = mysql_fetch_array($result)) 
        $type = substr($obj[1], 0, 7);
//echo $type;
        if (preg_match("/varchar/", $obj[1]) && (!preg_match("/Id/", $obj[0]) && !preg_match("/date/", $obj[0]) && !preg_match("/dob/", $obj[0]))) 
            $x = createLookup($obj[0], $table);
            $arr = array($obj[0], $x);
            $tblProfile[] = $arr;
        
    
    return $tblProfile;


function getDistinctValues($field, $table) 
    $distinct = array();
    $query = "SELECT DISTINCT $field as 'value', COUNT($field) as 'no' FROM $table GROUP BY $field ORDER BY no DESC";
    $result = db_query($query);
    while ($obj = mysql_fetch_array($result)) 
        $distinct[] = $obj;
    
    return $distinct;


function createLookup($field, $table) 
    $query = "CREATE TABLE IF NOT EXISTS `" . $table . "_" . $field . "`
(
`id` int(5) NOT NULL auto_increment,
`value` varchar(255) NOT NULL,
`no` int(5) NOT NULL,
`map1` int(3) NOT NULL,
`map2` int(3) NOT NULL,
PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1";
    db_query($query);
    $distinct = getDistinctValues($field, $table);
    $count = count($distinct);
    foreach ($distinct as $val) 
        $val['value'] = addslashes($val['value']);
        $rs = db_query("SELECT id FROM " . $table . "_" . $field . " WHERE value = '" . $val['value'] . "' LIMIT 1");
        if (mysql_num_rows($rs) == 0) 
            $sql = "INSERT INTO " . $table . "_" . $field . " (value,no) VALUES ('" . $val['value'] . "', " . $val['no'] . ")";
         else 
            $sql = "UPDATE " . $table . "_" . $field . " (value,no) VALUES ('" . $val['value'] . "', " . $val['no'] . ")";
        
        db_query($sql);
    
    return $count;


function classifyDatabase($database) 
    mysql_select_db($database);
    $query = "SHOW TABLES";
    $result = db_query($query);
    $dbProfile = array();
    while ($obj = mysql_fetch_array($result)) 
        if (!preg_match("/_/", $obj[0])) 
            classifyTable($obj[0]);
            //echo "Classfied $obj[0]\n";
        
    


function classifyTable($table) 
    $query = "SHOW TABLES";
    $result = db_query($query);
    $dbProfile = array();
    $setup = true;
    while ($obj = mysql_fetch_array($result)) 
        if ($obj[0] == "classify_" . $table)
            $setup = false;
    
    if ($setup) 
        setupClassifyTable($table);
        //echo "Setup $table\n";
    

    $query = "DESCRIBE $table";
    $result = db_query($query);
    while ($obj = mysql_fetch_array($result)) 
        if (preg_match("/varchar/", $obj[1]) && (!preg_match("/Id/", $obj[0]) && !preg_match("/date/", $obj[0]) && !preg_match("/dob/", $obj[0]))) 
            $rs = db_query("
        SELECT t.entryId, t.$obj[0], COALESCE(tc.map1,99) as 'group' FROM $table t 
        LEFT JOIN " . $table . "_$obj[0] tc ON t.$obj[0] = tc.value 
        ORDER BY tc.map1 ASC");
            while ($obj2 = mysql_fetch_object($rs)) 
                $sql = "UPDATE classify_$table SET $obj[0] = $obj2->group WHERE entryId = $obj2->entryId";
                db_query($sql);
            
         else 
            if ($obj[0] != "entryId") 
                $rs = db_query("
        SELECT t.entryId, t.$obj[0] as 'value' FROM $table t");
                while ($obj2 = mysql_fetch_object($rs)) 
                    $sql = "UPDATE classify_$table SET $obj[0] = '" . addslashes($obj2->value) . "' WHERE entryId = $obj2->entryId";
                    db_query($sql);
                
            
        
    


function setupClassifyTable($table) 
    $tblProfile = array();
    $query = "DESCRIBE $table";
    $result = db_query($query);
    $create = "CREATE TABLE IF NOT EXISTS `classify_$table` (";
    while ($obj = mysql_fetch_array($result)) 
        if (preg_match("/varchar/", $obj[1]) && (!preg_match("/Id/", $obj[0]) && !preg_match("/date/", $obj[0]) && !preg_match("/dob/", $obj[0]))) 
            //echo $obj[1]. " matches<br/>";
            $create .= "$obj[0] int(3) NULL,";
         else 
            $create .= "$obj[0] $obj[1] NULL,";
        
    
    $create .= "PRIMARY KEY(`entryId`)) ENGINE=MyISAM DEFAULT CHARSET=latin1";
    db_query($create);
    $result = mysql_query("SELECT entryId FROM $table");
    while ($obj = mysql_fetch_object($result)) 
        db_query("INSERT IGNORE INTO classify_$table (entryId) VALUES ($obj->entryId)");
    


?>

【讨论】:

【参考方案2】:

也许http://dev.mysql.com/doc/refman/5.1/en/procedure-analyse.html 将有助于了解如何使用字段。

【讨论】:

有用的链接。但我正在寻找有关构建一种基于字符串 - 组分类将数据从字符串转换为组的有效方法的建议。

以上是关于Varchar 值到数值分类的主要内容,如果未能解决你的问题,请参考以下文章

在SQL语句中怎样对varchar型别的列进行数值大小的比较

MySQL数据类型

使用 Jooq 在数值基础上按 varchar 字段(具有数值)对查询进行排序

MySQL 如何从 varchar 列中获取精确的整数值

从数字到varchar的CAST返回指数值? [复制]

选择转换为小数的最大 varchar