【问题标题】:SQL select join: is it possible to prefix all columns as 'prefix.*'?SQL select join:是否可以为所有列添加前缀“prefix.*”?
【发布时间】:2010-09-24 16:50:56
【问题描述】:

我想知道这在 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);

基本上要说,“在 b.* 返回的每一列前面加上 'something'”。这是可能的还是我不走运?

编辑

关于不使用SELECT * 等的建议是有效的建议,但与我的上下文无关,所以请坚持手头的问题——是否可以添加前缀(SQL 查询中指定的常量)到连接中表的所有列名?

我的最终目标是能够通过连接在两个表上执行SELECT *,并且能够根据我在结果集中获得的列的名称来判断哪些列来自表 A,哪些列来自表 A列来自表 B。同样,我不想单独列出列,我需要能够执行 SELECT *

【问题讨论】:

  • 您希望查询的结果究竟是什么?我很困惑
  • GregD:我希望所有来自 b.* 的列名都以我指定的某个常量作为前缀。例如,我想指定“special_”前缀并获取“special_name”和“special_number”,而不是“name”和“number”。但我不想单独为每一列执行此操作。
  • 当我快速 SELECT 以查看多个表中的列时,我有时会从 TableA 中选择 'AAAAA', A.*, 'BBBBB', B.* 作为 A JOIN TableB AS B ON A。 ID = B.ID 这样我在沿行扫描时至少有一个表标识符
  • 也许为此使用架构会有所帮助?

标签: sql join


【解决方案1】:

您的问题的答案似乎是否定的,但是您可以使用的一种技巧是分配一个虚拟列来分隔每个新表。如果您要循环使用 Python 或 PHP 等脚本语言的列列表的结果集,这种方法尤其适用。

SELECT '' as table1_dummy, table1.*, '' as table2_dummy, table2.*, '' as table3_dummy, table3.* FROM table1
JOIN table2 ON table2.table1id = table1.id
JOIN table3 ON table3.table1id = table1.id

我知道这并不能准确回答您的问题,但如果您是编码人员,这是分隔具有重复列名的表的好方法。希望这对某人有所帮助。

【讨论】:

  • 它确实对我有帮助。非常感谢分享
【解决方案2】:

我在这里看到两种可能的情况。首先,您想知道是否有针对此的 SQL 标准,无论数据库如何,您都可以使用该标准。不,那里没有。其次,您想了解特定的 dbms 产品。然后你需要识别它。但我想最有可能的答案是你会得到类似“a.id, b.id”的东西,因为这就是你需要识别 SQL 表达式中的列的方式。找出默认值的最简单方法就是提交这样的查询,看看你会得到什么。如果你想指定点之前的前缀,你可以使用“SELECT * FROM a AS my_alias”,例如。

【讨论】:

  • 我不确定这如何回答您的问题。我正在使用 MS SQL Server 并在表名后添加别名不会将别名附加到结果集中的列名。
【解决方案3】:

我完全理解为什么这是必要的 - 至少对我来说,当需要连接很多表(包括许多内部连接)时,它在快速原型制作过程中很方便。一旦第二个“joinedtable.*”字段通配符中的列名相同,主表的字段值就会被joinedtable值覆盖。当不得不一遍又一遍地手动指定具有别名的表字段时,容易出错、令人沮丧并且违反 DRY...

这里有一个 PHP (Wordpress) 函数通过代码生成来实现这一点,以及如何使用它的示例。在示例中,它用于快速生成自定义查询,该查询将提供通过 高级自定义字段 字段引用的相关 wordpress 帖子的字段。

function prefixed_table_fields_wildcard($table, $alias)
{
    global $wpdb;
    $columns = $wpdb->get_results("SHOW COLUMNS FROM $table", ARRAY_A);

    $field_names = array();
    foreach ($columns as $column)
    {
        $field_names[] = $column["Field"];
    }
    $prefixed = array();
    foreach ($field_names as $field_name)
    {
        $prefixed[] = "`{$alias}`.`{$field_name}` AS `{$alias}.{$field_name}`";
    }

    return implode(", ", $prefixed);
}

