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. * พร้อม 'บางสิ่งบางอย่าง" สิ่งนี้เป็นไปได้หรือเปล่า

ขอบคุณล่วงหน้าสำหรับความช่วยเหลือของ!

แก้ไข: คำแนะนำเกี่ยวกับการไม่ใช้ SELECT * และอื่น ๆ เป็นคำแนะนำที่ถูกต้อง แต่ไม่เกี่ยวข้องในบริบทของฉันดังนั้นโปรดติดปัญหาที่อยู่ในมือ - เป็นไปได้หรือไม่ที่จะเพิ่มคำนำหน้า (ค่าคงที่ที่ระบุในแบบสอบถาม SQL) ชื่อคอลัมน์ของตารางในการเข้าร่วม?

แก้ไข: เป้าหมายสูงสุดของฉันคือการสามารถเลือก * ในสองตารางที่มีการเข้าร่วมและสามารถบอกได้จากชื่อของคอลัมน์ที่ฉันได้รับในชุดผลลัพธ์ของฉันคอลัมน์ใดมาจากตาราง A และคอลัมน์ใดมา จากตาราง B อีกครั้งฉันไม่ต้องการที่จะแสดงคอลัมน์ทีละรายการฉันต้องสามารถเลือก * ได้


คุณคาดหวังสิ่งที่ผลลัพธ์ของแบบสอบถามของคุณเป็นอย่างไร ฉันสับสน
GregD

GregD: ฉันต้องการชื่อคอลัมน์ทั้งหมดที่มาจาก b. * เพื่อนำหน้าด้วยค่าคงที่ที่ฉันระบุ ตัวอย่างเช่นแทนที่จะเป็น 'ชื่อ' และ 'หมายเลข' ฉันต้องการระบุว่าคำนำหน้า 'special_' และรับ 'special_name' และ 'special_number' แต่ฉันไม่ต้องการทำสิ่งนี้สำหรับแต่ละคอลัมน์
foxdonut

6
เมื่อฉันเลือกด่วนเพื่อดูคอลัมน์จากหลาย ๆ ตารางฉันจะเลือก 'AAAAA', A. *, 'BBBBB', B. * จาก TableA เป็น A เข้าร่วม TableB อย่าง B บน A.ID = B.ID ดังนั้นฉันจึงเลือก อย่างน้อยมีตัวระบุตารางเมื่อสแกนพร้อมแถว
คริสเต

สำเนาซ้ำที่เป็นไปได้: stackoverflow.com/questions/2595068/…
Andrioid

คำตอบ:


35

ฉันเห็นสองสถานการณ์ที่เป็นไปได้ที่นี่ ก่อนอื่นคุณต้องการทราบว่ามีมาตรฐาน SQL สำหรับสิ่งนี้หรือไม่ซึ่งคุณสามารถใช้โดยทั่วไปไม่ว่าฐานข้อมูลจะเป็นเช่นไร ไม่ไม่มี ประการที่สองคุณต้องการทราบเกี่ยวกับผลิตภัณฑ์ dbms เฉพาะ จากนั้นคุณต้องระบุมัน แต่ฉันคิดว่าคำตอบที่เป็นไปได้มากที่สุดคือคุณจะได้รับบางสิ่งเช่น "a.id, b.id" เนื่องจากเป็นวิธีที่คุณต้องระบุคอลัมน์ในนิพจน์ SQL ของคุณ และวิธีที่ง่ายที่สุดในการค้นหาว่าเป็นค่าเริ่มต้นคือเพียงส่งแบบสอบถามดังกล่าวและดูว่าคุณได้รับกลับมา หากคุณต้องการระบุว่าคำนำหน้าใดมาก่อนจุดคุณสามารถใช้ตัวอย่างเช่น "SELECT * FROM a 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

ฉันเข้าใจอย่างถ่องแท้ว่าทำไมถึงมีความจำเป็น - อย่างน้อยสำหรับฉันมันมีประโยชน์ในระหว่างการสร้างต้นแบบอย่างรวดเร็วเมื่อมีตารางจำนวนมากที่จำเป็นต้องเข้าร่วมรวมถึงการรวมภายในหลายอย่าง ทันทีที่ชื่อคอลัมน์เหมือนกันใน wild wildcard ฟิลด์ "jointable. *" ที่สองค่าของฟิลด์หลักของตารางจะถูกแทนที่ด้วยค่า 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
isanae

