【发布时间】:2009-05-07 12:44:47
【问题描述】:
我有两个动态表(tabx 和 taby),它们是通过 php 界面创建和维护的,可以在其中添加、删除、重命名等列。 我想像这样从两个表中同时读取所有列;-
select * from tabx,taby where ... ;
我希望能够从查询结果中判断每列是来自 tabx 还是 taby - 有没有办法强制 mysql 返回完全限定的列名,例如tabx.col1、tabx.col2、taby.coln 等?
【问题讨论】:
我有两个动态表(tabx 和 taby),它们是通过 php 界面创建和维护的,可以在其中添加、删除、重命名等列。 我想像这样从两个表中同时读取所有列;-
select * from tabx,taby where ... ;
我希望能够从查询结果中判断每列是来自 tabx 还是 taby - 有没有办法强制 mysql 返回完全限定的列名,例如tabx.col1、tabx.col2、taby.coln 等?
【问题讨论】:
在PHP中,你可以从结果中获取字段信息,就像这样(从我很久以前写的一个项目中偷来的):
/*
Similar to mysql_fetch_assoc(), this function returns an associative array
given a mysql resource, but prepends the table name (or table alias, if
used in the query) to the column name, effectively namespacing the column
names and allowing SELECTS for column names that would otherwise have collided
when building a row's associative array.
*/
function mysql_fetch_assoc_with_table_names($resource) {
// get a numerically indexed row, which includes all fields, even if their names collide
$row = mysql_fetch_row($resource);
if( ! $row)
return $row;
$result = array();
$size = count($row);
for($i = 0; $i < $size; $i++) {
// now fetch the field information
$info = mysql_fetch_field($resource, $i);
$table = $info->table;
$name = $info->name;
// and make an associative array, where the key is $table.$name
$result["$table.$name"] = $row[$i]; // e.g. $result["user.name"] = "Joe Schmoe";
}
return $result;
}
那么你可以这样使用它:
$resource = mysql_query("SELECT * FROM user JOIN question USING (user_id)");
while($row = mysql_fetch_assoc_with_table_names($resource)) {
echo $row['question.title'] . ' Asked by ' . $row['user.name'] . "\n";
}
所以要直接回答你的问题,表名数据总是由 MySQL 发送的——由客户端来告诉你每列的来源。如果您真的希望 MySQL 明确地返回每个列名,则需要修改查询以显式执行别名,如 @Shabbyrobe 建议的那样。
【讨论】:
select * from tabx tx, taby ty where ... ;
【讨论】:
做:
SELECT tabx.*, taby.* FROM tabx, taby WHERE ...
工作?
【讨论】:
我想知道您要完成什么。首先,在表中添加和删除列是一种奇怪的做法;这意味着您的数据架构在运行时正在发生变化。
此外,要同时从两个表中查询,它们之间应该存在某种关系。一个表中的行应该以某种方式与另一个表中的行相关联。如果不是这种情况,最好执行两个单独的 SELECT 查询。
您的问题的答案已经给出:SELECT tablename.* 从给定表中检索所有列。如果两个表中都有同名的列,这可能会也可能不会正常工作;您应该在文档中查找。
您能否就您要解决的问题向我们提供更多信息?我认为你很有可能会走错路。
【讨论】:
撇开关于为什么要这样做以及为什么要在这里进行交叉连接的任何问题,这是我能想到的最好的方法。
您可以尝试对每个表执行 EXPLAIN 并根据结果以编程方式构建 select 语句。这是一个糟糕的脚本示例,它将为您提供一个动态生成的带有别名的字段列表。这将增加您执行的查询数量,因为动态生成的查询中的每个表都会导致 EXPLAIN 查询被触发(尽管这可以通过缓存相当容易地缓解)。
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
function aliasFields($pdo, $table, $delim='__') {
$fields = array();
// gotta sanitise the table name - can't do it with prepared statement
$table = preg_replace('/[^A-z0-9_]/', "", $table);
foreach ($pdo->query("EXPLAIN `".$table."`") as $row) {
$fields[] = $table.'.'.$row['Field'].' as '.$table.$delim.$row['Field'];
}
return $fields;
}
$fieldAliases = array_merge(aliasFields($pdo, 'artist'), aliasFields($pdo, 'event'));
$query = 'SELECT '.implode(', ', $fieldAliases).' FROM artist, event';
echo $query;
结果是一个如下所示的查询,表名和列名由两个下划线分隔(或任何您喜欢的分隔符,请参见 aliasFields() 的第三个参数):
// ABOVE PROGRAM'S OUTPUT (assuming database exists)
SELECT artist__artist_id, artist__event_id, artist__artist_name, event__event_id, event__event_name FROM artist, event
从那里,当您迭代结果时,您可以使用相同的分隔符对每个字段名称进行分解,以获得表名称和字段名称。
John Douthat 的回答比上面的要好得多。仅当数据库未返回字段元数据时它才有用,因为 PDO 威胁可能是某些驱动程序的情况。
这是一个简单的 sn-p,说明如何使用 PDO 而不是 mysql_*() 来执行 John 建议的操作:
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
$query = 'SELECT artist.*, eventartist.* FROM artist, eventartist LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch()) {
foreach ($row as $key=>$value) {
if (is_int($key)) {
$meta = $stmt->getColumnMeta($key);
echo $meta['table'].".".$meta['name']."<br />";
}
}
}
【讨论】: