SQL chọn tham gia: có thể đặt tiền tố cho tất cả các cột dưới dạng 'tiền tố. *'?


206

Tôi tự hỏi nếu điều này là có thể trong SQL. Giả sử bạn có hai bảng A và B và bạn chọn một bảng trên bảng A và tham gia vào bảng B:

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

Nếu bảng A có các cột 'a_id', 'name' và 'some_id' và bảng B có 'b_id', 'name' và 'some_id', truy vấn sẽ trả về các cột 'a_id', 'name', 'some_id ',' b_id ',' tên ',' some_id '. Có cách nào để thêm tiền tố vào tên cột của bảng B mà không liệt kê từng cột riêng lẻ không? Tương đương với điều này:

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

Nhưng, như đã đề cập, không liệt kê mỗi cột, vì vậy một cái gì đó như:

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

Về cơ bản một cái gì đó để nói, "tiền tố mỗi cột được trả về bởi b. * Với 'cái gì đó" ". Điều này có thể hay tôi hết may mắn?

Cảm ơn trước sự giúp đỡ của bạn!

EDIT: lời khuyên về việc không sử dụng SELECT * và vv là lời khuyên hợp lệ nhưng không liên quan trong ngữ cảnh của tôi, vì vậy vui lòng xử lý vấn đề trong tay - có thể thêm tiền tố (hằng số được chỉ định trong truy vấn SQL) cho tất cả tên cột của một bảng trong một tham gia?

EDIT: mục tiêu cuối cùng của tôi là có thể thực hiện CHỌN * trên hai bảng bằng cách nối và có thể cho biết, từ tên của các cột tôi nhận được trong tập kết quả của mình, cột nào xuất phát từ bảng A và cột nào xuất hiện từ bảng B. Một lần nữa, tôi không muốn phải liệt kê các cột riêng lẻ, tôi cần có thể thực hiện CHỌN *.


Chính xác thì bạn mong đợi kết quả của truy vấn của bạn là gì? Tôi đang bối rối
GregD

GregD: Tôi muốn tất cả các tên cột xuất phát từ b. * Được thêm tiền tố với một số hằng số mà tôi chỉ định. Ví dụ: thay vì 'tên' và 'số', tôi muốn chỉ định, giả sử, tiền tố 'Special_' và nhận 'Special_name' và 'Special_number'. Nhưng tôi không muốn làm điều này cho từng cột riêng lẻ.
foxdonut

6
Khi tôi thực hiện CHỌN nhanh để xem các cột từ nhiều bảng, đôi khi tôi thực hiện CHỌN 'AAAAA', A. *, 'BBBBB', B. * TỪ TableA NHƯ MỘT Bảng THAM GIA B ONNG A.ID = B.ID để tôi ít nhất có một mã định danh bảng khi quét dọc theo các hàng
Kristen

Bản sao có thể có: stackoverflow.com/questions/2595068/
Khắc

Câu trả lời:


35

Tôi thấy hai tình huống có thể xảy ra ở đây. Đầu tiên, bạn muốn biết liệu có một tiêu chuẩn SQL cho việc này hay không, mà bạn có thể sử dụng nói chung bất kể cơ sở dữ liệu. Không có. Thứ hai, bạn muốn biết liên quan đến một sản phẩm dbms cụ thể. Sau đó, bạn cần xác định nó. Nhưng tôi tưởng tượng câu trả lời rất có thể là bạn sẽ nhận lại được một cái gì đó như "a.id, b.id" vì đó là cách bạn cần xác định các cột trong biểu thức SQL của mình. Và cách dễ nhất để tìm ra mặc định là gì, chỉ cần gửi một truy vấn như vậy và xem những gì bạn nhận lại. Nếu bạn muốn chỉ định tiền tố nào xuất hiện trước dấu chấm, bạn có thể sử dụng "CHỌN * TỪ AS my_alias".


11
Tôi không chắc làm thế nào điều này trả lời câu hỏi của bạn. Tôi đang sử dụng MS SQL Server và thêm một bí danh sau khi tên bảng không nối thêm bí danh vào các tên cột trong tập kết quả.
paiego 04/11/2015

74

Có vẻ như câu trả lời cho câu hỏi của bạn là không, tuy nhiên một cách hack bạn có thể sử dụng là gán một cột giả để tách từng bảng mới. Điều này đặc biệt hiệu quả nếu bạn lặp qua một tập kết quả cho một danh sách các cột bằng ngôn ngữ kịch bản như Python hoặc 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

