SQL select join: возможно ли префикс всех столбцов как "префикс. *"?

Мне интересно, возможно ли это в 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. * с" чем-то ". Это возможно или мне не повезло?

Заранее благодарим за помощь!

EDIT: советы по использованию SELECT * и т.д. являются действительными советами, но не релевантными в моем контексте, поэтому, пожалуйста, придерживайтесь этой проблемы: возможно ли добавить префикс (константу, указанную в SQL-запросе) ко всем именам столбцов таблицы в соединении?

EDIT: моя конечная цель состоит в том, чтобы иметь возможность делать SELECT * на двух таблицах с объединением и быть в состоянии сказать, из имен столбцов, которые я получаю в своем результирующем наборе, какие столбцы поступают из таблицы A и какие столбцы пришли из таблицы B. Опять же, я не хочу, чтобы список столбцов был индивидуальным, мне нужно иметь возможность делать SELECT *.

Ответ 1

Здесь я вижу две возможные ситуации. Во-первых, вы хотите знать, есть ли для этого стандарт SQL, который вы можете использовать вообще независимо от базы данных. Нет, нет. Во-вторых, вы хотите знать, что касается конкретного продукта dbms. Затем вам нужно определить его. Но я предполагаю, что наиболее вероятным ответом является то, что вы получите что-то вроде "a.id, b.id", так как вам нужно будет идентифицировать столбцы в выражении SQL. И самый простой способ узнать, что такое по умолчанию, - это просто отправить такой запрос и посмотреть, что вы вернетесь. Если вы хотите указать, какой префикс подходит до точки, вы можете использовать, например, "SELECT * FROM a AS my_alias".

Ответ 2

Кажется, ответ на ваш вопрос - нет, однако один взлом, который вы можете использовать, - это назначить фиктивный столбец для разделения каждой новой таблицы. Это особенно хорошо работает, если вы перебираете результирующий набор для списка столбцов на языке сценариев, таких как 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

Я понимаю, что это точно не отвечает на ваш вопрос, но если вы кодер, это отличный способ разделить таблицы с дублирующимися именами столбцов. Надеюсь, это поможет кому-то.

Ответ 3

Я полностью понимаю, почему это необходимо - по крайней мере для меня это удобно во время быстрого прототипирования, когда есть много столов, которые необходимо объединить, включая многие внутренние соединения. Как только имя столбца совпадает со вторым полем "объединенная таблица. *", Значения основного поля таблицы переопределяются вместе с объединенными значениями. Ошибка, подверженная ошибкам, нарушение и нарушение 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_names и PRAGMA short_column_names. См. http://www.sqlite.org/pragma.html

В противном случае все, что я могу порекомендовать, - это получить столбцы в результирующем наборе по порядковой позиции, а не по имени столбца, если вам слишком сложно набрать имена столбцов в вашем запросе.

Это хороший пример того, почему это плохая практика использовать SELECT * - потому что в конце концов вам будет нужно набирать все имена столбцов в любом случае.

Я понимаю необходимость поддержки столбцов, которые могут изменять имя или позицию, но использование подстановочных знаков делает это сложнее, а не проще.

Ответ 5

Продукты базы данных DIfferent предоставят вам разные ответы; но вы настраиваете себя навредить, если несете это очень далеко. Вы намного лучше выбираете нужные столбцы и даете им свои собственные псевдонимы, чтобы идентичность каждого столбца была кристально чистой, и вы можете отличить их в результатах.

Ответ 6

Я нахожусь в той же лодке, что и OP. У меня есть десятки полей из трех разных таблиц, к которым я присоединяюсь, некоторые из которых имеют одинаковое имя (например, id, имя и т.д.). Я не хочу перечислять каждое поле, поэтому мое решение состояло в том, чтобы слить те поля, которые поделились именем, и использовать select * для тех, у которых есть уникальное имя.

Например:

таблица a: Я бы, имя, field1, field2...

таблица b: Я бы, имя, field3, поле4...

выберите a.id как aID, a.name как aName, a. *, b.id как bID, b.name как bName, b. *.....

При обращении к результатам я получаю псевдонимы для этих полей и игнорирую "оригинальные" имена.

Возможно, это не лучшее решение, но оно работает для меня.... Я использую mysql

Ответ 7

Этот вопрос очень полезен на практике. Необходимо только перечислять все явные столбцы в программном обеспечении, где вы уделяете особое внимание всем условиям.

Представьте себе, когда вы отлаживаете или пытаетесь использовать СУБД как ежедневный офисный инструмент, вместо того, чтобы что-то изменить реализацию абстрактной базовой инфраструктуры конкретного программиста, нам нужно закодировать много 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;

Ответ 8

Для этого нет стандарта 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)

Ответ 9

Я полностью понимаю вашу проблему с дублированными именами полей.

Мне тоже было нужно, пока я не закодировал свою собственную функцию, чтобы решить эту проблему. Если вы используете 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;
}

Ответ 10

Или вы можете использовать Red Gate SQL Refactor или SQL Prompt, который расширяет ваш SELECT * в списки столбцов одним нажатием кнопки Tab

