代码之家  ›  专栏  ›  技术社区  ›  zaf

从多个表中选择

  •  15
  • zaf  · 技术社区  · 15 年前

    使用php/pdo/mysql,当对多个表执行select操作并且返回的数组键完全限定以避免列名冲突时,是否可以对列使用通配符?

    例子:

    从表1、表2中选择*;

    给予:

    数组键有'table1.id'、'table2.id'、'table1.name'等。

    我尝试了“选择表1.*,表2.*”,但返回的数组键没有完全限定,因此同名列冲突并被覆盖。

    5 回复  |  直到 7 年前
        1
  •  14
  •   goat    7 年前

    是的,你可以。最简单的方法是使用PDO,尽管至少还有一些其他扩展能够做到这一点。

    pdo

    在上设置属性 PDO 对象,而不是 PDOStatment .

    $PDO->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, true);
    

    就是这样。然后得到关联数组键 $row['myTable.myColumn'] . 如果你也提取一个对象(例如通过 PDO::FETCH_OBJECT )所以要小心,因为你需要访问 $obj->{'myTable.myColumn'}

    * manual says 这个 PDO::ATTR_FETCH_TABLE_NAMES 属性仅受某些驱动程序支持。如果上面不起作用,这个 可以 而不是工作。

    $pdoStatement->setFetchMode(PDO::FETCH_NUM);
    $pdoStatement->execute();
    //build our associative array keys
    $qualifiedColumnNames = array();
    for ($i = 0; $i < $pdoStatement->columnCount(); $i++) {
        $columnMeta = $pdoStatement->getColumnMeta($i);
        $qualifiedColumnNames[] = "$columnMeta[table].$columnMeta[name]";
    }
    
    //fetch results and combine with keys
    while ($row = $pdoStatement->fetch()) {
        $qualifiedRow = array_combine($qualifiedColumnNames, $row);
        print_r($qualifiedRow);
    }
    

    其他数据库扩展使用相同的基本模式

    mysql

    $res = mysql_query($sql);
    //build our associative array keys
    $qualifiedColumnNames = array();
    for ($i = 0; $i < mysql_num_fields($res); $i++) {
        $columnMeta = mysql_fetch_field($res, $i);
        $qualifiedColumnNames[] = "$columnMeta[table].$columnMeta[name]";
    }
    
    //fetch results and combine with keys
    while ($row = mysql_fetch_row($res)) {
        $qualifiedRow = array_combine($qualifiedColumnNames, $row);
        print_r($qualifiedRow);
    }
    

    mysqli

    $res = $mysqli->query($sql);
    //build our associative array keys
    $qualifiedColumnNames = array();
    foreach ($res->fetch_fields() as $columnMeta) {
        $qualifiedColumnNames[] = "{$columnMeta->table}.{$columnMeta->name}";
    }
    
    //fetch results and combine with keys
    while ($row = $res->fetch_row()) {
        $qualifiedRow = array_combine($qualifiedColumnNames, $row);
        print_r($qualifiedRow);
    }
    

    这也适用于表别名(在php 7.1中测试)——限定的列名将使用表别名。

        2
  •  4
  •   KM.    15 年前

    您可以这样做:

    SELECT Table1.*,Table2.xyz, Table2.abc,... From...
    

    使用“*”从一个表中获取所有列,然后只从另一个表中获取所需的列,这样就不会发生冲突。

    您还可以使用列别名,在其中“重命名”列:

    SELECT Table1.A AS T1_A,Table2.A AS T2_A,... From...
    

    您的结果集将是T1列和T2列

        3
  •  2
  •   Adam Robinson    15 年前

    不幸的是,没有;没有用于确保列名唯一的SQL语法。

    如果您确实不知道列的名称,必须使用 SELECT * ,您唯一真正的选择是恢复到一些外观非常丑陋的动态SQL,它可以检查表的结构并生成一个查询,该查询将使用表名前缀显式地选择所有表。

    我不知道您使用的是哪种RDBMS,但类似的功能应该在SQL Server上工作:

    declare @columns table (idx int identity(1,1), tablename varchar(100), columnname varchar(100))
    
    insert into @columns (tablename, columnname) 
    select tablename, columnname
    
    from INFORMATION_SCHEMA.COLUMNS
    
    where tablename in ('table_1', 'table_2')
    
    declare @sql nvarchar(4000)
    
    declare @i int
    declare @cnt in
    
    declare @col varchar(100)
    declare @table varchar(100)
    
    select @i = 0, @cnt = max(idx), @sql = '' from @columns
    
    while @i < @cnt
    begin
        select @i = @i + 1
    
        select @col = columnname, @table = tablename from @columns where idx = @i
    
        if len(@sql) > 0
            select @sql = @sql + ', '
    
        select @sql = @sql + '[' + @table + '].[' + @col + '] as [' + @table + '_' + @col + ']'
    end
    
    select @sql = 'select ' + @sql + ' from table_1, table_2'
    
    exec sp_executesql @sql
    
        4
  •  1
  •   William Entriken    8 年前

    不知羞耻地从@goat重新包装:

    // Workaround for setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, true);
    function pdoStatementExecuteAndFetchObjWithTableNames(PDOStatement $statement)
    {
      $statement->setFetchMode(PDO::FETCH_NUM);
      $statement->execute();
    
      //build our associative array keys
      $qualifiedColumnNames = array();
      for ($i = 0; $i < $statement->columnCount(); $i++) {
          $columnMeta = $statement->getColumnMeta($i);
          $qualifiedColumnNames[] = "$columnMeta[table].$columnMeta[name]";
      }
    
      //fetch results and combine with keys
      while ($row = $statement->fetch()) {
          $qualifiedRow = array_combine($qualifiedColumnNames, $row);
          yield (object) $qualifiedRow;
      }  
    }
    

    注:如果使用:

    从“我的表”中选择1作为“我的表”别名

    然后你会得到 my_table . 我本来希望 my_table_alias . 我用php 5.6和sqlite驱动程序得到了这个结果。

        5
  •  0
  •   Dominic Barnes    15 年前

    不幸的是,php(尤其是mysql、pgsql、mssql扩展)总是在重叠的情况下覆盖列。

    我建议创建一个 View 在数据库中,对列进行别名,以便它们“完全限定”。

    例如:(mysql)

    CREATE VIEW viewTable1Table2 AS
        SELECT
            t1.field1 AS Table1Field1
            t2.field1 AS Table2Field1
        FROM Table1 t1
            INNER JOIN Table2 t2
                ON t1.id = t2.id;
    

    语法可能不完美,但您可以大致了解我在说什么。