6

ฉันอยู่ในประเภทเดียวกันกับเรือ OP - ฉันมีหลายสาขาจาก 3 ตารางที่ต่างกันที่ฉันเข้าร่วมบางส่วนมีชื่อเดียวกัน (เช่น id, ชื่อ ฯลฯ ) ฉันไม่ต้องการแสดงรายการแต่ละฟิลด์ดังนั้นโซลูชันของฉันคือตั้งชื่อแทนฟิลด์เหล่านั้นที่ใช้ชื่อร่วมกันและใช้ select * สำหรับผู้ที่มีชื่อเฉพาะ

ตัวอย่างเช่น :

ตาราง a: id, ชื่อ, field1, field2 ...

ตาราง b: id, ชื่อ, field3, field4 ...

เลือก a.id เป็น aID, a.name เป็น aName, a *, b.id เป็น bID, b.name เป็น bName, b * .....

เมื่อเข้าถึงผลลัพธ์เราใช้ชื่อแทนสำหรับฟิลด์เหล่านี้และละเว้นชื่อ "ดั้งเดิม"

อาจไม่ใช่วิธีที่ดีที่สุด แต่ใช้งานได้สำหรับฉัน .... ฉันใช้ mysql


5

ผลิตภัณฑ์ฐานข้อมูลที่แตกต่างกันจะให้คำตอบที่แตกต่างกัน แต่คุณกำลังเตรียมพร้อมสำหรับความเจ็บปวดหากคุณดำเนินการไปไกลมาก คุณดีกว่าการเลือกคอลัมน์ที่คุณต้องการและให้ชื่อแทนของคุณเองเพื่อให้ข้อมูลประจำตัวของแต่ละคอลัมน์ชัดเจนและคุณสามารถแยกพวกเขาออกจากผลลัพธ์ได้


1
ชี้ไปที่ แต่เป้าหมายของฉันที่นี่เป็นสิ่งทั่วไปมากดังนั้นการไม่ชัดเจนไม่มีปัญหา ในความเป็นจริงการมีความเฉพาะเจาะจงจะเป็นปัญหา
foxdonut

ดูการส่งเพิ่มเติมด้านล่าง ใช้ use dot.notation ซึ่งน่าจะเป็นค่าเริ่มต้น
dkretz

มันสำคัญสำหรับการอ่าน ฉันหวังว่าจะทำสิ่งนี้ในตอนนี้เพราะฉันมีกระบวนการ CTE ที่ดี อดีต CTE_A -> CTE_B -> CTE_C -> CTE_D -> select / insert ไม่จำเป็นต้องระบุคอลัมน์ที่ฉันต้องการจนกว่าคำสั่ง select สุดท้ายและประสิทธิภาพจะไม่ได้รับการพิจารณา
ThomasRones

5

คำถามนี้มีประโยชน์มากในทางปฏิบัติ จำเป็นต้องระบุทุกคอลัมน์ชัดเจนในการเขียนโปรแกรมซอฟต์แวร์ซึ่งคุณต้องระมัดระวังเป็นพิเศษในการจัดการกับเงื่อนไขทั้งหมด

ลองนึกภาพเมื่อทำการดีบั๊กหรือพยายามใช้ DBMS เป็นเครื่องมือ office รายวันแทนที่จะใช้สิ่งที่เปลี่ยนแปลงได้ของโครงสร้างพื้นฐานพื้นฐานของโปรแกรมเมอร์เฉพาะเราจำเป็นต้องใช้รหัส SQL จำนวนมาก สถานการณ์สามารถพบได้ทุกที่เช่นการแปลงฐานข้อมูลการโยกย้ายการจัดการ ฯลฯ SQLs เหล่านี้ส่วนใหญ่จะถูกดำเนินการเพียงครั้งเดียวและไม่ถูกใช้อีกครั้งทำให้ชื่อคอลัมน์ทุกคอลัมน์เสียเวลา และอย่าลืมว่าการประดิษฐ์ 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