function test_prefixed_table_fields_wildcard()
{
    global $wpdb;

    $query = "
    SELECT
        " . prefixed_table_fields_wildcard($wpdb->posts, 'campaigns') . ",
        " . prefixed_table_fields_wildcard($wpdb->posts, 'venues') . "
        FROM $wpdb->posts AS campaigns
    LEFT JOIN $wpdb->postmeta meta1 ON (meta1.meta_key = 'venue' AND campaigns.ID = meta1.post_id)
    LEFT JOIN $wpdb->posts venues ON (venues.post_status = 'publish' AND venues.post_type = 'venue' AND venues.ID = meta1.meta_value)
    WHERE 1
    AND campaigns.post_status = 'publish'
    AND campaigns.post_type = 'campaign'
    LIMIT 1
    ";

    echo "<pre>$query</pre>";

    $posts = $wpdb->get_results($query, OBJECT);

    echo "<pre>";
    print_r($posts);
    echo "</pre>";
}

输出:

SELECT
    `campaigns`.`ID` AS `campaigns.ID`, `campaigns`.`post_author` AS `campaigns.post_author`, `campaigns`.`post_date` AS `campaigns.post_date`, `campaigns`.`post_date_gmt` AS `campaigns.post_date_gmt`, `campaigns`.`post_content` AS `campaigns.post_content`, `campaigns`.`post_title` AS `campaigns.post_title`, `campaigns`.`post_excerpt` AS `campaigns.post_excerpt`, `campaigns`.`post_status` AS `campaigns.post_status`, `campaigns`.`comment_status` AS `campaigns.comment_status`, `campaigns`.`ping_status` AS `campaigns.ping_status`, `campaigns`.`post_password` AS `campaigns.post_password`, `campaigns`.`post_name` AS `campaigns.post_name`, `campaigns`.`to_ping` AS `campaigns.to_ping`, `campaigns`.`pinged` AS `campaigns.pinged`, `campaigns`.`post_modified` AS `campaigns.post_modified`, `campaigns`.`post_modified_gmt` AS `campaigns.post_modified_gmt`, `campaigns`.`post_content_filtered` AS `campaigns.post_content_filtered`, `campaigns`.`post_parent` AS `campaigns.post_parent`, `campaigns`.`guid` AS `campaigns.guid`, `campaigns`.`menu_order` AS `campaigns.menu_order`, `campaigns`.`post_type` AS `campaigns.post_type`, `campaigns`.`post_mime_type` AS `campaigns.post_mime_type`, `campaigns`.`comment_count` AS `campaigns.comment_count`,
    `venues`.`ID` AS `venues.ID`, `venues`.`post_author` AS `venues.post_author`, `venues`.`post_date` AS `venues.post_date`, `venues`.`post_date_gmt` AS `venues.post_date_gmt`, `venues`.`post_content` AS `venues.post_content`, `venues`.`post_title` AS `venues.post_title`, `venues`.`post_excerpt` AS `venues.post_excerpt`, `venues`.`post_status` AS `venues.post_status`, `venues`.`comment_status` AS `venues.comment_status`, `venues`.`ping_status` AS `venues.ping_status`, `venues`.`post_password` AS `venues.post_password`, `venues`.`post_name` AS `venues.post_name`, `venues`.`to_ping` AS `venues.to_ping`, `venues`.`pinged` AS `venues.pinged`, `venues`.`post_modified` AS `venues.post_modified`, `venues`.`post_modified_gmt` AS `venues.post_modified_gmt`, `venues`.`post_content_filtered` AS `venues.post_content_filtered`, `venues`.`post_parent` AS `venues.post_parent`, `venues`.`guid` AS `venues.guid`, `venues`.`menu_order` AS `venues.menu_order`, `venues`.`post_type` AS `venues.post_type`, `venues`.`post_mime_type` AS `venues.post_mime_type`, `venues`.`comment_count` AS `venues.comment_count`
    FROM wp_posts AS campaigns
