SQL select join: apakah mungkin untuk awalan semua kolom sebagai 'awalan. *'?


206

Saya bertanya-tanya apakah ini mungkin dalam SQL. Katakanlah Anda memiliki dua tabel A dan B, dan Anda memilih di tabel A dan bergabung di tabel B:

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

Jika tabel A memiliki kolom 'a_id', 'name', dan 'some_id', dan tabel B memiliki 'b_id', 'name', dan 'some_id', kueri akan mengembalikan kolom 'a_id', 'name', 'some_id ',' b_id ',' name ',' some_id '. Apakah ada cara untuk mengawali nama kolom pada tabel B tanpa mencantumkan setiap kolom secara terpisah? Setara dengan ini:

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

Tapi, seperti yang disebutkan, tanpa mencantumkan setiap kolom, jadi sesuatu seperti:

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

Pada dasarnya sesuatu untuk dikatakan, "awali setiap kolom dikembalikan oleh b. * Dengan 'sesuatu'". Apakah ini mungkin atau saya kurang beruntung?

Terima kasih sebelumnya atas bantuan Anda!

EDIT: saran tentang tidak menggunakan SELECT * dan sebagainya adalah saran yang valid tetapi tidak relevan dalam konteks saya, jadi tolong tetap pada masalah yang ada - apakah mungkin untuk menambahkan awalan (konstanta yang ditentukan dalam permintaan SQL) ke semua nama kolom dari suatu tabel dalam suatu gabungan?

EDIT: tujuan akhir saya adalah untuk dapat melakukan SELECT * pada dua tabel dengan join, dan dapat mengetahui, dari nama-nama kolom yang saya dapatkan di set hasil saya, kolom mana yang berasal dari tabel A dan kolom mana yang berasal dari tabel B. Sekali lagi, saya tidak ingin harus membuat daftar kolom satu per satu, saya harus dapat melakukan SELECT *.


Apa tepatnya yang Anda harapkan dari hasil kueri Anda? Saya bingung
GregD

GregD: Saya ingin semua nama kolom yang keluar dari b. * Diawali dengan beberapa konstanta yang saya tentukan. Misalnya, alih-alih 'nama' dan 'angka', saya ingin menentukan, katakanlah, awalan 'special_' dan dapatkan 'special_name' dan 'special_number'. Tetapi saya tidak ingin melakukan ini untuk setiap kolom secara individual.
foxdonut

6
Ketika saya melakukan SELECT cepat untuk melihat kolom dari beberapa tabel saya kadang-kadang melakukan SELECT 'AAAAA', A. *, 'BBBBB', B. * DARI TableA SEBAGAI GABUNG TableB AS B ON A.ID = B.ID sehingga saya setidaknya memiliki pengidentifikasi tabel saat pemindaian di sepanjang baris
Kristen

Jawaban:


35

Saya melihat dua kemungkinan situasi di sini. Pertama, Anda ingin tahu apakah ada standar SQL untuk ini, yang dapat Anda gunakan secara umum terlepas dari database. Tidak, tidak ada. Kedua, Anda ingin tahu tentang produk dbms tertentu. Maka Anda perlu mengidentifikasinya. Tapi saya membayangkan jawaban yang paling mungkin adalah Anda akan mendapatkan kembali sesuatu seperti "a.id, b.id" karena itulah bagaimana Anda perlu mengidentifikasi kolom dalam ekspresi SQL Anda. Dan cara termudah untuk mengetahui apa defaultnya, adalah dengan mengirimkan pertanyaan seperti itu dan melihat apa yang Anda dapatkan kembali. Jika Anda ingin menentukan awalan apa yang muncul sebelum titik, Anda dapat menggunakan "SELECT * FROM AS my_alias", misalnya.


11
Saya tidak yakin bagaimana ini menjawab pertanyaan Anda. Saya menggunakan MS SQL Server dan menambahkan alias setelah nama tabel tidak menambahkan alias ke nama kolom di resultset.
paiego

74

Tampaknya jawaban untuk pertanyaan Anda adalah tidak, namun satu peretasan yang dapat Anda gunakan adalah dengan menetapkan kolom dummy untuk memisahkan setiap tabel baru. Ini berfungsi terutama jika Anda mengulang hasil yang ditetapkan untuk daftar kolom dalam bahasa scripting seperti Python atau 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

Saya menyadari ini tidak menjawab pertanyaan Anda dengan tepat, tetapi jika Anda seorang pembuat kode, ini adalah cara yang bagus untuk memisahkan tabel dengan nama kolom duplikat. Semoga ini bisa membantu seseorang.


24

Saya benar-benar mengerti mengapa ini perlu - setidaknya bagi saya itu berguna selama prototyping cepat ketika ada banyak tabel yang perlu digabungkan, termasuk banyak sambungan dalam. Segera setelah nama kolom sama dengan wild card bidang "gabungan. *" Kedua, nilai bidang tabel utama diganti dengan nilai gabungan. Kesalahan rawan, membuat frustrasi, dan pelanggaran KERING ketika harus secara manual menentukan bidang tabel dengan alias berulang-ulang ...

Berikut adalah fungsi PHP (Wordpress) untuk mencapai hal ini melalui pembuatan kode bersama dengan contoh cara menggunakannya. Dalam contoh, ini digunakan untuk secara cepat menghasilkan kueri khusus yang akan menyediakan bidang-bidang posting wordpress terkait yang direferensikan melalui bidang bidang khusus lanjutan .

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>";
}

Hasil:

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

Satu-satunya database yang saya tahu melakukan ini adalah SQLite, tergantung pada pengaturan yang Anda konfigurasikan dengan PRAGMA full_column_namesdan PRAGMA short_column_names. Lihat http://www.sqlite.org/pragma.html

Kalau tidak, yang bisa saya rekomendasikan adalah mengambil kolom dalam hasil yang ditentukan oleh posisi ordinal daripada dengan nama kolom, jika terlalu banyak masalah bagi Anda untuk mengetikkan nama kolom dalam permintaan Anda.

Ini adalah contoh yang baik mengapa itu praktik yang buruk untuk digunakanSELECT * - karena pada akhirnya Anda akan perlu mengetikkan semua nama kolom.

Saya memahami perlunya mendukung kolom yang dapat mengubah nama atau posisi, tetapi menggunakan wildcard menjadikannya lebih sulit , bukan lebih mudah.


2
Perhatikan bahwa keduanya full_column_namesdan short_column_namessudah usang dalam SQLite.
isanae

6

Saya memiliki jenis perahu yang sama dengan OP - Saya memiliki lusinan bidang dari 3 tabel berbeda yang saya gabungkan, beberapa di antaranya memiliki nama yang sama (mis. Id, nama, dll). Saya tidak ingin mencantumkan setiap bidang, jadi solusi saya adalah dengan alias bidang yang membagikan nama dan menggunakan pilih * untuk bidang yang memiliki nama unik.

Sebagai contoh :

tabel a: id, nama, field1, field2 ...

tabel b: id, nama, field3, field4 ...

pilih a.id sebagai aID, a.name sebagai aName, a. *, b.id sebagai bID, b.name sebagai bName, b. * .....

Saat mengakses hasil, saya memberikan nama alias untuk bidang ini dan mengabaikan nama "asli".

Mungkin bukan solusi terbaik tetapi berfungsi untuk saya .... saya menggunakan mysql


5

Produk basis data yang berbeda akan memberikan jawaban yang berbeda; tetapi Anda membuat diri Anda terluka jika Anda membawa ini sejauh ini. Anda jauh lebih baik memilih kolom yang Anda inginkan, dan memberi mereka alias Anda sendiri sehingga identitas setiap kolom sejernih kristal, dan Anda dapat membedakannya dalam hasil.


1
Poin yang diambil, tetapi tujuan saya di sini adalah sesuatu yang sangat umum, jadi tidak eksplisit tidak menjadi masalah. Bahkan, harus spesifik akan menjadi masalah.
foxdonut

Lihat pengiriman lebih lanjut di bawah ini. Dapat menggunakan use dot.notation, yang mungkin akan menjadi default Anda?
dkretz

Sangat penting untuk keterbacaan. Saya berharap untuk melakukan ini sekarang karena saya memiliki proses CTE lniked. ex. CTE_A -> CTE_B -> CTE_C -> CTE_D -> select / insert Tidak perlu menentukan kolom yang saya inginkan sampai pernyataan dan kinerja pilih akhir tidak menjadi pertimbangan.
ThomasRones

5

