【问题标题】:how to extract table names from mysql query with php?如何使用 php 从 mysql 查询中提取表名?
【发布时间】:2012-06-16 04:13:23
【问题描述】:

我想用 php 检测 mysql 查询中的所有表。我看到了适用于普通查询的 mysql_field_table() 函数。但是当您为表使用替代名称时(table_name AS new_name)它返回替代名称而不是真实名称,我如何通过正则表达式修复它。但现在我的问题是这样的高级查询:

SELECT mail_id, mail_date, mail_from, mail_to, mail_subject, (
            (
            SELECT COUNT(*)
            FROM `sys_messagecenter_qmails`
            WHERE qmail_mail_id = mail_id
            ) + (
            SELECT COUNT(*)
            FROM `sys_messagecenter_rels`
            WHERE rel_mail_id = mail_id
            )
            ) AS email_total, (
            SELECT COUNT(*)
            FROM `sys_messagecenter_rels`
            WHERE rel_mail_id = mail_id
            ) AS email_sent, (
            SELECT COUNT(*)
            FROM `sys_messagecenter_rels`
            INNER JOIN `sys_email_receives` ON receive_reply_to = rel_sent_id
            WHERE rel_mail_id = mail_id
            ) AS email_reply FROM `sys_messagecenter_emails` WHERE mail_draft='No' 
ORDER BY mail_id ASC LIMIT 0,10 

现在我想我需要一些正则表达式来检测查询中的所有真实表名。或任何其他完美的解决方案。我该怎么做?

【问题讨论】:

  • 我认为你做不到。如果您构建查询,您是否已经知道表名?您需要在查询执行后找出表名还是要提取查询变量中使用的表?
  • 必须由开发人员在他们的模块中编写查询。这是 CMS 的一部分。所以不,我不知道表名。我需要一种在查询运行之前或之后定义表名的方法
  • OMFG,如果这是来自 CMS 的查询,我希望它永远不会看到阳光......
  • @shadyyx :D 它只是一个在管理页面中运行的查询,所以不用担心这个 CMS 不会使 mysql 服务器崩溃 :P
  • @shadyyx 这绝对是一个例子(不是普通查询)因为我不知道,开发人员可能会做这样的事情,我必须呈现所有类型的查询

标签: php mysql regex


【解决方案1】:

抱歉...这里有一个提取它的解决方案(如果您在 $query 中查询)

if(preg_match_all('/((FROM|JOIN) `(.*)`)/', $query, $matches)) {
    $tables = array_unique($matches[3]);
    print_r($tables);
}

【讨论】:

  • 基本上是想从查询中提取表名而不是提取数据库中的所有表
  • @IVIR3zaM 我改变了答案
  • 当我运行这个时,我在第一个和最后一个之间得到了很大的范围,而不是选择每个单独的表。这是我用来单独获取每个表的行/((from|join) `(.*?)`)/
【解决方案2】:

我还需要从查询中提取表名。然后我编写自己的脚本,该脚本几乎适用于每个基本查询。

$tables = array();
$sql ="SELECT m.`id` FROM my_table m INNER JOIN mytable_2 m2 ON(m.`id` = m2.`m_id`) ";

    $query_structure = explode( ' ', strtolower( preg_replace('!\s+!', ' ', $sql) ) );

    $searches_from = array_keys( $query_structure , 'from');
    $searches_join = array_keys( $query_structure , 'join');
    $searches_update = array_keys( $query_structure , 'update');
    $searches_into = array_keys( $query_structure , 'into');
    $searches = array_merge($searches_join , $searches_from , $searches_update , $searches_into );
    foreach($searches as $search ){
        if(isset($query_structure[$search+1])){
            $tables[] = trim( $query_structure[$search+1] , '` ');
        }
    }
    print_r($tables);

希望这会有所帮助