поэтому в вашем случае, если вы наберете SELECT * FROM A JOIN B... Идите в конец *, Tab, voila! вот увидишь SELECT A.column1, A.column2,...., B.column1, B.column2 FROM A JOIN B

Это не бесплатно, хотя

Ответ 11

Не могу сделать это без наложения псевдонимов, просто потому, что как вы собираетесь ссылаться на поле в предложении where, если это поле существует в 2 или 3 таблицах, к которым вы присоединяетесь? Будет непонятно, для mysql, который вы пытаетесь сделать ссылкой.

Ответ 12

Я решил аналогичную проблему, переименовав поля в соответствующих таблицах. Да, я имел честь сделать это и понять, что у всех это может не быть. Я добавил префикс для каждого поля в таблице, представляющей имя таблицы. Таким образом, SQL, отправленный OP, останется неизменным -

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

и все еще дают ожидаемые результаты - легкость определения таблицы, к которой принадлежат выходные поля.

Ответ 13

Есть два способа, которые я могу придумать, чтобы это произошло в многоразовом режиме. Один из них - переименование всех ваших столбцов с префиксом для таблицы, из которой они пришли. Я видел это много раз, но мне это действительно не нравится. Я считаю, что он избыточен, вызывает много ввода, и вы всегда можете использовать псевдонимы, когда вам нужно покрыть случай с именем столбца, имеющим неясное происхождение.

Другим способом, который я бы рекомендовал вам сделать в вашей ситуации, если вы намерены это увидеть, заключается в создании представлений для каждой таблицы, которая имеет псевдоним имен таблиц. Затем вы присоединяетесь к этим представлениям, а не к таблицам. Таким образом, вы можете свободно использовать *, если хотите, свободно использовать исходные таблицы с именами исходных столбцов, если хотите, а также упростить запись любых последующих запросов, поскольку вы уже выполнили работу по переименованию в представлениях.

Наконец, я не понимаю, почему вам нужно знать, из какой таблицы из столбца. Это имеет значение? В конечном итоге важны данные, которые они содержат. Независимо от того, пришел ли UserID из таблицы User или таблицы UserQuestion, это не имеет значения. Это важно, конечно, когда вам нужно обновить его, но в этот момент вы уже должны знать свою схему достаточно хорошо, чтобы определить это.

Ответ 14

Если вас беспокоят изменения схемы, это может сработать для вас:  1. Запустите запрос "DESCRIBE table" во всех задействованных таблицах.  2. Используйте имена возвращаемых полей, чтобы динамически построить строку с именами столбцов с префиксом выбранного вами псевдонима.

Ответ 15

Существует прямой ответ на ваш вопрос для тех, кто использует C-API MySQL.

Учитывая 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 */

Обратите внимание на поля: каталог, таблица, org_name

Теперь вы знаете, какие поля в вашем SQL принадлежат той схеме (aka catalog) и таблице. Этого достаточно, чтобы в общем случае идентифицировать каждое поле из многозадачного sql-запроса без необходимости псевдонима.

Фактический продукт SqlYOG показывает использование этих точных данных в такой усадьбе, что они могут самостоятельно обновлять каждую таблицу объединения нескольких таблиц, когда присутствуют поля PK.

Ответ 16

Развиваясь из этого решения, я как-то подхожу к проблеме:

Сначала создайте список всех операторов 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.

Ответ 17

Недавно столкнулся с этой проблемой в NodeJS и Postgres.

ES6 подход

Я не знаю каких-либо функций СУБД, которые бы обеспечивали эту функцию, поэтому я создал объект, содержащий все мои поля, например:

const schema = { columns: ['id','another_column','yet_another_column'] }

Определил редуктор для объединения строк вместе с именем таблицы:

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');

Ответ 18

Я реализовал решение, основанное на ответе, предложив использовать пустые или контрольные столбцы в узле. Вы бы использовали его, генерируя 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)
  })
})

Ответ 19

Что я делаю, это использую Excel для объединения процедуры. Например, сначала я выбираю * и получаю все столбцы, вставляю их в Excel. Затем напишите код, который мне нужен, чтобы окружить колонку. Скажем, мне нужно было рекламировать предыдущую группу столбцов. Я хотел бы иметь мои поля в столбце и "как предыдущий" в столбце B и мои поля снова в столбце c. В столбце d у меня будет столбец.

Затем используйте concatanate в столбце e и объедините их вместе, указав пробелы. Затем вырезать и вставить это в свой код SQL. Я также использовал этот метод для создания операторов case для того же поля и других более длинных кодов, которые мне нужно сделать для каждого поля в таблице из нескольких сотен полей.

Ответ 20

select * обычно делает для плохого кода, поскольку новые столбцы, как правило, добавляются или порядок столбцов изменяется в таблицах довольно часто, что обычно ломает select * очень тонким образом. Поэтому перечисление столбцов - правильное решение.

Что касается вашего запроса, не уверен в mysql, но в sqlserver вы можете выбрать имена столбцов из syscolumns и динамически построить предложение select.

Ответ 21

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'));