Pertanyaan ini sangat berguna dalam praktiknya. Anda hanya perlu mencantumkan setiap kolom eksplisit dalam pemrograman perangkat lunak, tempat Anda membayar khusus untuk menangani semua kondisi.

Bayangkan ketika melakukan debugging, atau, coba gunakan DBMS sebagai alat kantor harian, alih-alih sesuatu yang bisa diubah implementasi dari infrastruktur abstrak yang mendasari programmer tertentu, kita perlu kode banyak SQL. Skenario dapat ditemukan di mana-mana, seperti konversi basis data, migrasi, administrasi, dll. Sebagian besar dari SQL ini akan dieksekusi hanya sekali dan tidak pernah digunakan lagi, memberikan setiap kolom nama hanya buang-buang waktu. Dan jangan lupa penemuan SQL tidak hanya untuk penggunaan programer.

Biasanya saya akan membuat tampilan utilitas dengan nama kolom diawali, di sini adalah fungsi di pl / pgsql, itu tidak mudah tetapi Anda dapat mengubahnya ke bahasa prosedur lainnya.

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

Contoh:

-- 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

Saya benar-benar mengerti masalah Anda tentang nama bidang yang digandakan.

Saya juga membutuhkannya sampai saya mengkodekan fungsi saya sendiri untuk menyelesaikannya. Jika Anda menggunakan PHP, Anda dapat menggunakannya, atau kode Anda dalam bahasa yang Anda gunakan jika Anda memiliki fasilitas berikut ini.

Kuncinya di sini adalah mysql_field_table()mengembalikan nama tabel dan mysql_field_name()bidang untuk setiap baris dalam hasil jika ada mysql_num_fields()sehingga Anda dapat mencampurnya dalam array baru.

Ini mengawali semua kolom;)

Salam,

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

Tidak ada standar SQL untuk ini.

Namun Dengan pembuatan kode (baik berdasarkan permintaan saat tabel dibuat atau diubah atau saat runtime), Anda dapat melakukan ini dengan mudah:

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)

ini akan berhasil tetapi pertanyaannya agak konyol. mengapa tidak hanya melakukan penyatuan atau sub-kueri. Mengapa Anda bergabung dan masih menginginkan awalan tabel dalam nama kolom?
D3vtr0n

Cade: terima kasih atas informasinya, itu menarik. Sayangnya, membuat / mengubah basis data bukanlah pilihan dalam kasus saya. Devtron: jika Anda mencoba memetakan informasi yang kembali dari permintaan ke properti objek yang berbeda, informasi itu menjadi sangat berguna.
foxdonut

1
Kadang-kadang nama kolom dalam tabel berbeda adalah sama, tetapi tidak mengandung nilai yang sama. Oleh karena itu perlu awalan mereka untuk membedakannya dalam tampilan atau tabel turunan (yang harus memiliki semua nama kolom yang unik).
Cade Roux

@Frederic, kode Anda harus tinggal di suatu tempat - ini hanya menghasilkan kode. Sekali lagi, ini dapat dilakukan satu kali selama pengembangan atau secara dinamis pada saat run time.
Cade Roux

1

Ada dua cara yang dapat saya pikirkan untuk mewujudkan hal ini dengan cara yang dapat digunakan kembali. Pertama adalah mengganti nama semua kolom Anda dengan awalan untuk tabel asal mereka. Saya telah melihat ini berkali-kali, tetapi saya benar-benar tidak menyukainya. Saya menemukan bahwa itu berlebihan, menyebabkan banyak pengetikan, dan Anda selalu dapat menggunakan alias ketika Anda perlu untuk menutupi kasus nama kolom yang memiliki asal tidak jelas.

Cara lain, yang saya sarankan Anda lakukan dalam situasi Anda jika Anda berkomitmen untuk melihat ini, adalah untuk membuat tampilan untuk setiap tabel yang alias nama tabel. Kemudian Anda bergabung dengan pandangan itu, bukan tabel. Dengan begitu, Anda bebas menggunakan * jika ingin, bebas menggunakan tabel asli dengan nama kolom asli jika Anda mau, dan itu juga membuat penulisan kueri selanjutnya menjadi lebih mudah karena Anda telah melakukan pekerjaan penggantian nama dalam tampilan.

