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 ',' ім'я ',' 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 *.


Яким саме ви очікуєте результату вашого запиту? Я розгублений
GregD

GregD: Я хочу, щоб усі назви стовпців, які виходять з b. *, Мали префікс із якоюсь постійною, яку я вказую. Наприклад, замість 'ім'я' та 'номер' я хочу вказати, скажімо, префікс 'special_' і отримати 'special_name' та 'special_number'. Але я не хочу робити це для кожного стовпця окремо.
foxdonut

6
Коли я швидко виберіть SELECT, щоб побачити стовпці з декількох таблиць, я колись SELECT 'AAAAA', A. *, 'BBBBB', B. * З TableA ЯК ПРИЄДНАЙТЕСЯ TableB AS B НА A.ID = B.ID, щоб я принаймні мати ідентифікатор таблиці під час сканування по рядках
Крістен,

Можливий дублікат: stackoverflow.com/questions/2595068 / ...
Andrioid

Відповіді:


35

Я бачу тут дві можливі ситуації. По-перше, ви хочете дізнатися, чи є для цього стандарт SQL, який ви можете використовувати взагалі незалежно від бази даних. Ні, немає. По-друге, ви хочете знати, що стосується конкретного продукту dbms. Тоді вам потрібно його визначити. Але я думаю, що найбільш вірогідна відповідь полягає в тому, що ви отримаєте щось на кшталт "a.id, b.id", оскільки саме так вам потрібно буде визначити стовпці у виразі SQL. І найпростіший спосіб дізнатися, що таке за замовчуванням - це просто подати такий запит і подивитися, що ви отримаєте назад. Якщо ви хочете вказати, який префікс поставляється перед крапкою, ви можете, наприклад, використати "SELECT * FROM AS my_alias".


11
Я не впевнений, як це відповідає на ваше запитання. Я використовую MS SQL Server і додаю псевдонім після того, як ім'я таблиці не додає псевдонім до імен стовпців у наборі результатів.
paiego

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

Я повністю розумію, чому це необхідно - принаймні, для мене це зручно під час швидкого складання прототипів, коли існує маса таблиць, які необхідно з'єднати, включаючи багато внутрішніх з'єднань. Як тільки ім'я стовпця є однаковим у другому "підключеному. *" Полевому знаку поля, значення поля основної таблиці переосмислюються зі значеннями, що з'єднуються. Схильність до помилок, розчарування та порушення 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.
isanae

6

Я в роді того ж човна, що і OP - у мене є десятки полів з 3 різних таблиць, до яких я приєднуюся, деякі з яких мають те саме ім’я (тобто id, ім'я та ін.). Я не хочу перераховувати кожне поле, тому моє рішення було псевдонімом тих полів, які мають загальне ім'я та використовують select * для тих, у кого є унікальне ім’я.

Наприклад :

таблиця a: id, ім'я, field1, field2 ...

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

виберіть 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 -> вибирати / вставляти Не потрібно вказувати потрібні стовпці, поки остаточний оператор вибору та продуктивність не враховуються.
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;

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 з таблиці користувача або з таблиці UserQuestion. Звичайно, важливо, коли вам потрібно оновити його, але в цей момент ви вже повинні добре знати свою схему, щоб це визначити.


"Нарешті, мені незрозуміло, чому вам потрібно знати, з якої таблиці походить кожна зі стовпців. Це має значення?" <- 11 років потому, одним із випадків використання є сканування структури в Go.
Лі Бенсон

1

Або ви можете використовувати Red Gate SQL Refactor або SQL Prompt, який розширює ваш SELECT * у списки стовпців натисканням кнопки Tab

тож у вашому випадку, якщо ви введете ВИБІР * З ПРИЄДНАННЯ В ... Перейдіть до кінця *, кнопки Tab, вуаля! ви побачите SELECT A.column1, A.column2, ...., B.column1, B.column2 З ПРИЄДНАЙТЕСЬ B

Це не безкоштовно


1

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


1

Я вирішив подібну проблему моєї, перейменувавши поля у відповідних таблицях. Так, я мав честь робити це і розумів, що у кожного може цього не бути. Я додав префікс до кожного поля в межах таблиці, що представляє ім'я таблиці. Таким чином, SQL, розміщений ОП, залишився б незмінним -

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

і все ж дають очікувані результати - простота визначити, до якої таблиці належать вихідні поля.


0

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

Щодо того, як зробити ваш запит, не впевнений у mysql, але в sqlserver ви можете вибрати назви стовпців із системних стовпців та динамічно будувати пункт вибору.


Точка прийнята, але в моєму контексті мені потрібно щось загальне і динамічне, тому насправді мій код буде адаптуватися до нових стовпців, що додаються / упорядковуються / тощо. Мені не хочеться окремо перераховувати стовпці.
foxdonut

5
Вибір із системних стовпців для динамічної побудови вибору оператора - жахливий хак, і я не рекомендував би його у виробництві.
Джульєтта

0

Якщо вас турбують зміни схеми, це може допомогти вам: 1. Запустіть запит 'DESCRIBE table' для всіх задіяних таблиць. 2. Використовуйте імена повернених полів, щоб динамічно побудувати рядок імен стовпців з префіксом вибраного псевдоніму.


0

Тим, хто використовує 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_

Тепер ви знаєте, які поля у вашому 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'] }

Визначений редуктор для об'єднання рядків разом із назвою таблиці:

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. Потім випишіть код, який мені потрібен для оточення стовпця. Скажіть, мені потрібно було оголосити попередню купу колонок. Я маю свої поля у стовпці та "як prev_" у колонці B, а мої поля знову в колонці c. У колонці d я мав би стовпець.

Потім використовуйте конкатанат у стовпці е і об'єднайте їх разом, обов'язково включивши пробіли. Потім виріжте і вставте це у код sql. Я також використовував цей метод для складання заяв про регістри для того ж поля та інших довших кодів, які мені потрібно зробити для кожного поля в багатотисячній таблиці поля.


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'));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.