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

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 ',' 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. *, Префикс« что-то »». Это возможно или мне не повезло?

Заранее спасибо за вашу помощь!

РЕДАКТИРОВАТЬ: рекомендация не использовать SELECT * и т. Д. Является действительной рекомендацией, но не имеет отношения к моему контексту, поэтому, пожалуйста, придерживайтесь рассматриваемой проблемы - возможно ли добавить префикс (константу, указанную в запросе SQL) ко всем имена столбцов таблицы в объединении?

РЕДАКТИРОВАТЬ: моя конечная цель состоит в том, чтобы иметь возможность выполнять SELECT * для двух таблиц с объединением и иметь возможность определять по именам столбцов, которые я получаю в моем наборе результатов, какие столбцы получены из таблицы A и какие столбцы получены из таблицы B. Опять же, я не хочу, чтобы список столбцов индивидуально, мне нужно иметь возможность сделать SELECT *.

foxdonut
источник
Что именно вы ожидаете от результатов вашего запроса? Я в замешательстве
GregD
GregD: я хочу, чтобы все имена столбцов, начинающиеся с b. *, Имели префикс с некоторой константой, которую я указал. Например, вместо «name» и «number» я хочу указать, скажем, префикс «special_» и получить «special_name» и «special_number». Но я не хочу делать это для каждого столбца в отдельности.
foxdonut
6
Когда я делаю быстрый SELECT, чтобы увидеть столбцы из нескольких таблиц, я иногда делаю SELECT 'AAAAA', A. *, 'BBBBB', B. * ИЗ таблицы TableA КАК СОЕДИНЯЕМАЯ TableB AS B ON A.ID = B.ID, чтобы я по крайней мере, иметь идентификатор таблицы при сканировании вдоль строк
Кристен
Возможный дубликат: stackoverflow.com/questions/2595068/…
Andrioid

Ответы:

35

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

dkretz
источник
11
Я не уверен, как это отвечает на ваш вопрос. Я использую MS SQL Server и добавляю псевдоним после того, как имя таблицы не добавляет псевдоним к именам столбцов в наборе результатов.
августа
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

Я полностью понимаю, почему это необходимо - по крайней мере, для меня это удобно при быстром прототипировании, когда необходимо объединить множество таблиц, включая множество внутренних объединений. Как только имя столбца совпадает со вторым подстановочным знаком поля "jointable. *", Значения полей основной таблицы заменяются значениями объединяемой таблицы. Склонность к ошибкам, разочарование и нарушение 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
Обратите внимание , что оба full_column_namesи short_column_namesявляются устаревшими в SQLite.
Исана
6

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

Например :

таблица а: идентификатор, имя, поле1, поле2 ...

таблица b: идентификатор, имя, поле3, поле4 ...

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

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

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


источник
5

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

dkretz
источник
1
Смысл принят, но моя цель здесь очень общая, поэтому не быть явным - не проблема. На самом деле, необходимость быть конкретным была бы проблемой.
foxdonut
Смотрите дальнейшее представление ниже. Можно использовать use dot.notation, который, вероятно, вы получите по умолчанию?
dkretz
Это важно для удобства чтения. Я надеялся сделать это прямо сейчас, потому что у меня есть процесс CTE. ех. CTE_A -> CTE_B -> CTE_C -> CTE_D -> выбор / вставка Нет необходимости указывать нужные столбцы до тех пор, пока окончательный оператор выбора и производительность не будут рассматриваться.
ThomasRones
5

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

Представьте себе, что при отладке или попробуйте использовать СУБД в качестве инструмента ежедневной работы, вместо того, чтобы что-то изменить реализацию абстрактной базовой инфраструктуры конкретного программиста, нам нужно кодировать много 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;
Xiè Jìléi
источник
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;
}
axelbrz
источник
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
Иногда имена столбцов в разных таблицах совпадают, но не содержат одинаковых значений. Отсюда необходимость их префикса, чтобы различать их в представлениях или производных таблицах (которые должны иметь все уникальные имена столбцов).
Cade Roux
@Frederic, ваш код должен где-то жить - он просто генерирует код. Опять же, это можно сделать один раз во время разработки или динамически во время выполнения.
Cade Roux
1

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

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

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

RedFilter
источник
«Наконец, я не понимаю, зачем вам знать, из какой таблицы пришел каждый столбец. Имеет ли это значение?» <- 11 лет спустя, одним из вариантов использования является структурное сканирование в Go.
Ли Бенсон
1

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

так что в вашем случае, если вы наберете SELECT * FROM A JOIN B ... Перейти к концу *, кнопка Tab, вуаля! вы увидите ВЫБРАТЬ A.column1, A.column2, ...., B.column1, B.column2 ОТ СОЕДИНЕНИЯ B

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

jerryhung
источник
1

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

kobejr
источник
1

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

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

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

Сэм
источник
0

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

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

Kozyarchuk
источник
Точка взята, но в моем контексте мне нужно что-то общее и динамичное, так что на самом деле мой код будет адаптироваться к добавляемым / переупорядоченным новым столбцам / и т.д. Я не хочу, чтобы список столбцов индивидуально.
foxdonut
5
Выбор из syscolumns для динамического построения оператора select является ужасным хаком, и я бы не рекомендовал его в производстве.
Джульетта
0

Если вас беспокоит изменение схемы, это может сработать для вас: 1. Запустите запрос «DESCRIBE table» для всех задействованных таблиц. 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 */

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

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

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

J Jorgenson
источник
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 подход

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

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');
блэр
источник
Ни за что! Это какая-то хакерская инъекция 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. Затем напишите код, который мне нужен, чтобы окружить колонку. Скажем, мне нужно было рекламировать предыдущую группу столбцов. Я бы имел мои поля в столбце и «как предыдущий» в столбце B, а мои поля снова в столбце c. В столбце d у меня будет столбец.

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

Натан Майкл
источник
0

В postgres я использую функции json, чтобы вместо этого возвращать объекты json .... затем, после запроса, я json_decode поля с суффиксом _json.

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_decode () их, если они имеют суффикс "_json" (также удаляя суффикс. В конце я получаю объект с именем "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'));
JasonWoof
источник