Cade: ขอบคุณสำหรับข้อมูลที่น่าสนใจ น่าเสียดายที่การสร้าง / แก้ไขฐานข้อมูลไม่ใช่ตัวเลือกในกรณีของฉัน Devtron: ถ้าคุณพยายามแมปข้อมูลที่กลับมาจากการสืบค้นไปยังคุณสมบัติต่าง ๆ ของวัตถุข้อมูลนั้นจะมีประโยชน์มาก
foxdonut

1
บางครั้งชื่อคอลัมน์ในตารางที่แตกต่างกันจะเหมือนกัน แต่ไม่มีค่าเดียวกัน ดังนั้นความต้องการที่จะนำหน้าพวกเขาเพื่อแยกพวกเขาในมุมมองหรือตารางที่ได้รับ (ซึ่งจะต้องมีชื่อคอลัมน์ที่ไม่ซ้ำกันทั้งหมด)
เคดรูส์

@ เฟรเดอริกโค้ดของคุณต้องอยู่ที่ไหนสักแห่ง - นี่เป็นเพียงการสร้างรหัส สามารถทำได้อีกครั้งในระหว่างการพัฒนาหรือขณะรันไทม์
เคดรูส์

1

มีสองวิธีที่ฉันสามารถคิดเพื่อทำให้สิ่งนี้เกิดขึ้นในแบบที่นำมาใช้ซ้ำได้ หนึ่งคือการเปลี่ยนชื่อคอลัมน์ทั้งหมดของคุณด้วยคำนำหน้าสำหรับตารางที่พวกเขาได้มาจาก ฉันเคยเห็นมาหลายครั้งแล้ว แต่ฉันไม่ชอบ ฉันพบว่ามันซ้ำซ้อนทำให้เกิดการพิมพ์จำนวนมากและคุณสามารถใช้ชื่อแทนได้ทุกเมื่อที่คุณต้องการครอบคลุมกรณีของชื่อคอลัมน์ที่มีต้นกำเนิดที่ไม่ชัดเจน

วิธีอื่นที่ฉันอยากจะแนะนำให้คุณทำในสถานการณ์ของคุณหากคุณมีความมุ่งมั่นที่จะเห็นสิ่งนี้ผ่านคือการสร้างมุมมองสำหรับแต่ละตารางที่เป็นชื่อแทนชื่อตาราง จากนั้นคุณเข้าร่วมกับมุมมองเหล่านั้นไม่ใช่ตาราง ด้วยวิธีนี้คุณมีอิสระในการใช้ * หากคุณต้องการฟรีใช้ตารางดั้งเดิมที่มีชื่อคอลัมน์เดิมหากคุณต้องการและมันยังทำให้การเขียนแบบสอบถามใด ๆ ที่ตามมาง่ายขึ้นเพราะคุณได้ทำการเปลี่ยนชื่องานในมุมมองแล้ว

ในที่สุดฉันยังไม่ชัดเจนว่าทำไมคุณต้องรู้ว่าแต่ละคอลัมน์มาจากไหน มันเป็นเรื่องสำคัญไหม ในที่สุดสิ่งที่สำคัญคือข้อมูลที่มี UserID นั้นมาจากตารางผู้ใช้หรือตาราง UserQuestion ไม่สำคัญ แน่นอนว่ามันสำคัญเมื่อคุณต้องการอัปเดต แต่ ณ จุดนั้นคุณควรรู้สคีมาของคุณดีพอที่จะตัดสินได้


"ในที่สุดฉันไม่ชัดเจนว่าทำไมคุณต้องรู้ว่าแต่ละคอลัมน์มาจากตารางใด <- 11 ปีต่อมากรณีใช้งานหนึ่งกรณีคือการสแกนโครงสร้างใน Go
Lee Benson

1

หรือคุณสามารถใช้ Red Gate SQL Refactor หรือ SQL Prompt ซึ่งขยาย SELECT * ของคุณไปยังรายการคอลัมน์ด้วยการคลิกปุ่ม Tab