Tôi nhận ra điều này không trả lời chính xác câu hỏi của bạn, nhưng nếu bạn là một lập trình viên thì đây là một cách tuyệt vời để tách các bảng có tên cột trùng lặp. Hy vọng điều này sẽ giúp ai đó.


24

Tôi hoàn toàn hiểu tại sao điều này lại cần thiết - ít nhất là đối với tôi, nó rất tiện lợi trong quá trình tạo mẫu nhanh khi có rất nhiều bảng cần thiết được nối, bao gồm nhiều phép nối bên trong. Ngay sau khi một tên cột giống nhau trong thẻ đại diện trường "có thể tham gia. *" Thứ hai, các giá trị trường của bảng chính sẽ được ghi đè bằng các giá trị có thể nối được. Dễ bị lỗi, bực bội và vi phạm DRY khi phải chỉ định thủ công các trường bảng với các bí danh lặp đi lặp lại ...

Đây là một hàm PHP (Wordpress) để đạt được điều này thông qua việc tạo mã cùng với một ví dụ về cách sử dụng nó. Trong ví dụ này, nó được sử dụng để nhanh chóng tạo một truy vấn tùy chỉnh sẽ cung cấp các trường của một bài đăng wordpress có liên quan được tham chiếu thông qua trường tùy chỉnh nâng cao .

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

Đầu ra:

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

Cơ sở dữ liệu duy nhất tôi biết thực hiện điều này là SQLite, tùy thuộc vào cài đặt bạn định cấu hình PRAGMA full_column_namesPRAGMA short_column_names. Xem http://www.sqlite.org/pragma.html

Mặt khác, tất cả những gì tôi có thể khuyên là tìm nạp các cột trong kết quả được đặt theo vị trí thứ tự thay vì theo tên cột, nếu bạn gặp quá nhiều khó khăn khi nhập tên của các cột trong truy vấn của mình.

Đây là một ví dụ tốt về lý do tại sao nó sử dụng thực tiễn xấuSELECT * - bởi vì cuối cùng bạn sẽ có nhu cầu gõ tất cả các tên cột.

Tôi hiểu sự cần thiết phải hỗ trợ các cột có thể thay đổi tên hoặc vị trí, nhưng sử dụng ký tự đại diện làm cho việc đó khó hơn , không dễ dàng hơn.


2
Lưu ý rằng cả hai full_column_nameskhôngshort_column_names được dùng trong SQLite.
isanae

6

Tôi thuộc cùng loại thuyền với OP - Tôi có hàng tá lĩnh vực từ 3 bảng khác nhau mà tôi tham gia, một số trong đó có cùng tên (ví dụ: id, name, v.v.). Tôi không muốn liệt kê từng trường, vì vậy giải pháp của tôi là bí danh những trường có chung tên và sử dụng select * cho những trường có tên duy nhất.

Ví dụ :

bảng a: id, tên, trường1, trường2 ...

bảng b: id, tên, trường3, trường4 ...

chọn a.id làm aID, a.name làm aName, a. *, b.id là bID, b.name là bName, b. * .....

Khi truy cập kết quả, chúng tôi đặt tên bí danh cho các trường này và bỏ qua tên "gốc".

Có thể không phải là giải pháp tốt nhất nhưng nó hiệu quả với tôi .... Tôi đang sử dụng mysql


5

Các sản phẩm cơ sở dữ liệu khác nhau sẽ cung cấp cho bạn các câu trả lời khác nhau; nhưng bạn đang tự làm tổn thương mình nếu bạn mang điều này đi rất xa. Tốt hơn hết là bạn nên chọn các cột bạn muốn và đặt cho chúng các bí danh của riêng bạn để danh tính của mỗi cột rõ ràng và bạn có thể phân biệt chúng trong các kết quả.


1
Điểm lấy, nhưng mục tiêu của tôi ở đây là một cái gì đó rất chung chung, vì vậy không rõ ràng không phải là một vấn đề. Trong thực tế, phải được cụ thể sẽ là một vấn đề.
foxdonut

Xem thêm trình dưới đây. Có thể sử dụng dot.notation, đây có thể là những gì bạn sẽ được mặc định?
dkretz

Nó quan trọng đối với khả năng đọc. Tôi đã hy vọng thực hiện điều này ngay bây giờ vì tôi có một quy trình CTE được xử lý. Ví dụ. CTE_A -> CTE_B -> CTE_C -> CTE_D -> select / insert Không cần chỉ định các cột tôi muốn cho đến khi tuyên bố chọn cuối cùng và hiệu suất không được xem xét.
ThomasRones