LEFT JOIN wp_postmeta meta1 ON (meta1.meta_key = 'venue' AND campaigns.ID = meta1.post_id)
LEFT JOIN wp_posts venues ON (venues.post_status = 'publish' AND venues.post_type = 'venue' AND venues.ID = meta1.meta_value)
WHERE 1
AND campaigns.post_status = 'publish'
AND campaigns.post_type = 'campaign'
LIMIT 1

Array
(
    [0] => stdClass Object
        (
            [campaigns.ID] => 33
            [campaigns.post_author] => 2
            [campaigns.post_date] => 2012-01-16 19:19:10
            [campaigns.post_date_gmt] => 2012-01-16 19:19:10
            [campaigns.post_content] => Lorem ipsum
            [campaigns.post_title] => Lorem ipsum
            [campaigns.post_excerpt] => 
            [campaigns.post_status] => publish
            [campaigns.comment_status] => closed
            [campaigns.ping_status] => closed
            [campaigns.post_password] => 
            [campaigns.post_name] => lorem-ipsum
            [campaigns.to_ping] => 
            [campaigns.pinged] => 
            [campaigns.post_modified] => 2012-01-16 21:01:55
            [campaigns.post_modified_gmt] => 2012-01-16 21:01:55
            [campaigns.post_content_filtered] => 
            [campaigns.post_parent] => 0
            [campaigns.guid] => http://example.com/?p=33
            [campaigns.menu_order] => 0
            [campaigns.post_type] => campaign
            [campaigns.post_mime_type] => 
            [campaigns.comment_count] => 0
            [venues.ID] => 84
            [venues.post_author] => 2
            [venues.post_date] => 2012-01-16 20:12:05
            [venues.post_date_gmt] => 2012-01-16 20:12:05
            [venues.post_content] => Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
            [venues.post_title] => Lorem ipsum venue
            [venues.post_excerpt] => 
            [venues.post_status] => publish
            [venues.comment_status] => closed
            [venues.ping_status] => closed
            [venues.post_password] => 
            [venues.post_name] => lorem-ipsum-venue
            [venues.to_ping] => 
            [venues.pinged] => 
            [venues.post_modified] => 2012-01-16 20:53:37
            [venues.post_modified_gmt] => 2012-01-16 20:53:37
            [venues.post_content_filtered] => 
            [venues.post_parent] => 0
            [venues.guid] => http://example.com/?p=84
            [venues.menu_order] => 0
            [venues.post_type] => venue
            [venues.post_mime_type] => 
            [venues.comment_count] => 0
        )
)

【讨论】:

  • 这篇文章有点老了,但函数方法绝对优雅且运行良好。
【解决方案4】:

我知道的唯一数据库是 SQLite,这取决于您使用 PRAGMA full_column_namesPRAGMA short_column_names 配置的设置。见http://www.sqlite.org/pragma.html

否则,如果在查询中键入列名太麻烦的话,我只能建议按序号位置而不是按列名获取结果集中的列。

这是为什么it's bad practice to use SELECT * 的一个很好的例子——因为最终你还是需要输入所有的列名。

我了解支持可能更改名称或位置的列的必要性,但使用通配符会使这更难,而不是更容易。

【讨论】:

  • 请注意,full_column_namesshort_column_names 在 SQLite 中都是 deprecated
【解决方案5】:

这个问题在实践中非常有用。只需要列出软件编程中的每一个显式列,您需要特别小心地处理所有条件。

试想在调试时,或者,尝试使用 DBMS 作为日常办公工具,而不是特定程序员抽象底层基础设施的可更改实现,我们需要编写大量 SQL 代码。这种场景随处可见,如数据库转换、迁移、管理等。这些 SQL 中的大多数只会执行一次,永远不会再次使用,给每一列命名只是浪费时间。并且不要忘记 SQL 的发明不仅仅是供程序员使用的。

