SQL select join : 모든 열의 접두어를 'prefix. *'로 지정할 수 있습니까?


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 ','name ','some_id '. 모든 열을 개별적으로 나열하지 않고 테이블 B의 열 이름 앞에 접두어를 넣을 방법이 있습니까? 이것과 동등합니다 :

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

그러나 언급했듯이 모든 열을 나열하지 않으면 다음과 같습니다.

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

기본적으로 "b. *에 의해 반환 된 모든 열 앞에 'something"을 붙입니다. " 이것이 가능합니까, 아니면 운이 없습니까?

도움을 주셔서 감사합니다.

편집 : SELECT *를 사용하지 않는 것에 대한 조언은 유효한 조언이지만 내 상황과 관련이 없으므로 당면 문제를 고수하십시오-접두사 (SQL 쿼리에 지정된 상수)를 모든에 추가 할 수 있습니까? 조인에서 테이블의 열 이름?

편집 : 내 궁극적 인 목표는 조인으로 두 테이블에서 SELECT *를 수행하고 결과 세트에있는 열의 이름, 테이블 A에서 가져온 열 및 가져온 열을 알 수있는 것입니다. 다시, 나는 열을 개별적으로 나열하고 싶지 않고 SELECT *를 수행 할 수 있어야합니다.


쿼리 결과가 정확히 무엇을 기대합니까? 혼란스러워
GregD

GregD : b. *에서 나오는 모든 열 이름에 내가 지정한 상수를 접두어로 사용하고 싶습니다. 예를 들어 'name'과 'number'대신 'special_'접두사를 지정하고 'special_name'과 'special_number'를 가져오고 싶습니다. 그러나 각 열마다 개별적 으로이 작업을 수행하고 싶지 않습니다.
foxdonut

6
여러 테이블의 열을보기 위해 빠른 SELECT를 수행 할 때 때때로 SELECT 'AAAAA', A. *, 'BBBBB', B. * FROM TableA AS A JOIN TableB AS B ON A.ID = B.ID 행을 따라 스캔 할 때 적어도 테이블 식별자가 있습니다.
Kristen

답변:


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

나는 이것이 왜 필요한지 완전히 이해합니다. 적어도 나에게는 많은 내부 조인을 포함하여 많은 테이블을 조인해야 할 때 신속한 프로토 타이핑 중에 편리합니다. 두 번째 "joinedtable. *"필드 와일드 카드에서 열 이름이 동일하면 기본 테이블의 필드 값이 결합 가능한 값으로 대체됩니다. 별칭이 여러 번인 테이블 필드를 수동으로 지정해야 할 경우 오류가 발생하기 쉽고 좌절하며 DRY 위반이 발생합니다.