5

Câu hỏi này rất hữu ích trong thực tế. Chỉ cần liệt kê mọi cột rõ ràng trong lập trình phần mềm, nơi bạn đặc biệt cẩn thận để xử lý mọi điều kiện.

Hãy tưởng tượng khi gỡ lỗi, hoặc, cố gắng sử dụng DBMS làm công cụ văn phòng hàng ngày, thay vì triển khai cơ sở hạ tầng cơ bản trừu tượng của lập trình viên cụ thể, chúng ta cần mã hóa rất nhiều SQL. Kịch bản có thể được tìm thấy ở mọi nơi, như chuyển đổi cơ sở dữ liệu, di chuyển, quản trị, v.v. Hầu hết các SQL này sẽ chỉ được thực thi một lần và không bao giờ được sử dụng lại, cho mỗi tên cột chỉ là lãng phí thời gian. Và đừng quên việc phát minh ra SQL không chỉ dành cho các lập trình viên sử dụng.

Thông thường tôi sẽ tạo ra một khung nhìn tiện ích với các tên cột có tiền tố, đây là hàm trong pl / pssql, nó không dễ dàng nhưng bạn có thể chuyển đổi nó sang các ngôn ngữ thủ tục khác.

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

Ví dụ:

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

Tôi hoàn toàn hiểu vấn đề của bạn về tên trường trùng lặp.

Tôi cũng cần điều đó cho đến khi tôi mã hóa chức năng của chính mình để giải quyết nó. Nếu bạn đang sử dụng PHP, bạn có thể sử dụng nó hoặc mã của bạn bằng ngôn ngữ bạn đang sử dụng nếu bạn có các phương tiện sau đây.

Mẹo ở đây là mysql_field_table()trả về tên bảng và mysql_field_name()trường cho mỗi hàng trong kết quả nếu nó có mysql_num_fields()để bạn có thể trộn chúng trong một mảng mới.

Tiền tố này tất cả các cột;)

Trân trọng,

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

Không có tiêu chuẩn SQL cho việc này.

Tuy nhiên Với việc tạo mã (theo yêu cầu khi các bảng được tạo hoặc thay đổi hoặc trong thời gian chạy), bạn có thể thực hiện việc này khá dễ dàng:

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)

Điều này sẽ làm việc nhưng câu hỏi là khá ngớ ngẩn. tại sao không chỉ thực hiện một liên minh hoặc truy vấn phụ. Tại sao bạn tham gia và vẫn muốn tiền tố bảng trong tên cột?
D3vtr0n

Cade: cảm ơn thông tin, đó là thú vị. Thật không may, tạo / thay đổi cơ sở dữ liệu không phải là một lựa chọn trong trường hợp của tôi. Devtron: nếu bạn đang cố gắng ánh xạ thông tin quay lại từ một truy vấn đến các thuộc tính khác nhau của một đối tượng, thông tin đó sẽ trở nên rất hữu ích.
foxdonut

1
Đôi khi tên cột trong các bảng khác nhau là giống nhau, nhưng không chứa cùng một giá trị. Do đó, cần phải thêm tiền tố vào chúng để phân biệt chúng trong các khung nhìn hoặc các bảng dẫn xuất (phải có tất cả các tên cột duy nhất).
Cade Roux

@Frederic, mã của bạn phải sống ở đâu đó - điều này chỉ tạo mã. Một lần nữa, điều này có thể được thực hiện một lần trong quá trình phát triển hoặc tự động khi chạy.
Cade Roux

1

Có hai cách tôi có thể nghĩ ra để làm cho điều này xảy ra theo cách có thể sử dụng lại. Một là đổi tên tất cả các cột của bạn bằng tiền tố cho bảng mà chúng xuất phát. Tôi đã thấy điều này nhiều lần, nhưng tôi thực sự không thích nó. Tôi thấy rằng nó dư thừa, gây ra nhiều thao tác gõ và bạn luôn có thể sử dụng bí danh khi bạn cần bao gồm trường hợp tên cột có nguồn gốc không rõ ràng.