通常我会创建一个带有列名前缀的实用程序视图,这是pl/pgsql中的函数,这并不容易,但你可以将它转换为其他过程语言。

-- Create alias-view for specific table.

create or replace function mkaview(schema varchar, tab varchar, prefix varchar)
    returns table(orig varchar, alias varchar) as $$
declare
    qtab varchar;
    qview varchar;
    qcol varchar;
    qacol varchar;
    v record;
    sql varchar;
    len int;
begin
    qtab := '"' || schema || '"."' || tab || '"';
    qview := '"' || schema || '"."av' || prefix || tab || '"';
    sql := 'create view ' || qview || ' as select';

    for v in select * from information_schema.columns
            where table_schema = schema and table_name = tab
    loop
        qcol := '"' || v.column_name || '"';
        qacol := '"' || prefix || v.column_name || '"';

        sql := sql || ' ' || qcol || ' as ' || qacol;
        sql := sql || ', ';

        return query select qcol::varchar, qacol::varchar;
    end loop;

    len := length(sql);
    sql := left(sql, len - 2); -- trim the trailing ', '.
    sql := sql || ' from ' || qtab;

    raise info 'Execute SQL: %', sql;
    execute sql;
end
$$ language plpgsql;

例子:

-- This will create a view "avp_person" with "p_" prefix to all column names.
select * from mkaview('public', 'person', 'p_');

select * from avp_person;

