我想知道这在SQL中是否可行。假设你有两个表A和B,你在表A上做一个选择,在表B上做一个连接:
SELECT a.*, b.* FROM TABLE_A a JOIN TABLE_B b USING (some_id);
如果表A有“a_id”、“name”、“some_id”列,表B有“b_id”、“name”、“some_id”列,查询将返回“a_id”、“name”、“some_id”、“b_id”、“name”、“some_id”列。有什么方法可以为表B的列名加上前缀而不单独列出每一列吗?等价于这个:
SELECT a.*, b.b_id as 'b.b_id', b.name as 'b.name', b.some_id as 'b.some_id'
FROM TABLE_A a JOIN TABLE_B b USING (some_id);
但是,如前所述,没有列出每一列,所以像这样:
SELECT a.*, b.* as 'b.*'
FROM TABLE_A a JOIN TABLE_B b USING (some_id);
基本上就是说,“用‘something’为b.*返回的每一列添加前缀”。这可能吗,还是我运气不好?
编辑
关于不使用SELECT *等的建议是有效的建议,但与我的上下文无关,因此请关注眼前的问题——是否可以在连接中为表的所有列名添加前缀(SQL查询中指定的常量)?
我的最终目标是能够通过连接对两个表执行SELECT *操作,并且能够从结果集中获得的列的名称中分辨出哪些列来自表a,哪些列来自表b。同样,我不想单独列出列,我需要能够执行SELECT *操作。
与非常好的“PHP (Wordpress)函数”相同的响应,但为CakePHP 4.3编码。
放在src/Controller/Component/MyUtilsComponent.php中
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Datasource\ConnectionManager;
class MyUtilsComponent extends Component
{
public static function prefixedTableFieldsWildcard(string $table, string $alias, string $connexion = 'default'): string
{
$c = ConnectionManager::get($connexion);
$columns = $c->execute("SHOW COLUMNS FROM $table");
$field_names = [];
foreach ($columns as $column) {
$field_names[] = $column['Field'];
}
$prefixed = [];
foreach ($field_names as $field_name) {
$prefixed[] = "`{$alias}`.`{$field_name}` AS `{$alias}.{$field_name}`";
}
return implode(', ', $prefixed);
}
}
测试和使用
function testPrefixedTableFieldsWildcard(): void
{
$fields = MyUtilsComponent::prefixedTableFieldsWildcard('metas', 'u', 'test');
$this->assertEquals('`u`.`id` AS `u.id`, `u`.`meta_key` AS `u.meta_key`, `u`.`meta_value` AS `u.meta_value`, `u`.`meta_default` AS `u.meta_default`, `u`.`meta_desc` AS `u.meta_desc`', $fields,);
}
对于使用MySQL C-API的人来说,你的问题有一个直接的答案。
给定SQL:
SELECT a.*, b.*, c.* FROM table_a a JOIN table_b b USING (x) JOIN table_c c USING (y)
'mysql_stmt_result_metadata()'的结果将准备好的SQL查询中的字段定义提供到结构MYSQL_FIELD[]中。每个字段包含以下数据:
char *name; /* Name of column (may be the alias) */
char *org_name; /* Original column name, if an alias */
char *table; /* Table of column if column was a field */
char *org_table; /* Org table name, if table was an alias */
char *db; /* Database for table */
char *catalog; /* Catalog for table */
char *def; /* Default value (set by mysql_list_fields) */
unsigned long length; /* Width of column (create length) */
unsigned long max_length; /* Max width for selected set */
unsigned int name_length;
unsigned int org_name_length;
unsigned int table_length;
unsigned int org_table_length;
unsigned int db_length;
unsigned int catalog_length;
unsigned int def_length;
unsigned int flags; /* Div flags */
unsigned int decimals; /* Number of decimals in field */
unsigned int charsetnr; /* Character set */
enum enum_field_types type; /* Type of field. See mysql_com.h for types */
请注意以下字段:catalog、table、org_name
现在您知道SQL中的哪个字段属于哪个模式(即目录)和表。
这足以从多表sql查询中通用地识别每个字段,而不需要别名。
一个实际的产品SqlYOG在这样一个庄园中使用这个确切的数据,当PK字段存在时,它们能够独立地更新多表连接的每个表。
与非常好的“PHP (Wordpress)函数”相同的响应,但为CakePHP 4.3编码。
放在src/Controller/Component/MyUtilsComponent.php中
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Datasource\ConnectionManager;
class MyUtilsComponent extends Component
{
public static function prefixedTableFieldsWildcard(string $table, string $alias, string $connexion = 'default'): string
{
$c = ConnectionManager::get($connexion);
$columns = $c->execute("SHOW COLUMNS FROM $table");
$field_names = [];
foreach ($columns as $column) {
$field_names[] = $column['Field'];
}
$prefixed = [];
foreach ($field_names as $field_name) {
$prefixed[] = "`{$alias}`.`{$field_name}` AS `{$alias}.{$field_name}`";
}
return implode(', ', $prefixed);
}
}
测试和使用
function testPrefixedTableFieldsWildcard(): void
{
$fields = MyUtilsComponent::prefixedTableFieldsWildcard('metas', 'u', 'test');
$this->assertEquals('`u`.`id` AS `u.id`, `u`.`meta_key` AS `u.meta_key`, `u`.`meta_value` AS `u.meta_value`, `u`.`meta_default` AS `u.meta_default`, `u`.`meta_desc` AS `u.meta_desc`', $fields,);
}
最近在NodeJS和Postgres中遇到了这个问题。
ES6方法
我知道没有任何RDBMS特性提供这种功能,所以我创建了一个包含我所有字段的对象,例如:
const schema = { columns: ['id','another_column','yet_another_column'] }
定义了一个reducer将字符串与表名连接在一起:
const prefix = (table, columns) => columns.reduce((previous, column) => {
previous.push(table + '.' + column + ' AS ' + table + '_' + column);
return previous;
}, []);
这将返回一个字符串数组。为每个表调用它并合并结果:
const columns_joined = [...prefix('tab1',schema.columns), ...prefix('tab2',schema.columns)];
输出最后的SQL语句:
console.log('SELECT ' + columns_joined.join(',') + ' FROM tab1, tab2 WHERE tab1.id = tab2.id');