Một cách khác, mà tôi muốn khuyên bạn nên làm trong tình huống của mình nếu bạn cam kết nhìn thấy điều này thông qua, là tạo các khung nhìn cho mỗi bảng có bí danh tên bảng. Sau đó, bạn tham gia chống lại những quan điểm đó, chứ không phải là các bảng. Bằng cách đó, bạn có thể tự do sử dụng * nếu bạn muốn, miễn phí sử dụng các bảng gốc với tên cột ban đầu nếu bạn muốn và nó cũng giúp viết bất kỳ truy vấn tiếp theo nào dễ dàng hơn vì bạn đã thực hiện công việc đổi tên trong chế độ xem.

Cuối cùng, tôi không rõ lý do tại sao bạn cần biết mỗi cột xuất phát từ bảng nào. Có vấn đề này? Cuối cùng, những gì quan trọng là dữ liệu họ chứa. Cho dù UserID đến từ bảng Người dùng hay bảng UserQuestion không thực sự quan trọng. Tất nhiên, vấn đề là khi bạn cần cập nhật nó, nhưng tại thời điểm đó bạn đã biết rõ lược đồ của mình đủ để xác định điều đó.


"Cuối cùng, tôi không rõ lý do tại sao bạn cần biết mỗi cột xuất phát từ bảng nào. Điều này có quan trọng không?" <- 11 năm sau, một trường hợp sử dụng là quét cấu trúc trong Go.
Lee Benson

1

Hoặc bạn có thể sử dụng Red Gate SQL Refactor hoặc SQL Prompt, mở rộng CHỌN * của bạn vào danh sách cột chỉ bằng một cú nhấp chuột vào nút Tab

vì vậy, trong trường hợp của bạn, nếu bạn gõ CHỌN * TỪ MỘT THAM GIA B ... Đi đến cuối *, nút Tab, thì đấy! bạn sẽ thấy CHỌN A.column1, A.column2, ...., B.column1, B.column2 TỪ MỘT THAM GIA B

Nó không miễn phí mặc dù


1

Không thể làm điều này mà không có bí danh, đơn giản là vì, bạn sẽ tham chiếu một trường trong mệnh đề where như thế nào, nếu trường đó tồn tại trong 2 hoặc 3 bảng bạn đang tham gia? Sẽ không rõ ràng cho mysql mà bạn đang cố gắng tham khảo.


1

Tôi đã giải quyết một vấn đề tương tự của tôi bằng cách đổi tên các trường trong các bảng liên quan. Vâng, tôi có đặc quyền làm điều này và hiểu rằng mọi người có thể không có nó. Tôi đã thêm tiền tố vào mỗi trường trong một bảng biểu thị tên bảng. Do đó, SQL được đăng bởi OP sẽ không thay đổi -

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

và vẫn đưa ra kết quả mong đợi - dễ dàng xác định các trường đầu ra thuộc về bảng nào.


0

select * thường làm cho mã xấu, vì các cột mới có xu hướng được thêm vào hoặc thứ tự các cột thay đổi trong các bảng khá thường xuyên, thường phá vỡ select * theo một cách rất tinh tế. Vì vậy, liệt kê ra các cột là giải pháp đúng.

Về cách thực hiện truy vấn của bạn, không chắc chắn về mysql nhưng trong sqlserver, bạn có thể chọn tên cột từ syscolumns và tự động xây dựng mệnh đề chọn.


Điểm lấy, nhưng trong ngữ cảnh của tôi, tôi cần một cái gì đó chung chung và năng động, vì vậy trên thực tế, mã của tôi sẽ thích ứng với các cột mới được thêm / sắp xếp lại / v.v. Tôi không muốn phải liệt kê các cột riêng lẻ.
foxdonut

5
Chọn từ syscolumn để tự động xây dựng một câu lệnh chọn là một hack khủng khiếp và tôi sẽ không đề xuất nó trong sản xuất.
Juliet

0

Nếu lo ngại về các thay đổi lược đồ, điều này có thể phù hợp với bạn: 1. Chạy truy vấn 'bảng MÔ TẢ' trên tất cả các bảng có liên quan. 2. Sử dụng tên trường được trả về để tự động xây dựng một chuỗi tên cột có tiền tố với bí danh bạn đã chọn.


0

Có một câu trả lời trực tiếp cho câu hỏi của bạn cho những người sử dụng API C-API của MySQL.

Đưa ra SQL:

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

Các kết quả từ 'mysql_stmt_result_metadata ()' đưa ra định nghĩa về các trường của bạn từ truy vấn SQL đã chuẩn bị của bạn vào cấu trúc MYSQL_FIELD []. Mỗi trường chứa dữ liệu sau:

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