【讨论】:

    【解决方案3】:

    这不是最优雅的解决方案,但已经通过了我迄今为止运行的所有测试:

    function get_table_name($query) {
    
        $query = trim(str_replace(PHP_EOL, ' ', $query));
    
        $table = '';
    
        if(strtolower(substr($query, 0, 12)) == 'create table') {
            $start = stripos($query, 'CREATE TABLE') + 12;
            $end = strpos($query, '(');
            $length = $end - $start;
            $table = substr($query, $start, $length);
        }
        elseif(strtolower(substr($query, 0, 6)) == 'update') {
            $end = stripos($query, 'SET');
            $table = substr($query, 6, $end);
        }
        elseif(strtolower(substr($query, 0, 11)) == 'alter table') {
            $parts = explode(' ', $query);
            $table = $parts[2];
        }
        elseif(strtolower(substr($query, 0, 11)) == 'insert into') {
            $parts = explode(' ', $query);
            $table = $parts[2];
        }
        elseif(strtolower(substr($query, 0, 12)) == 'create index') {
            $parts = explode(' ', $query);
            $table = $parts[4];
        }
        elseif(strtolower(substr($query, 0, 6)) == 'select') {
            $parts = explode(' ', $query);
            foreach($parts as $i => $part) {
                if(trim(strtolower($part)) == 'from') {
                    $table = $parts[$i + 1];
                    break;
                }
            }
        }
        elseif(strtolower(substr($query, 0, 29)) == 'create unique clustered index') {
            $parts = explode(' ', $query);
            $table = $parts[6];
        }
        elseif(strtolower(substr($query, 0, 22)) == 'create clustered index') {
            $parts = explode(' ', $query);
            $table = $parts[5];
        }
        elseif(strtolower(substr($query, 0, 15)) == 'exec sp_columns') {
            $parts = explode(' ', $query);
            $table = str_replace("'", '', $parts[2]);
        }
        elseif(strtolower(substr($query, 0, 11)) == 'delete from') {
            $parts = explode(' ', $query);
            $table = str_replace("'", '', $parts[2]);
        }
    
        return trim(str_replace(['`', '[', ']'], ['', '', ''], $table));
    
    }
    

    【讨论】:

    • SHOW 和 DESCRIBE,虽然可能不太经常使用,但丢失了
    【解决方案4】:

    我使用下面的代码(a 是等效的 var_dump):

    /**
     * Only works if the table names and database names don't have a space or a dot in them.
     */
    
    $queries = [
        "select * from my_table",
        "select * from `my_table`",
        "select * from my_db.my_table",
        "select * from my_db.`my_table`",
        "select id from my_table where x=2",
        "select id from my_table mt inner join other_table ot on ot.my_table_id=mt.id where mt.x=2",
        "SELECT mail_id, mail_date, mail_from, mail_to, mail_subject, (
                (
                SELECT COUNT(*)
                FROM `sys_messagecenter_qmails`
                WHERE qmail_mail_id = mail_id
                ) + (
                SELECT COUNT(*)
                FROM `sys_messagecenter_rels`
                WHERE rel_mail_id = mail_id
                )
                ) AS email_total, (
                SELECT COUNT(*)
                FROM `sys_messagecenter_rels`
                WHERE rel_mail_id = mail_id
                ) AS email_sent, (
                SELECT COUNT(*)
                FROM `sys_messagecenter_rels`
                INNER JOIN `sys_email_receives` ON receive_reply_to = rel_sent_id
                WHERE rel_mail_id = mail_id
                ) AS email_reply FROM `sys_messagecenter_emails` WHERE mail_draft='No' 
    ORDER BY mail_id ASC LIMIT 0,10 ",
          "select count(*) as count from (
    select 
    user_id,
    permission_group_id,
    concat(uhpg.user_id, '. ', u.pseudo) as user_id_plus,
    concat(uhpg.permission_group_id, '. ', pg.name) as permission_group_id_plus
    from lud_user_has_permission_group uhpg
    inner join lud_user u on uhpg.user_id=u.id
    inner join lud_permission_group pg on uhpg.permission_group_id=pg.id
    ) as ttt",
    ];
    
    
    $tables = [];
    
    foreach ($queries as $query) {
        a($query);
        if (preg_match_all('!((FROM|JOIN)\s([\S]+))!i', $query, $matches)) {
            $tables = array_unique($matches[3]);
            array_walk($tables, function (&$v) {
                $p = explode('.', $v, 2);
                $v = array_pop($p);
                $v = trim($v, '`');
            });
            $tables = array_filter($tables, function ($v) {
                return ('(' !== $v);
            });
            a($tables);
        }
    }
    

    它给出以下输出:

    string(22) "select * from my_table"
    
    array(1) {
      [0] => string(8) "my_table"
    }
    
    string(24) "select * from `my_table`"
    
    array(1) {
      [0] => string(8) "my_table"
    }
    
    string(28) "select * from my_db.my_table"
    
    array(1) {
      [0] => string(8) "my_table"
    }
    
    string(30) "select * from my_db.`my_table`"
    
    array(1) {
      [0] => string(8) "my_table"
    }
    
    string(33) "select id from my_table where x=2"
    
    array(1) {
      [0] => string(8) "my_table"
    }
    
    string(89) "select id from my_table mt inner join other_table ot on ot.my_table_id=mt.id where mt.x=2"
    
    array(2) {
      [0] => string(8) "my_table"
      [1] => string(11) "other_table"
    }
    
    string(810) "SELECT mail_id, mail_date, mail_from, mail_to, mail_subject, (
                (
                SELECT COUNT(*)
                FROM `sys_messagecenter_qmails`
                WHERE qmail_mail_id = mail_id
                ) + (
                SELECT COUNT(*)
                FROM `sys_messagecenter_rels`
                WHERE rel_mail_id = mail_id
                )
                ) AS email_total, (
                SELECT COUNT(*)
                FROM `sys_messagecenter_rels`
                WHERE rel_mail_id = mail_id
                ) AS email_sent, (
                SELECT COUNT(*)
                FROM `sys_messagecenter_rels`
                INNER JOIN `sys_email_receives` ON receive_reply_to = rel_sent_id
                WHERE rel_mail_id = mail_id
                ) AS email_reply FROM `sys_messagecenter_emails` WHERE mail_draft='No' 
    ORDER BY mail_id ASC LIMIT 0,10 "
    
    array(4) {
      [0] => string(24) "sys_messagecenter_qmails"
      [1] => string(22) "sys_messagecenter_rels"
      [4] => string(18) "sys_email_receives"
      [5] => string(24) "sys_messagecenter_emails"
    }
    
    string(360) "select count(*) as count from (
    select 
    user_id,
    permission_group_id,
    concat(uhpg.user_id, '. ', u.pseudo) as user_id_plus,
    concat(uhpg.permission_group_id, '. ', pg.name) as permission_group_id_plus
    from lud_user_has_permission_group uhpg
    inner join lud_user u on uhpg.user_id=u.id
    inner join lud_permission_group pg on uhpg.permission_group_id=pg.id
    ) as ttt"
    
    array(3) {
      [1] => string(29) "lud_user_has_permission_group"
      [2] => string(8) "lud_user"
      [3] => string(20) "lud_permission_group"
    }
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-25
      • 2016-06-08
      • 2015-08-05
      • 2011-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多