SQL select连接:是否可以将所有列都前缀为'prefix。*'?


206

我想知道在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','名称','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 *的建议是有效的建议,但在我的上下文中不相关,因此请坚持手头的问题-是否可以为所有连接中表的列名称?

编辑:我的最终目标是能够通过联接在两个表上执行SELECT *,并能够从我在结果集中获得的列名称中分辨出哪些列来自表A,哪些列来自同样,我也不想单独列出各列,我需要能够执行SELECT *。


您究竟希望查询的结果是什么?我很困惑
GregD

GregD:我希望所有来自b。*的列名都以我指定的常量作为前缀。例如,我要指定“ special_”前缀而不是“ name”和“ number”,并获取“ special_name”和“ special_number”。但是我不想对每个列都单独执行此操作。
foxdonut

6
当我执行快速SELECT来查看多个表中的列时,有时我会从TableA中将SELECT AAA *,A。*,'BBBBB',B。*从A.ID = B.ID联接为TableB ASB。沿行扫描时至少要有一个表标识符
Kristen

Answers:


35

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


11
我不确定这如何回答您的问题。我正在使用MS SQL Server,并在表名称未将别名附加到结果集中的列名称之后添加别名。
paiego,2015年

74

看来您问题的答案是否定的,但是您可以使用的一种技巧是分配一个虚拟列来分隔每个新表。如果要遍历结果集以使用脚本语言(例如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

我意识到这不能完全回答您的问题,但是如果您是编码人员,这是一种使用重复的列名分隔表的好方法。希望这对某人有帮助。


24

我完全理解为什么这样做是必要的-至少对我来说,在有许多需要联接的表(包括许多内部联接)的快速原型制作过程中,它很方便。一旦第二个“ joinedtable。*”字段通配符中的列名相同,主表的字段值就会被jointabletable值覆盖。当必须手动重复使用别名重复指定表字段时,容易出错,令人沮丧并且违反了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
        )
)

13

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

否则,我所建议的就是按顺序位置而不是按列名来获取结果集中的列,如果您在查询中键入列名太麻烦了。

这是一个使用不良做法SELECT *的好例子-因为最终您仍然需要输入所有列名称。

我知道需要支持可能会更改名称或位置的列,但是使用通配符会使难度加大,而不是容易。


2
请注意,在SQLite中,full_column_namesshort_column_names均已弃用
isanae '16

6

我和OP是同一个船-我要加入的3个不同表中有数十个字段,其中一些具有相同的名称(即id,name等)。我不想列出每个字段,所以我的解决方案是为那些共享名称的字段添加别名,并对具有唯一名称的字段使用select *。

例如 :

表a:id,名称,field1,field2 ...

表b:id,名称,field3,field4 ...

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

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

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


5

不同的数据库产品会给您不同的答案;但是如果您走得太远,就会伤到自己。您最好选择所需的列,并给它们提供自己的别名,这样每一列的标识都非常清晰,并且可以在结果中区分开它们。


1
采取了观点,但是我的目标是非常通用的,因此不露骨不是问题。其实,不必具体是一个问题。
foxdonut

请参阅下面的进一步提交。可以使用dot.notation,这可能是默认设置?
dkretz

这对于可读性很重要。我希望现在就执行此操作,因为我拥有完善的CTE流程。例如 CTE_A-> CTE_B-> CTE_C-> CTE_D-> select / insert在不需要考虑最终的select语句和性能之前,无需指定我想要的列。
ThomasRones

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;

3

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

在我编写自己的函数来解决该问题之前,我也需要这样做。如果您使用的是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;
}

2

对此没有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)

这会起作用,但问题相当愚蠢。为什么不只是执行并集或子查询。您为什么要加入并且仍然希望在列名中使用表前缀?
D3vtr0n

卡德:感谢您提供的信息,这很有趣。不幸的是,就我而言,生成/更改数据库不是一种选择。Devtron:如果您尝试将查询返回的信息映射到对象的不同属性,则该信息将非常有用。
foxdonut

1
有时,不同表中的列名相同,但不包含相同的值。因此,需要给它们加上前缀以在视图或派生表(必须具有所有唯一的列名称)中区分它们。
卡德·鲁

@Frederic,您的代码必须放在某个地方-这只会生成代码。同样,这可以在开发过程中一次完成,也可以在运行时动态完成。
卡德·鲁

1

我可以想到两种方法来实现可重用的实现。一种方法是使用其来源表的前缀重命名所有列。我已经看过很多次了,但是我真的不喜欢它。我发现它是多余的,会导致大量输入,并且当需要解决列名来源不明确的情况时,可以随时使用别名。

如果您决心通过这种方式,我建议您根据自己的情况采取另一种方式,就是为每个表创建以表名作为别名的视图。然后,您针对这些视图而不是表进行联接。这样,您可以随意使用*,如果愿意的话可以随意使用带有原始列名的原始表,而且由于您已经在视图中完成了重命名工作,因此也使编写后续查询变得更加容易。

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


“最后,我不清楚为什么您需要知道每一列来自哪个表。这有关系吗?” <-11年后,一个用例是Go中的结构扫描。
李本森

1

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

因此,根据您的情况,如果您输入SELECT * FROM A JOIN B ...转到*的末尾,Tab按钮,瞧!您会从一个JOIN B中看到SELECT A.column1,A.column2,....,B.column1,B.column2

它不是免费的


1

不能做到这一点而不会产生别名,这仅仅是因为,如果要连接的2或3个表中存在该字段,那么您将如何在where子句中引用该字段?对于mysql,您将要引用的是哪一个尚不清楚。


1

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

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

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


0

select *通常会导致错误的代码,因为新的列倾向于添加或表中列的顺序更改非常频繁,这通常会以非常微妙的方式破坏select *。因此列出列是正确的解决方案。

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


以观点为准,但是在我的上下文中,我需要通用和动态的东西,因此实际上我的代码将适应要添加/重新排序的新列。我不想单独列出各列。
foxdonut

5
从syscolumns中进行选择以动态生成select语句是一个可怕的技巧,我不建议在生产中使用它。
朱丽叶

0

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


0

对于使用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字段时,它们能够独立更新多表联接的每个表。


0

这个解决方案开发,这就是我要解决的问题:

首先创建所有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),请发表评论。


0

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

没门!那是一些骇人听闻的SQL注入,不适用于表达式。
ratijas

0

我根据建议在节点中使用虚拟列或前哨列的答案实施了一个解决方案。您可以通过生成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)
  })
})

0

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

然后在e列中使用concatenate,并将它们合并在一起,确保包含空格。然后剪切并粘贴到您的sql代码中。我还使用了这种方法来为同一字段以及多个字段表中的每个字段需要做的其他较长代码编写case语句。


0

在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字段。


-1

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'));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.