Akhirnya, saya tidak jelas mengapa Anda perlu tahu dari tabel mana masing-masing kolom berasal. Apakah ini masalah? Pada akhirnya yang penting adalah data yang dikandungnya. Apakah UserID berasal dari tabel Pengguna atau tabel UserQuestion tidak terlalu penting. Itu penting, tentu saja, ketika Anda perlu memperbaruinya, tetapi pada saat itu Anda harus sudah mengetahui skema Anda dengan cukup baik untuk menentukan itu.


"Akhirnya, aku tidak jelas mengapa kamu perlu tahu dari mana tabel masing-masing kolom berasal. Apakah ini penting?" <- 11 tahun kemudian, satu use case adalah pemindaian struct di Go.
Lee Benson

1

Atau Anda bisa menggunakan Red Gate SQL Refactor atau SQL Prompt, yang memperluas SELECT * Anda ke dalam daftar kolom dengan mengklik tombol Tab

jadi dalam kasus Anda, jika Anda mengetikkan SELECT * FROM A JOIN B ... Pergi ke akhir *, tombol Tab, voila! Anda akan melihat SELECT A.column1, A.column2, ...., B.column1, B.column2 DARI A JOIN B

Ini tidak gratis


1

Tidak dapat melakukan ini tanpa alias, hanya karena, bagaimana Anda akan merujuk bidang dalam klausa where, jika bidang itu ada di 2 atau 3 tabel yang Anda gabungkan? Tidak jelas untuk mysql yang mana yang Anda coba rujuk.


1

Saya memecahkan masalah yang sama dengan menamai ulang bidang dalam tabel yang terlibat. Ya, saya memiliki hak istimewa untuk melakukan ini dan memahami bahwa semua orang mungkin tidak memilikinya. Saya menambahkan awalan ke setiap bidang dalam tabel yang mewakili nama tabel. Dengan demikian SQL yang diposting oleh OP akan tetap tidak berubah -

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

dan masih memberikan hasil yang diharapkan - kemudahan mengidentifikasi tabel mana bidang output milik.


0

pilih * biasanya membuat kode buruk, karena kolom baru cenderung ditambahkan atau urutan kolom berubah dalam tabel yang cukup sering yang biasanya memecah pilih * dengan cara yang sangat halus. Jadi daftar kolom adalah solusi yang tepat.

Tentang cara melakukan kueri Anda, tidak yakin tentang mysql tetapi dalam sqlserver Anda bisa memilih nama kolom dari syscolumns dan secara dinamis membangun klausa pilih.


Poin diambil, tetapi dalam konteks saya, saya memerlukan sesuatu yang generik dan dinamis, jadi sebenarnya kode saya akan beradaptasi dengan kolom baru yang ditambahkan / dipesan ulang / dll. Saya tidak mau harus membuat daftar kolom satu per satu.
foxdonut

5
Memilih dari syscolumns untuk secara dinamis membangun pernyataan pilih adalah peretasan yang mengerikan, dan saya tidak akan merekomendasikannya dalam produksi.
Juliet

0

Jika khawatir tentang perubahan skema, ini mungkin berfungsi untuk Anda: 1. Jalankan kueri 'DESCRIBE table' di semua tabel yang terlibat. 2. Gunakan nama bidang yang dikembalikan untuk secara dinamis membangun serangkaian nama kolom yang diawali dengan alias yang Anda pilih.


0

Ada jawaban langsung untuk pertanyaan Anda bagi mereka yang menggunakan MySQL C-API.

Mengingat SQL:

  SELECT a.*, b.*, c.* FROM table_a a JOIN table_b b USING (x) JOIN table_c c USING (y)

Hasil dari 'mysql_stmt_result_metadata ()' memberikan definisi bidang Anda dari kueri SQL yang disiapkan ke dalam struktur MYSQL_FIELD []. Setiap bidang berisi data berikut:

  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 */

Perhatikan bidang: katalog, tabel, org_name

Anda sekarang tahu bidang mana dalam SQL Anda yang termasuk skema (alias katalog) dan tabel mana. Ini cukup untuk secara umum mengidentifikasi setiap bidang dari kueri multi-tabel sql, tanpa harus alias apa pun.

SqlYOG produk aktual ditunjukkan untuk menggunakan data yang tepat ini di manor sehingga mereka dapat memperbarui setiap tabel gabungan multi-tabel secara independen, saat bidang PK ada.