【讨论】:

    【解决方案6】:

    我与 OP 处于同一条船上 - 我有来自我要加入的 3 个不同表的数十个字段,其中一些具有相同的名称(即 id、名称等)。我不想列出每个字段,因此我的解决方案是为共享名称的字段设置别名,并对具有唯一名称的字段使用 select *。

    例如:

    表一: ID, 姓名, 字段1, 字段2 ...

    表 b: ID, 姓名, 字段3, 字段4 ...

    选择 a.id 作为 aID,a.name 作为 aName,a. * , b.id 作为 bID, b.name 作为 bName, b. * .....

    访问结果时,我使用这些字段的别名并忽略“原始”名称。

    也许不是最好的解决方案,但它对我有用....我正在使用 mysql

    【讨论】:

      【解决方案7】:

      不同的数据库产品会给你不同的答案;但是如果你把这件事走得太远,你就会让自己受到伤害。你最好选择你想要的列,并给他们自己的别名,这样每列的身份就很清楚了,你可以在结果中区分它们。

      【讨论】:

      • 点了,但我的目标是非常通用的,所以不明确不是问题。事实上,必须具体是个问题。
      • 请参阅下面的进一步提交。可以使用 use dot.notation,这可能是您默认的?
      • 可读性很重要。我希望现在就这样做,因为我有一个相关的 CTE 流程。前任。 CTE_A -> CTE_B -> CTE_C -> CTE_D -> select/insert 在最终的 select 语句之前不需要指定我想要的列并且性能不是考虑因素。
      【解决方案8】:

      我完全理解您关于重复字段名称的问题。

      在我编写自己的函数来解决它之前,我也需要它。如果您使用的是 PHP,则可以使用它,或者如果您有以下功能,则可以使用您正在使用的语言编写代码。

      这里的技巧是mysql_field_table() 返回表名,mysql_field_name() 返回结果中每一行的字段,如果它与mysql_num_fields() 一起获得,那么您可以将它们混合在一个新数组中。

      这为所有列添加前缀;)

      问候,

      function mysql_rows_with_columns($query) {
          $result = mysql_query($query);
          if (!$result) return false; // mysql_error() could be used outside
          $fields = mysql_num_fields($result);
          $rows = array();
          while ($row = mysql_fetch_row($result)) { 
              $newRow = array();
              for ($i=0; $i<$fields; $i++) {
                  $table = mysql_field_table($result, $i);
                  $name = mysql_field_name($result, $i);
                  $newRow[$table . "." . $name] = $row[$i];
              }
              $rows[] = $newRow;
          }
          mysql_free_result($result);
          return $rows;
      }
      

      【讨论】:

        【解决方案9】:

        在 postgres 中,我使用 json 函数来代替返回 json 对象.... 然后,在查询之后,我对带有 _json 后缀的字段进行 json_decode。

        IE:

        select row_to_json(tab1.*),tab1_json, row_to_json(tab2.*) tab2_json 
         from tab1
         join tab2 on tab2.t1id=tab1.id
        

        然后在 PHP(或任何其他语言)中,如果它们具有“_json”后缀(也删除后缀),我会遍历返回的列和 json_decode() 它们。最后,我得到一个名为“tab1”的对象包括所有 tab1 字段,另一个称为“tab2”,包括所有 tab2 字段。

        【讨论】:

          【解决方案10】:

          没有这方面的 SQL 标准。

          但是,通过代码生成(在创建或更改表时按需或在运行时),您可以很容易地做到这一点:

          CREATE TABLE [dbo].[stackoverflow_329931_a](
              [id] [int] IDENTITY(1,1) NOT NULL,
              [col2] [nchar](10) NULL,
              [col3] [nchar](10) NULL,
              [col4] [nchar](10) NULL,
           CONSTRAINT [PK_stackoverflow_329931_a] PRIMARY KEY CLUSTERED 
          (
              [id] ASC
          )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
          ) ON [PRIMARY]
          
          CREATE TABLE [dbo].[stackoverflow_329931_b](
              [id] [int] IDENTITY(1,1) NOT NULL,
              [col2] [nchar](10) NULL,
              [col3] [nchar](10) NULL,
              [col4] [nchar](10) NULL,
           CONSTRAINT [PK_stackoverflow_329931_b] PRIMARY KEY CLUSTERED 
          (
              [id] ASC
          )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
          ) ON [PRIMARY]
          
          DECLARE @table1_name AS varchar(255)
          DECLARE @table1_prefix AS varchar(255)
          DECLARE @table2_name AS varchar(255)
          DECLARE @table2_prefix AS varchar(255)
          DECLARE @join_condition AS varchar(255)
          SET @table1_name = 'stackoverflow_329931_a'
          SET @table1_prefix = 'a_'
          SET @table2_name = 'stackoverflow_329931_b'
          SET @table2_prefix = 'b_'
          SET @join_condition = 'a.[id] = b.[id]'
          
          DECLARE @CRLF AS varchar(2)
          SET @CRLF = CHAR(13) + CHAR(10)
          
          DECLARE @a_columnlist AS varchar(MAX)
          DECLARE @b_columnlist AS varchar(MAX)
          DECLARE @sql AS varchar(MAX)
          
          SELECT @a_columnlist = COALESCE(@a_columnlist + @CRLF + ',', '') + 'a.[' + COLUMN_NAME + '] AS [' + @table1_prefix + COLUMN_NAME + ']'
          FROM INFORMATION_SCHEMA.COLUMNS
          WHERE TABLE_NAME = @table1_name
          ORDER BY ORDINAL_POSITION
          
          SELECT @b_columnlist = COALESCE(@b_columnlist + @CRLF + ',', '') + 'b.[' + COLUMN_NAME + '] AS [' + @table2_prefix + COLUMN_NAME + ']'
          FROM INFORMATION_SCHEMA.COLUMNS
          WHERE TABLE_NAME = @table2_name
          ORDER BY ORDINAL_POSITION
          
          SET @sql = 'SELECT ' + @a_columnlist + '
          ,' + @b_columnlist + '
          FROM [' + @table1_name + '] AS a
          INNER JOIN [' + @table2_name + '] AS b
          ON (' + @join_condition + ')'
          
          PRINT @sql
          -- EXEC (@sql)
          

          【讨论】:

          • 这可行,但这个问题相当愚蠢。为什么不只执行联合或子查询。为什么要加入并仍然希望在列名中添加表前缀?
          • 凯德:感谢您提供的信息,这很有趣。不幸的是,在我的情况下,生成/更改数据库不是一个选项。 Devtron:如果您尝试将查询返回的信息映射到对象的不同属性,则该信息将非常有用。
          • 有时不同表中的列名相同,但不包含相同的值。因此需要为它们添加前缀以在视图或派生表中区分它们(必须具有所有唯一的列名)。
          • @Frederic,您的代码必须存在于某个地方 - 这只是生成代码。同样,这可以在开发期间完成一次,也可以在运行时动态完成。
          【解决方案11】:

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

          所以在你的情况下,如果你输入 SELECT * FROM A JOIN B ... 转到 * 的末尾,Tab 按钮,瞧!你会看到的 SELECT A.column1, A.column2, .... , B.column1, B.column2 FROM A JOIN B

          虽然不是免费的

          【讨论】:

            【解决方案12】:

            我通过重命名相关表中的字段解决了我的类似问题。是的,我有幸这样做,并且了解每个人可能都没有这样做。我为代表表名的表中的每个字段添加了前缀。因此,OP 发布的 SQL 将保持不变 -

            SELECT a.*, b.* FROM TABLE_A a JOIN TABLE_B b USING (some_id);
            

            并且仍然给出预期的结果 - 易于识别输出字段属于哪个表。

            【讨论】:

              【解决方案13】:

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

              【讨论】:

              • 不可能!这是一些 hacky SQL 注入,不适用于表达式。
              【解决方案14】:

              select * 通常会产生糟糕的代码,因为往往会添加新列或表中的列顺序非常频繁地更改,这通常会以非常微妙的方式破坏 select *。所以列出列是正确的解决方案。

              至于如何进行查询,不确定 mysql 但在 sqlserver 中,您可以从 syscolumns 中选择列名并动态构建 select 子句。

              【讨论】:

              • 点了,但在我的上下文中,我需要一些通用和动态的东西,所以实际上我的代码将适应添加/重新排序/等的新列。我不想单独列出列。
              • 从 syscolumns 中选择动态构建 select 语句是一种可怕的 hack,我不建议在生产环境中使用它。
              【解决方案15】:

              有两种方法可以让我以可重用的方式实现这一目标。一种是使用它们来自的表的前缀重命名所有列。我已经看过很多次了,但我真的不喜欢它。我发现它是多余的,会导致大量输入,并且当您需要涵盖来源不明的列名的情况时,您始终可以使用别名。

              如果您致力于解决这个问题,我建议您根据自己的情况采取另一种方法,即为每个表创建视图,为表名取别名。然后你加入这些视图,而不是表。这样一来,您可以随意使用 *,如果您愿意,可以随意使用具有原始列名的原始表,并且还可以更轻松地编写任何后续查询,因为您已经在视图中完成了重命名工作。

              最后,我不清楚为什么您需要知道每列来自哪个表。这有关系吗?最终重要的是它们包含的数据。 UserID 是来自 User 表还是来自 UserQuestion 表并不重要。当然,当您需要更新它时,它很重要,但此时您应该已经足够了解您的架构来确定这一点。

              【讨论】:

              • “最后,我不清楚你为什么需要知道每一列来自哪个表。这有关系吗?”
              【解决方案16】:

              如果担心架构更改,这可能对您有用: 1. 对所有涉及的表运行“DESCRIBE table”查询。 2. 使用返回的字段名动态构造一串以您选择的别名为前缀的列名。

              【讨论】:

                【解决方案17】:

                对于那些使用 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 */
                

                注意以下字段:目录、表格、组织名称

                您现在知道 SQL 中的哪些字段属于哪个架构(也称为目录)和表。 这足以从多表 sql 查询中通用地识别每个字段,而无需别名。

                一个实际的产品 SqlYOG 被展示为在这样一个庄园中使用这个确切的数据,以至于当 PK 字段存在时,他们能够独立更新多表连接的每个表。

                【讨论】:

                  【解决方案18】:

                  不能在没有别名的情况下做到这一点,仅仅是因为,如果该字段存在于您要加入的 2 或 3 个表中,您将如何引用 where 子句中的字段? mysql 不清楚您要引用哪一个。

                  【讨论】:

                    【解决方案19】:

                    this solution 开发,这就是我解决问题的方式:

                    首先创建一个包含所有AS 语句的列表:

                    DECLARE @asStatements varchar(8000)
                    
                    SELECT @asStatements = ISNULL(@asStatements + ', ','') + QUOTENAME(table_name) + '.' + QUOTENAME(column_name) + ' AS ' + '[' + table_name + '.' + column_name + ']'
                    FROM INFORMATION_SCHEMA.COLUMNS
                    WHERE TABLE_NAME = 'TABLE_A' OR TABLE_NAME = 'TABLE_B'
                    ORDER BY ORDINAL_POSITION
                    

                    然后在您的查询中使用它:

                    EXEC('SELECT ' + @asStatements + ' FROM TABLE_A a JOIN TABLE_B b USING (some_id)');
                    

                    但是,这可能需要修改,因为类似的东西只在 SQL Server 中进行了测试。但此代码在 SQL Server 中并不完全适用,因为不支持 USING。

                    如果您可以测试/更正此代码,请发表评论,例如MySQL。

                    【讨论】:

                      【解决方案20】:

                      PHP 7.2 + MySQL/Mariadb

                      MySQL 将向您发送多个具有相同名称的字段。即使在终端客户端。但是如果你想要一个关联数组,你必须自己制作键。

                      感谢@axelbrz 的原创。我已将其移植到较新的 php 并对其进行了一些清理:

                      function mysqli_rows_with_columns($link, $query) {
                          $result = mysqli_query($link, $query);
                          if (!$result) {
                              return mysqli_error($link);
                          }
                          $field_count = mysqli_num_fields($result);
                          $fields = array();
                          for ($i = 0; $i < $field_count; $i++) {
                              $field = mysqli_fetch_field_direct($result, $i);
                              $fields[] = $field->table . '.' . $field->name; # changed by AS
                              #$fields[] = $field->orgtable . '.' . $field->orgname; # actual table/field names
                          }
                          $rows = array();
                          while ($row = mysqli_fetch_row($result)) {
                              $new_row = array();
                              for ($i = 0; $i < $field_count; $i++) {
                                  $new_row[$fields[$i]] = $row[$i];
                              }
                              $rows[] = $new_row;
                          }
                          mysqli_free_result($result);
                          return $rows;
                      }
                      
                      $link = mysqli_connect('localhost', 'fixme', 'fixme', 'fixme');
                      print_r(mysqli_rows_with_columns($link, 'select foo.*, bar.* from foo, bar'));
                      

                      【讨论】:

                        【解决方案21】:

                        我在 node.js 中实现了一个基于the answer suggesting using dummy or sentinel columns 的解决方案。您可以通过生成如下 SQL 来使用它:

                        select 
                            s.*
                          , '' as _prefix__creator_
                          , u.*
                          , '' as _prefix__speaker_
                          , p.*
                        from statements s 
                          left join users u on s.creator_user_id = u.user_id
                          left join persons p on s.speaker_person_id = p.person_id
                        

                        然后对从数据库驱动程序返回的行进行后处理,例如 addPrefixes(row)

                        实现(基于我的驱动程序返回的fields/rows,但对于其他数据库驱动程序应该很容易更改):

                        const PREFIX_INDICATOR = '_prefix__'
                        const STOP_PREFIX_INDICATOR = '_stop_prefix'
                        
                        /** Adds a <prefix> to all properties that follow a property with the name: PREFIX_INDICATOR<prefix> */
                        function addPrefixes(fields, row) {
                          let prefix = null
                          for (const field of fields) {
                            const key = field.name
                            if (key.startsWith(PREFIX_INDICATOR)) {
                              if (row[key] !== '') {
                                throw new Error(`PREFIX_INDICATOR ${PREFIX_INDICATOR} must not appear with a value, but had value: ${row[key]}`)
                              }
                              prefix = key.substr(PREFIX_INDICATOR.length)
                              delete row[key]
                            } else if (key === STOP_PREFIX_INDICATOR) {
                              if (row[key] !== '') {
                                throw new Error(`STOP_PREFIX_INDICATOR ${STOP_PREFIX_INDICATOR} must not appear with a value, but had value: ${row[key]}`)
                              }
                              prefix = null
                              delete row[key]
                            } else if (prefix) {
                              const prefixedKey = prefix + key
                              row[prefixedKey] = row[key]
                              delete row[key]
                            }
                          }
                          return row
                        }
                        

                        测试:

                        const {
                          addPrefixes,
                          PREFIX_INDICATOR,
                          STOP_PREFIX_INDICATOR,
                        } = require('./BaseDao')
                        
                        describe('addPrefixes', () => {
                          test('adds prefixes', () => {
                            const fields = [
                              {name: 'id'},
                              {name: PREFIX_INDICATOR + 'my_prefix_'},
                              {name: 'foo'},
                              {name: STOP_PREFIX_INDICATOR},
                              {name: 'baz'},
                            ]
                            const row = {
                              id: 1,
                              [PREFIX_INDICATOR + 'my_prefix_']: '',
                              foo: 'bar',
                              [STOP_PREFIX_INDICATOR]: '',
                              baz: 'spaz'
                            }
                            const expected = {
                              id: 1,
                              my_prefix_foo: 'bar',
                              baz: 'spaz',
                            }
                            expect(addPrefixes(fields, row)).toEqual(expected)
                          })
                        })
                        

                        【讨论】:

                          【解决方案22】:

                          我所做的是使用 Excel 来连接过程。例如,首先我选择 * 并获取所有列,将它们粘贴到 Excel 中。然后写出我需要围绕该列的代码。假设我需要在一堆列中添加 prev。我将我的字段放在 a 列中,将“as prev_”放在 B 列中,并将我的字段再次放在 c 列中。在 d 列中,我将有一列。

                          然后在 e 列中使用 concatenate 并将它们合并在一起,确保包含空格。然后将其剪切并粘贴到您的 sql 代码中。我还使用这种方法为同一个字段和其他更长的代码制作案例陈述,我需要为数百个字段表中的每个字段做。

                          【讨论】:

                            【解决方案23】:

                            这将创建具有给定前缀的字段列表

                            select
                                name + ' as prefix.' + name + ','
                            from sys.columns where object_id = object_id('mytable')
                            order by column_id
                            

                            【讨论】:

                              【解决方案24】:

                              我在 PostgreSQL 13 中使用 to_jsonb 函数将 joined 表中的所有字段作为单个列。

                              select
                                TABLE_A.*,
                                to_jsonb(TABLE_B.*) as b,
                                to_jsonb(TABLE_C.*) as c
                              from TABLE_A
                              left join TABLE_B on TABLE_B.a_id=TABLE_A.id
                              left join TABLE_C on TABLE_C.a_id=TABLE_A.id
                              where TABLE_A.id=1
                              

                              因此,您将获得 TABLE_A 列的数量加上 b 和 c 列:

                              id name some_other_col b c
                              1 Some name Some other value {"id":1,"a_id":1,"prop":"value"} {"id":1,"a_id":1,"prop":"value"}
                              1 Some other name Another value {"id":1,"a_id":1,"prop":"value"} {"id":1,"a_id":1,"prop":"value"}

                              您只需要解析 b 和 c 列即可将它们转换为对象。

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2010-12-22
                                • 1970-01-01
                                • 2021-05-14
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多