我想知道这在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 *操作。


当前回答

如果关心模式变化,这可能对你有用: 1. 在所有涉及的表上运行'DESCRIBE table'查询。 2. 使用返回的字段名动态构造以所选别名为前缀的列名字符串。

其他回答

或者你可以使用Red Gate SQL Refactor或SQL Prompt,它通过单击Tab按钮将SELECT *展开为列列表

所以在你的例子中,如果你输入SELECT * FROM A JOIN B… 转到*的末尾,Tab键,瞧!你会看到 选择a . columnn1, A.column2, ...., B. columnn1, B.column2 FROM A JOIN

但它不是免费的

I see two possible situations here. First, you want to know if there is a SQL standard for this, that you can use in general regardless of the database. No, there is not. Second, you want to know with regard to a specific dbms product. Then you need to identify it. But I imagine the most likely answer is that you'll get back something like "a.id, b.id" since that's how you'd need to identify the columns in your SQL expression. And the easiest way to find out what the default is, is just to submit such a query and see what you get back. If you want to specify what prefix comes before the dot, you can use "SELECT * FROM a AS my_alias", for instance.

与非常好的“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,);
    }

我知道的唯一一个这样做的数据库是SQLite,这取决于你使用PRAGMA full_column_names和PRAGMA short_column_names配置的设置。参见http://www.sqlite.org/pragma.html

否则,如果在查询中键入列名对您来说太麻烦的话,我所能建议的是通过序号位置而不是通过列名来获取结果集中的列。

这是一个很好的例子,说明了为什么使用SELECT *是不好的做法——因为最终您还是需要输入所有列名。

我理解需要支持可能更改名称或位置的列,但使用通配符会使这变得更加困难,而不是更容易。

最近在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');