0

Berkembang dari solusi ini , inilah cara saya mendekati masalah:

Pertama buat daftar semua ASpernyataan:

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

Kemudian gunakan dalam permintaan Anda:

EXEC('SELECT ' + @asStatements + ' FROM TABLE_A a JOIN TABLE_B b USING (some_id)');

Namun, ini mungkin perlu modifikasi karena sesuatu yang serupa hanya diuji dalam SQL Server. Tetapi kode ini tidak benar-benar berfungsi di SQL Server karena MENGGUNAKAN tidak didukung.

Berikan komentar jika Anda dapat menguji / memperbaiki kode ini untuk mis. MySQL.


0

Baru-baru ini mengalami masalah ini di NodeJS dan Postgres.

Pendekatan ES6

Tidak ada fitur RDBMS yang saya tahu menyediakan fungsi ini, jadi saya membuat objek yang berisi semua bidang saya, misalnya:

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

Menetapkan reducer untuk menggabungkan string bersama dengan nama tabel:

const prefix = (table, columns) => columns.reduce((previous, column) => {
  previous.push(table + '.' + column + ' AS ' + table + '_' + column);
  return previous;
}, []);

Ini mengembalikan array string. Sebut saja untuk setiap tabel dan gabungkan hasilnya:

const columns_joined = [...prefix('tab1',schema.columns), ...prefix('tab2',schema.columns)];

Keluarkan pernyataan SQL terakhir:

console.log('SELECT ' + columns_joined.join(',') + ' FROM tab1, tab2 WHERE tab1.id = tab2.id');

Tidak mungkin! Itu beberapa suntikan SQL hacky, dan tidak bekerja dengan ekspresi.
ratijas

0

Saya menerapkan solusi berdasarkan jawaban yang menyarankan menggunakan kolom dummy atau sentinel di node. Anda akan menggunakannya dengan menghasilkan SQL seperti:

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

Dan kemudian pasca-pemrosesan, baris yang Anda dapatkan dari driver basis data Anda seperti addPrefixes(row).

Implementasi (berdasarkan fields/ rowsdikembalikan oleh driver saya, tetapi harus mudah diubah untuk driver DB lainnya):

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
}

Uji:

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

Apa yang saya lakukan adalah menggunakan Excel untuk menggabungkan prosedur. Misalnya, pertama saya pilih * dan dapatkan semua kolom, tempel di Excel. Kemudian tulis kode yang saya butuhkan untuk mengelilingi kolom. Katakanlah saya perlu iklan sebelum sekelompok kolom. Saya akan memiliki bidang saya di kolom a dan "as prev_" di kolom B dan bidang saya lagi di kolom c. Di kolom d saya akan memiliki kolom.

Kemudian gunakan concatanate di kolom e dan gabungkan keduanya, pastikan untuk memasukkan spasi. Kemudian potong dan tempel ini ke dalam kode sql Anda. Saya juga menggunakan metode ini untuk membuat pernyataan kasus untuk bidang yang sama dan kode lain lagi yang perlu saya lakukan untuk setiap bidang dalam tabel bidang multihundred.


0

Dalam postgres, saya menggunakan fungsi json untuk mengembalikan objek json .... lalu, setelah kueri, saya json_decode bidang dengan akhiran _json.

YAITU:

select row_to_json(tab1.*),tab1_json, row_to_json(tab2.*) tab2_json 
 from tab1
 join tab2 on tab2.t1id=tab1.id

kemudian dalam PHP (atau bahasa lain), saya loop melalui kolom yang dikembalikan dan json_decode () mereka jika mereka memiliki akhiran "_json" (juga menghapus akhiran. Pada akhirnya, saya mendapatkan objek bernama "tab1" yang mencakup semua bidang tab1, dan bidang lain yang disebut "tab2" yang mencakup semua bidang tab2.


-1

PHP 7.2 + MySQL / Mariadb

MySQL akan mengirimkan Anda beberapa bidang dengan nama yang sama. Bahkan di klien terminal. Tetapi jika Anda menginginkan array asosiatif, Anda harus membuat kunci sendiri.

Terima kasih kepada @axelbrz untuk aslinya. Saya telah porting ke php yang lebih baru dan membersihkannya sedikit:

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'));
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.