ดังนั้นในกรณีของคุณถ้าคุณพิมพ์ใน SELECT * จาก A เข้าร่วม B ... ไปที่จุดสิ้นสุด *, ปุ่ม Tab, voila! คุณจะเห็น SELECT A.column1, A.column2, .... , B.column1, B.column2 จาก A เข้าร่วม B

มันไม่ฟรีแม้ว่า


1

ไม่สามารถทำสิ่งนี้ได้โดยไม่ใช้นามแฝงเพียงเพราะคุณจะอ้างอิงเขตข้อมูลในส่วนคำสั่งที่ไหนถ้าเขตข้อมูลนั้นอยู่ในตาราง 2 หรือ 3 ที่คุณเข้าร่วม มันจะไม่ชัดเจนสำหรับ mysql ที่คุณพยายามอ้างอิง


1

ฉันแก้ไขปัญหาที่คล้ายกันของฉันโดยเปลี่ยนชื่อฟิลด์ในตารางที่เกี่ยวข้อง ใช่ฉันมีสิทธิ์ทำสิ่งนี้และเข้าใจว่าทุกคนอาจไม่มี ฉันเพิ่มคำนำหน้าให้กับแต่ละฟิลด์ภายในตารางที่แสดงชื่อตาราง ดังนั้น SQL ที่โพสต์โดย OP จะยังคงไม่เปลี่ยนแปลง -

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

และยังคงให้ผลลัพธ์ที่คาดหวัง - ความสะดวกในการระบุว่าฟิลด์ใดเป็นฟิลด์เอาต์พุต


0

select * มักจะสร้างรหัสที่ไม่ดีเนื่องจากคอลัมน์ใหม่มีแนวโน้มที่จะถูกเพิ่มเข้ามาหรือลำดับของคอลัมน์เปลี่ยนไปในตารางค่อนข้างบ่อยซึ่งมักจะทำให้ select select แตกต่างกันมาก ดังนั้นการออกรายการคอลัมน์เป็นทางออกที่ถูกต้อง

สำหรับวิธีการทำแบบสอบถามของคุณไม่แน่ใจเกี่ยวกับ mysql แต่ใน sqlserver คุณสามารถเลือกชื่อคอลัมน์จาก syscolumns และสร้างประโยคที่เลือกแบบไดนามิก


ชี้ไปที่ แต่ในบริบทของฉันฉันต้องการสิ่งทั่วไปและแบบไดนามิกดังนั้นในความเป็นจริงรหัสของฉันจะปรับให้เข้ากับคอลัมน์ใหม่ที่เพิ่ม / เรียงลำดับใหม่ / ฯลฯ ฉันไม่ต้องการรายการคอลัมน์ทีละรายการ
foxdonut

5
การเลือกจาก syscolumns ไปยังการสร้างคำสั่ง select แบบไดนามิกนั้นเป็นการแฮ็คที่แย่มากและฉันจะไม่แนะนำในการผลิต
Juliet

0

หากกังวลเกี่ยวกับการเปลี่ยนแปลงสกีมาสิ่งนี้อาจใช้ได้สำหรับคุณ: 1. เรียกใช้คิวรี 'DESCRIBE' ในทุกตารางที่เกี่ยวข้อง 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 */

สังเกตช่องต่างๆ: แคตตาล็อกโต๊ะ org_name

ตอนนี้คุณรู้ว่าเขตข้อมูลใดใน SQL ของคุณเป็นของ schema (aka แคตตาล็อก) และตาราง นี่เป็นการเพียงพอที่จะระบุแต่ละฟิลด์โดยทั่วไปจากคิวรี 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 เพราะไม่รองรับการใช้

โปรดแสดงความคิดเห็นหากคุณสามารถทดสอบ / แก้ไขรหัสนี้สำหรับ 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คืนค่าโดยไดรเวอร์ของฉัน แต่ควรเปลี่ยนได้ง่ายสำหรับไดรเวอร์ DB อื่น ๆ ):

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 ฉันมีคอลัมน์

จากนั้นใช้ concatanate ในคอลัมน์ e และรวมเข้าด้วยกันเพื่อให้แน่ใจว่ามีช่องว่าง จากนั้นตัดและวางสิ่งนี้ลงในรหัส 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'));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.