Hãy chú ý các trường: danh mục, bảng, org_name

Bây giờ bạn biết các trường trong SQL của bạn thuộc về lược đồ nào (còn gọi là danh mục) và bảng. Điều này là đủ để xác định chung từng trường từ một truy vấn sql nhiều bảng, mà không phải bí danh bất cứ điều gì.

Một sản phẩm thực tế SqlYOG được hiển thị để sử dụng dữ liệu chính xác này trong một trang viên sao cho chúng có thể cập nhật độc lập từng bảng của một phép nối nhiều bảng, khi có các trường PK.


0

Phát triển từ giải pháp này , đây là cách tôi sẽ tiếp cận vấn đề:

Đầu tiên tạo một danh sách tất cả các AScâu lệnh:

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

Sau đó sử dụng nó trong truy vấn của bạn:

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

Tuy nhiên, điều này có thể cần sửa đổi vì một cái gì đó tương tự chỉ được thử nghiệm trong SQL Server. Nhưng mã này không hoạt động chính xác trong SQL Server vì USING không được hỗ trợ.

Vui lòng bình luận nếu bạn có thể kiểm tra / sửa mã này cho ví dụ MySQL.


0

Gần đây đã gặp phải vấn đề này trong NodeJS và Postgres.

Cách tiếp cận ES6

Không có bất kỳ tính năng RDBMS nào tôi biết cung cấp chức năng này, vì vậy tôi đã tạo một đối tượng chứa tất cả các trường của mình, ví dụ:

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

Xác định một bộ giảm để nối các chuỗi với nhau bằng tên bảng:

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

Điều này trả về một chuỗi các chuỗi. Gọi nó cho mỗi bảng và kết hợp các kết quả:

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

Xuất câu lệnh SQL cuối cùng:

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

Không đời nào! Đó là một số SQL SQL bị hack và không hoạt động với các biểu thức.
ratijas

0

Tôi đã triển khai một giải pháp dựa trên câu trả lời gợi ý sử dụng các cột giả hoặc sentinel trong nút. Bạn sẽ sử dụng nó bằng cách tạo SQL như:

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

Và sau đó xử lý hậu kỳ hàng bạn nhận lại từ trình điều khiển cơ sở dữ liệu của bạn như thế nào addPrefixes(row).

Việc triển khai (dựa trên fields/ được rowstrả về bởi trình điều khiển của tôi, nhưng phải dễ thay đổi đối với các trình điều khiển DB khác):

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
}

Kiểm tra:

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

Những gì tôi làm là sử dụng Excel để nối thủ tục. Chẳng hạn, đầu tiên tôi chọn * và lấy tất cả các cột, dán chúng vào Excel. Sau đó viết mã tôi cần bao quanh cột. Nói rằng tôi cần phải quảng cáo trước một loạt các cột. Tôi có các trường của mình trong một cột và "as trước_" trong cột B và các trường của tôi lại ở cột c. Trong cột d tôi sẽ có một cột.

Sau đó sử dụng concatanate trong cột e và hợp nhất chúng lại với nhau, đảm bảo bao gồm các khoảng trắng. Sau đó cắt và dán mã này vào mã sql của bạn. Tôi cũng đã sử dụng phương pháp này để tạo báo cáo trường hợp cho cùng một trường và các mã dài hơn khác mà tôi cần thực hiện cho từng trường trong bảng nhiều trường.


0

Trong postgres, tôi sử dụng các hàm json để thay vào đó trả về các đối tượng json .... sau đó, sau khi truy vấn, tôi json_decode các trường có hậu tố _json.

I E:

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

sau đó trong PHP (hoặc bất kỳ ngôn ngữ nào khác), tôi lặp qua các cột được trả về và json_decode () chúng nếu chúng có hậu tố "_json" (cũng loại bỏ hậu tố. Cuối cùng, tôi nhận được một đối tượng gọi là "tab1" bao gồm tất cả các trường tab1 và một trường khác gọi là "tab2" bao gồm tất cả các trường tab2.


-1

PHP 7.2 + MySQL / Mariadb

MySQL sẽ gửi cho bạn nhiều trường có cùng tên. Ngay cả trong máy khách đầu cuối. Nhưng nếu bạn muốn một mảng kết hợp, bạn sẽ phải tự tạo các phím.

Cảm ơn @axelbrz cho bản gốc. Tôi đã chuyển nó sang php mới hơn và dọn dẹp nó một chút:

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'));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.