다음은 코드 생성을 통해이를 사용하는 예제와 함께 PHP (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

내가 아는 유일한 데이터베이스는 PRAGMA full_column_namesand로 구성한 설정에 따라 SQLite PRAGMA short_column_names입니다. http://www.sqlite.org/pragma.html을 참조 하십시오

그렇지 않으면 쿼리에 열 이름을 입력하기가 너무 어려운 경우 열 이름이 아닌 서수 위치로 결과 집합에서 열을 가져 오는 것이 좋습니다.

이것은 왜 나쁜 습관을 쓰는지에SELECT * 대한 좋은 예입니다. 결국 모든 열 이름을 입력해야하기 때문입니다.

이름이나 위치가 변경 될 수있는 열을 지원해야한다는 것을 알고 있지만 와일드 카드를 사용하면 더 어렵고 어렵지 않습니다.


2
모두 참고 full_column_names하고이 short_column_names되어 사용되지 않는 SQLite는에.
isanae

6

나는 OP와 같은 종류의 보트에 있습니다 .3 개의 다른 테이블에서 수십 개의 필드가 있습니다. 일부 이름은 같은 이름 (예 : id, name 등)입니다. 각 필드를 나열하고 싶지 않기 때문에 내 솔루션은 이름을 공유하는 필드의 별칭을 지정하고 고유 이름을 가진 필드에 select *를 사용하는 것이 었습니다.

예를 들면 다음과 같습니다.

표 a : id, 이름, field1, field2 ...

표 b : 아이디, 이름, field3, field4 ...

a.id를 aID로, a.name을 aName으로, a. *, b.id는 bID, b. 이름은 bName, b. * .....

결과에 액세스 할 때이 필드의 별명을 사용하고 "원래"이름은 무시합니다.

어쩌면 가장 좋은 해결책은 아니지만 그것은 나를 위해 작동합니다 .... mysql을 사용합니다.


5

다른 데이터베이스 제품은 다른 답변을 제공합니다. 그러나 당신이 이것을 아주 멀리 가지고 다니면 스스로 상처를 입게됩니다. 원하는 열을 선택하고 별명을 지정하여 각 열의 ID가 명확하고 결과에서 구별 할 수있는 것이 훨씬 좋습니다.


1
요점을 취했지만 여기에 내 목표는 매우 일반적인 것이므로 명시 적이 지 않은 것은 문제가되지 않습니다. 실제로 구체적 이어야하는 것은 문제 될 수 있습니다.
foxdonut

아래의 추가 제출을 참조하십시오. dot.notation을 사용할 수 있습니까, 아마도 기본값이 될 것입니까?
dkretz 2018

가독성에 중요합니다. 나는 CTE 프로세스를 잘 알고 있기 때문에 지금이 일을하기를 바랐다. 전의. CTE_A-> CTE_B-> CTE_C-> CTE_D-> 선택 / 삽입 최종 select 문과 성능을 고려하지 않을 때까지 원하는 열을 지정할 필요가 없습니다.
ThomasRones

5

이 질문은 실제로 매우 유용합니다. 모든 조건을 처리하기 위해 특히주의를 기울이는 소프트웨어 프로그래밍의 모든 명시 적 열만 나열하면됩니다.

디버깅 할 때 또는 특정 프로그래머의 추상 기반 인프라를 변경할 수있는 구현 대신 DBMS를 일일 사무 도구로 사용하려고한다고 상상해보십시오. 많은 SQL을 코딩해야합니다. 이 시나리오는 데이터베이스 변환, 마이그레이션, 관리 등과 같은 모든 곳에서 찾을 수 있습니다. 이러한 SQL의 대부분은 한 번만 실행되고 다시 사용되지 않으며 모든 열 이름은 시간 낭비입니다. 그리고 프로그래머가 사용할 수있는 것은 SQL 발명이 아닙니다.

일반적으로 열 이름이 접두사로 유틸리티 뷰를 작성합니다. 여기 pl / pgsql의 함수가 있습니다. 쉽지는 않지만 다른 프로 시저 언어로 변환 할 수 있습니다.

-- Create alias-view for specific table.

create or replace function mkaview(schema varchar, tab varchar, prefix varchar)
    returns table(orig varchar, alias varchar) as $$
declare
    qtab varchar;
    qview varchar;
    qcol varchar;
    qacol varchar;
    v record;
    sql varchar;
    len int;
begin
    qtab := '"' || schema || '"."' || tab || '"';
    qview := '"' || schema || '"."av' || prefix || tab || '"';
    sql := 'create view ' || qview || ' as select';

    for v in select * from information_schema.columns
            where table_schema = schema and table_name = tab
    loop
        qcol := '"' || v.column_name || '"';
        qacol := '"' || prefix || v.column_name || '"';

        sql := sql || ' ' || qcol || ' as ' || qacol;
        sql := sql || ', ';

        return query select qcol::varchar, qacol::varchar;
    end loop;

    len := length(sql);
    sql := left(sql, len - 2); -- trim the trailing ', '.
    sql := sql || ' from ' || qtab;

    raise info 'Execute SQL: %', sql;
    execute sql;
end
$$ language plpgsql;

예 :

-- This will create a view "avp_person" with "p_" prefix to all column names.
select * from mkaview('public', 'person', 'p_');

select * from avp_person;

3

중복 된 필드 이름에 대한 문제를 완전히 이해합니다.

그것을 해결하기 위해 내 자신의 함수를 코딩 할 때까지 나도 필요했습니다. PHP를 사용하는 경우 다음 기능이있는 경우 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
다른 테이블의 열 이름이 동일하지만 동일한 값을 포함하지 않는 경우가 있습니다. 따라서 뷰 또는 파생 테이블 (모든 고유 열 이름을 가져야 함)에서 구별하기 위해 접두사를 붙여야합니다.
Cade Roux 2018

@ Frederic, 코드는 어딘가에 살아야합니다. 이것은 코드를 생성합니다. 다시 말하지만, 개발 중에 한 번 또는 런타임에 동적으로 수행 할 수 있습니다.
Cade Roux 2018

1

이것을 재사용 할 수있게 만드는 두 가지 방법이 있습니다. 하나는 모든 열의 이름을 테이블의 접두사로 바꾸는 것입니다. 나는 이것을 여러 번 보았지만 정말로 그것을 좋아하지 않는다. 중복되어 많은 타이핑이 발생하며 출처가 분명하지 않은 열 이름의 경우를 다루어야 할 때 항상 별칭을 사용할 수 있습니다.

다른 방법으로, 이것을 보겠다고 약속하면 상황에서 권장하는 방법은 테이블 이름의 별명을 갖는 각 테이블에 대한보기를 작성하는 것입니다. 그런 다음 테이블이 아닌 해당 뷰에 대해 조인합니다. 이렇게하면 원하는 경우 *를 자유롭게 사용할 수 있고 원하는 경우 원래 열 이름을 가진 원래 테이블을 자유롭게 사용할 수 있으며 뷰에서 이름 바꾸기 작업을 이미 완료했기 때문에 후속 쿼리를보다 쉽게 ​​작성할 수 있습니다.

마지막으로, 각 열이 어느 테이블에서 왔는지 알아야하는 이유가 확실하지 않습니다. 이 문제가 중요합니까? 궁극적으로 중요한 것은 포함 된 데이터입니다. UserID가 User 테이블에서 왔는지 UserQuestion 테이블에서 왔는지 여부는 실제로 중요하지 않습니다. 물론 업데이트해야 할 때 중요하지만 그 시점에서 스키마를 충분히 파악해야합니다.


"마지막으로, 각 열이 어느 테이블에서 왔는지 알아야하는 이유가 확실하지 않습니다.이 문제가 중요합니까?" <-11 년 후, 하나의 유스 케이스는 Go에서 struct 스캐닝입니다.
리 벤슨

1

또는 Red Gate SQL Refactor 또는 SQL Prompt를 사용하여 탭 버튼을 클릭하여 SELECT *를 열 목록으로 확장 할 수 있습니다.

따라서 귀하의 경우, SELECT * FROM A JOIN B ...를 입력하면 *, Tab 버튼, voila의 끝으로 이동하십시오! SELECT A.column1, A.column2, ...., B.column1, B.column2 FROM A JOIN B에서

그래도 무료는 아닙니다


1

Cant는 aliasing없이 이것을 수행합니다. 간단히 말해서 조인중인 2 개 또는 3 개의 테이블에 해당 필드가있는 경우 where 절에서 필드를 어떻게 참조합니까? 참조하려는 mysql에 대해서는 명확하지 않습니다.


1

관련 테이블의 필드 이름을 바꾸어 비슷한 문제를 해결했습니다. 그렇습니다, 나는 이것을하는 특권을 가졌으며 모든 사람이 그것을 할 수 없다는 것을 이해합니다. 테이블 이름을 나타내는 테이블 내의 각 필드에 접두사를 추가했습니다. 따라서 OP에 의해 게시 된 SQL은 변경되지 않습니다.

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

출력 필드가 속한 테이블을 쉽게 식별 할 수 있습니다.


0

새 열이 추가되는 경향이 있거나 테이블에서 열 순서가 자주 변경되어 select가 매우 미묘한 방식으로 손상되기 때문에 select *는 일반적으로 잘못된 코드를 만듭니다. 따라서 열을 나열하는 것이 올바른 솔루션입니다.

쿼리를 수행하는 방법에 대해서는 mysql에 대해 확실하지 않지만 sqlserver에서는 syscolumns에서 열 이름을 선택하고 select 절을 동적으로 작성할 수 있습니다.


포인트를 취했지만 내 상황에서는 일반적이고 역동적 인 것이 필요하므로 실제로 내 코드는 추가 / 재정렬 등의 새로운 열에 적응합니다. 열을 개별적으로 나열하고 싶지 않습니다.
foxdonut

5
동적으로 select 문을 작성하기 위해 syscolumns에서 선택하는 것은 끔찍한 해킹이므로 프로덕션에서는 권장하지 않습니다.
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 */

catalog, table, org_name 필드를 확인하십시오.

이제 SQL의 어떤 필드가 어떤 스키마 (카탈로그) 및 테이블에 속하는지 알 수 있습니다. 이것은 별명을 지정할 필요없이 다중 테이블 SQL 쿼리에서 각 필드를 일반적으로 식별하기에 충분합니다.

실제 제품 SqlYOG는 PK 필드가있을 때 다중 테이블 조인의 각 테이블을 독립적으로 업데이트 할 수있는 매너에서이 정확한 데이터를 사용하는 것으로 표시됩니다.


0

이 솔루션 에서 개발하면 다음과 같이 문제에 접근합니다.

먼저 모든 AS문장 목록을 작성하십시오.

DECLARE @asStatements varchar(8000)

SELECT @asStatements = ISNULL(@asStatements + ', ','') + QUOTENAME(table_name) + '.' + QUOTENAME(column_name) + ' AS ' + '[' + table_name + '.' + column_name + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TABLE_A' OR TABLE_NAME = 'TABLE_B'
ORDER BY ORDINAL_POSITION

그런 다음 쿼리에서 사용하십시오.

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

그러나 SQL Server에서만 유사한 항목이 테스트되므로 수정이 필요할 수 있습니다. 그러나 USING이 지원되지 않기 때문에이 코드는 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에 붙여 넣습니다. 그런 다음 열을 둘러싸는 데 필요한 코드를 작성하십시오. 여러 열로 이전해야한다고 가정 해보십시오. 열에는 필드가 있고 열 B에는 "prev_"로, 열 c에는 다시 필드가 있습니다. 열 d에는 열이 있습니다.

그런 다음 e 열에 연결을 사용하고 공백을 포함하여 함께 병합하십시오. 그런 다음 이것을 잘라서 SQL 코드에 붙여 넣으십시오. 또한이 방법을 사용하여 수백 개의 필드 테이블의 각 필드에 대해 동일한 필드 및 기타 더 긴 코드에 대한 사례 진술을 작성했습니다.


0

postgres에서 json 함수를 사용하여 대신 json 객체를 반환합니다 .... 그런 다음 쿼리 후 _json 접미어로 필드를 json_decode합니다.

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.