简体   繁体   English

SQL从多个表中选择*

[英]SQL Select * from multiple tables

Using PHP/PDO/MySQL is it possible to use a wildcard for the columns when a select is done on multiple tables and the returned array keys are fully qualified to avoid column name clash? 使用PHP / PDO / MySQL可以在多个表上执行select时对列使用通配符,并且返回的数组键完全限定以避免列名冲突?

example: 例:

SELECT * from table1, table2; SELECT * from table1,table2;

gives: 得到:

Array keys are 'table1.id', 'table2.id', 'table1.name' etc. 数组键是'table1.id','table2.id','table1.name'等。

I tried "SELECT table1.*,table2.* ..." but the returned array keys were not fully qualified so columns with the same name clashed and were overwritten. 我尝试了“SELECT table1。*,table2。* ...”但是返回的数组键不是完全限定的,因此具有相同名称的列会发生冲突并被覆盖。

Yes, you can. 是的你可以。 The easiest way is with pdo, although there's at least a few other extensions which are capable of it. 最简单的方法是使用pdo,尽管至少有一些其他扩展能够实现。

pdo PDO

Set the attribute on the PDO object, not the PDOStatment . PDO对象上设置属性,而不是PDOStatment

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

That's it. 而已。 Then you get associative array keys like $row['myTable.myColumn'] . 然后你得到像$row['myTable.myColumn']这样的关联数组键。 It works if you fetch an object too (eg via PDO::FETCH_OBJECT ) so beware, because you need to access the properties like $obj->{'myTable.myColumn'} 它也适用于你获取一个对象(例如通过PDO::FETCH_OBJECT )所以要小心,因为你需要访问像$obj->{'myTable.myColumn'}这样的属性

*The manual says the PDO::ATTR_FETCH_TABLE_NAMES attribute is only supported by certain drivers. * 手册说 PDO::ATTR_FETCH_TABLE_NAMES属性仅受某些驱动程序支持。 If the above doesn't work, this might work instead. 如果上述方法不起作用,则可能会有效。

$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);
}

Same basic pattern is used for other database extensions 相同的基本模式用于其他数据库扩展

mysql 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 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);
}

This should also work with table aliases (tested in php 7.1) - the qualified column name will use the table alias. 这也适用于表别名(在php 7.1中测试) - 限定列名将使用表别名。

you can do this: 你可以这样做:

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

where you get all columns from one table using "*" and then just the columns from the other table you need, so there is no clash. 在哪里使用“*”获取一个表中的所有列,然后使用您需要的另一个表中的列,这样就不会发生冲突。

You could also use column aliases, where you "rename" a column: 您还可以使用列别名,在其中“重命名”列:

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

your result set would be of columns T1_A and T2_A 您的结果集将是列T1_A和T2_A

Unfortunately, no; 抱歉不行; there is no SQL syntax for ensuring that column names are unique. 没有用于确保列名唯一的SQL语法。

If you truly don't know the names of the columns and must use SELECT * , your only real option would be to revert to some very ugly looking dynamic SQL that could inspect the structure of the tables and generate a query that would select them all explicitly with a table-name prefix. 如果您真的不知道列的名称并且必须使用SELECT * ,那么您唯一真正的选择是恢复到一些看起来非常难看的动态SQL,它可以检查表的结构并生成一个可以选择它们的查询显式地使用表名前缀。

I don't know which RDBMS you're using, but something like this should work on SQL Server: 我不知道您使用的是哪个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

Shamelessly repackaged from @goat: 从@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;
  }  
}

NOTE: if you use: 注意:如果您使用:

SELECT 1 FROM my_table AS my_table_alias SELECT 1 FROM my_table AS my_table_alias

then you will get my_table . 然后你会得到my_table I would have hoped for my_table_alias . 我希望my_table_alias I got this result with PHP 5.6 and sqlite driver. 我用PHP 5.6和sqlite驱动程序得到了这个结果。

Unfortunately, PHP (particularly the MySQL, PgSQL, MSSQL extensions) will always have your columns overwrite in the case of overlap. 不幸的是,PHP(特别是MySQL,PgSQL,MSSQL扩展)在重叠的情况下总是会覆盖您的列。

I would recommend creating a View in your database, and Alias your columns so that they are "fully-qualified". 我建议在数据库中创建一个View ,并为列添加Alias以使它们“完全合格”。

For example: (MySQL) 例如:(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;

The syntax may not be perfect, but you can get a general idea of what I am talking about. 语法可能不完美,但您可以大致了解我在说什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM