SQL select join: возможно ли префикс всех столбцов как префикс. *? - PullRequest
182 голосов
/ 01 декабря 2008

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

Ответы [ 21 ]

63 голосов
/ 29 марта 2012

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

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

35 голосов
/ 01 декабря 2008

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

19 голосов
/ 19 января 2012

Я полностью понимаю, почему это необходимо - по крайней мере, для меня это удобно при быстром прототипировании, когда необходимо объединить множество таблиц, включая множество внутренних объединений. Как только имя столбца совпадает со вторым подстановочным знаком поля "Jointable. *", Значения полей основной таблицы заменяются значениями объединяемой таблицы. Склонность к ошибкам, разочарование и нарушение DRY при необходимости вручную указывать поля таблицы с псевдонимами снова и снова ...

Вот функция PHP (Wordpress) для достижения этой цели посредством генерации кода вместе с примером того, как ее использовать. В этом примере он используется для быстрой генерации пользовательского запроса, который предоставит поля связанного поста WordPress, на который ссылались через расширенные настраиваемые поля поле.

<code>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
"; $ posts = $ wpdb-> get_results ($ query, OBJECT); echo "
";
    print_r($posts);
    echo "
"; }

Выход:

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
        )
)
11 голосов
/ 01 декабря 2008

Единственная известная мне база данных, которая делает это, - это SQLite, в зависимости от настроек, которые вы конфигурируете с помощью PRAGMA full_column_names и PRAGMA short_column_names. Смотри http://www.sqlite.org/pragma.html

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

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

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

6 голосов
/ 02 декабря 2008

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

Например:

таблица: Я бы, название, field1, field2 ...

таблица б: Я бы, название, field3, field4 ...

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

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

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

5 голосов
/ 01 декабря 2008

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

4 голосов
/ 22 октября 2014

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

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

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

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

Для этого не существует стандарта 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)
1 голос
/ 02 декабря 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...