Junção de seleção SQL: é possível prefixar todas as colunas como 'prefix. *'?

206

Gostaria de saber se isso é possível no SQL. Digamos que você tenha duas tabelas A e B e faça uma seleção na tabela A e participe da tabela B:

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

Se a tabela A tiver as colunas 'a_id', 'name' e 'some_id' e a tabela B tiver 'b_id', 'name' e 'some_id', a consulta retornará as colunas 'a_id', 'name', 'some_id ',' b_id ',' nome ',' some_id '. Existe alguma maneira de prefixar os nomes das colunas da tabela B sem listar todas as colunas individualmente? O equivalente a isso:

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

Mas, como mencionado, sem listar todas as colunas, algo como:

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

Basicamente, algo a dizer: "prefixe cada coluna retornada por b. * Com 'something'". Isso é possível ou estou sem sorte?

Agradeço antecipadamente por sua ajuda!

EDIT: conselhos sobre o não uso de SELECT * e assim por diante são conselhos válidos, mas não relevantes no meu contexto, portanto, atenha-se ao problema em questão - é possível adicionar um prefixo (uma constante especificada na consulta SQL) a todos os nomes de colunas de uma tabela em uma junção?

EDIT: meu objetivo final é poder fazer um SELECT * em duas tabelas com uma junção e ser capaz de distinguir, pelos nomes das colunas que recebo no meu conjunto de resultados, quais colunas vieram da tabela A e quais colunas vieram da tabela B. Novamente, não quero listar colunas individualmente, preciso poder fazer um SELECT *.

foxdonut
fonte
O que exatamente você espera que seja o resultado da sua consulta? Estou confuso
GregD 01/12/2008
GregD: Quero que todos os nomes de colunas que saem de b. * Sejam prefixados com alguma constante que eu especificar. Por exemplo, em vez de 'nome' e 'número', quero especificar, digamos, o prefixo 'special_' e obter 'special_name' e 'special_number'. Mas não quero fazer isso para cada coluna individualmente.
foxdonut
6
Quando faço uma SELECT rápida para ver colunas de várias tabelas, algumas vezes SELECT 'AAAAA', A. *, 'BBBBB', B. * FROM TableA COMO UMA JUNTA TableB AS B ON A.ID = B.ID para que eu ter pelo menos um identificador de tabela ao digitalizar ao longo das linhas
Kristen
Possível duplicata: stackoverflow.com/questions/2595068/…
Andrioid

Respostas:

35

Eu vejo duas situações possíveis aqui. Primeiro, você deseja saber se existe um padrão SQL para isso, que você pode usar em geral, independentemente do banco de dados. Não, não há. Segundo, você deseja saber sobre um produto dbms específico. Então você precisa identificá-lo. Mas imagino que a resposta mais provável é que você receberá algo como "a.id, b.id", pois é assim que você precisa identificar as colunas na sua expressão SQL. E a maneira mais fácil de descobrir qual é o padrão é enviar uma consulta e ver o que você recebe de volta. Se você deseja especificar qual prefixo vem antes do ponto, pode usar "SELECT * FROM a AS my_alias", por exemplo.

dkretz
fonte
11
Não tenho certeza de como isso responde à sua pergunta. Estou usando o MS SQL Server e adicionando um alias depois que o nome da tabela não anexa o alias aos nomes das colunas no conjunto de resultados.
paiego 4/11
74

Parece que a resposta para sua pergunta é não, no entanto, um truque que você pode usar é atribuir uma coluna fictícia para separar cada nova tabela. Isso funciona especialmente bem se você estiver percorrendo um conjunto de resultados para uma lista de colunas em uma linguagem de script como Python ou 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

Sei que isso não responde exatamente à sua pergunta, mas se você é um codificador, é uma ótima maneira de separar tabelas com nomes de colunas duplicados. Espero que isso ajude alguém.

Wayne Bryan
fonte
24

Entendo perfeitamente por que isso é necessário - pelo menos para mim é útil durante a prototipagem rápida, quando há muitas tabelas necessárias para unir, incluindo muitas junções internas. Assim que o nome de uma coluna é o mesmo em um segundo curinga do campo "tabela unida. *", Os valores do campo da tabela principal são substituídos pelos valores da tabela unida. Propenso a erros, frustrante e uma violação de DRY ao precisar especificar manualmente os campos da tabela com aliases repetidas vezes ...

Aqui está uma função PHP (Wordpress) para conseguir isso através da geração de código, juntamente com um exemplo de como usá-lo. No exemplo, é usado para gerar rapidamente uma consulta personalizada que fornecerá os campos de uma postagem relacionada do wordpress que foi referenciada através de um campo avançado de campos personalizados .

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

A saída:

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
        )
)
Motin
fonte
13

O único banco de dados que conheço que faz isso é o SQLite, dependendo das configurações definidas com PRAGMA full_column_namese PRAGMA short_column_names. Consulte http://www.sqlite.org/pragma.html

Caso contrário, tudo o que posso recomendar é buscar colunas em um conjunto de resultados pela posição ordinal, e não pelo nome da coluna, se for demais para você digitar os nomes das colunas na sua consulta.

Este é um bom exemplo de por que é uma má prática usarSELECT * - porque, eventualmente, você precisará digitar todos os nomes de colunas de qualquer maneira.

Entendo a necessidade de oferecer suporte a colunas que podem mudar de nome ou posição, mas o uso de curingas torna isso mais difícil , não mais fácil.

Bill Karwin
fonte
2
Observe que ambos full_column_namese short_column_namesestão obsoletos no SQLite.
Isanae 29/05
6

Estou no mesmo tipo de barco que o OP - tenho dezenas de campos de 3 tabelas diferentes às quais estou entrando, alguns dos quais têm o mesmo nome (por exemplo, id, nome, etc.). Como não quero listar cada campo, minha solução foi usar o alias dos campos que compartilhavam um nome e usar select * para aqueles que têm um nome exclusivo.

Por exemplo :

tabela a: id, nome, campo1, campo2 ...

tabela b: id, nome, campo3, campo4 ...

selecione a.id como aID, a.name como aName, a. *, b.id como lance, b.name como bName, b. * .....

Ao acessar os resultados, utilizamos os nomes alternativos desses campos e ignoramos os nomes "originais".

Talvez não seja a melhor solução, mas funciona para mim .... eu uso mysql


fonte
5

Produtos de banco de dados diferentes fornecerão respostas diferentes; mas você está se machucando se levar isso muito longe. É muito melhor escolher as colunas que deseja e dar a eles seus próprios aliases para que a identidade de cada coluna seja clara e você possa diferenciá-los nos resultados.

dkretz
fonte
1
Ponto de vista, mas meu objetivo aqui é algo muito genérico, portanto, não ser explícito não é um problema. De fato, ter que ser específico seria um problema.
foxdonut
Veja mais submissões abaixo. Pode usar use dot.notation, que provavelmente será o padrão?
Dkretz 01/12/2008
É importante para facilitar a leitura. Eu esperava fazer isso agora, porque tenho um processo CTE restrito. ex. CTE_A -> CTE_B -> CTE_C -> CTE_D -> selecionar / inserir Não há necessidade de especificar as colunas que eu quero até que a declaração e o desempenho final da seleção não sejam considerados.
ThomasRones
5

Esta questão é muito útil na prática. Só é necessário listar todas as colunas explícitas na programação de software, nas quais você deve ter cuidado especial ao lidar com todas as condições.

Imagine ao depurar ou, tente usar o DBMS como ferramenta diária de escritório, em vez de algo implementável na infraestrutura subjacente abstrata de um programador específico, precisamos codificar muitos SQLs. O cenário pode ser encontrado em qualquer lugar, como conversão de banco de dados, migração, administração, etc. A maioria desses SQLs será executada apenas uma vez e nunca mais será usada. Dê nomes a todas as colunas como perda de tempo. E não esqueça que a invenção do SQL não é apenas para uso dos programadores.

Normalmente, criarei uma exibição de utilitário com nomes de colunas prefixados; aqui está a função no pl / pgsql, não é fácil, mas você pode convertê-lo para outras linguagens de procedimentos.

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

Exemplos:

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

select * from avp_person;
Xiè Jìléi
fonte
3

Entendo perfeitamente o seu problema sobre nomes de campos duplicados.

Eu também precisava disso até codificar minha própria função para resolvê-la. Se você estiver usando PHP, poderá usá-lo ou codificar o seu no idioma para o qual está usando, se tiver os seguintes recursos.

O truque aqui é que mysql_field_table()retorna o nome da tabela e mysql_field_name()o campo para cada linha no resultado, se houver, mysql_num_fields()para que você possa misturá-los em uma nova matriz.

Isso prefixa todas as colunas;)

Saudações,

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;
}
axelbrz
fonte
2

Não existe um padrão SQL para isso.

No entanto, com a geração de código (sob demanda, à medida que as tabelas são criadas ou alteradas ou em tempo de execução), você pode fazer isso facilmente:

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)
Cade Roux
fonte
isso funcionaria, mas a questão é bastante boba. por que não apenas executar uma união ou subconsulta. Por que você ingressou e ainda deseja prefixos de tabela nos nomes das colunas?
D3vtr0n 01/12/2008
Cade: obrigado pela informação, isso é interessante. Infelizmente, gerar / alterar o banco de dados não é uma opção no meu caso. Devtron: se você estiver tentando mapear as informações que retornam de uma consulta para diferentes propriedades de um objeto, essas informações se tornam muito úteis.
foxdonut
1
Às vezes, os nomes de colunas em tabelas diferentes são iguais, mas não contêm os mesmos valores. Daí a necessidade de prefixá-los para distingui-los em visualizações ou tabelas derivadas (que devem ter todos os nomes de colunas exclusivos).
Cade Roux
@ Frederic, seu código precisa morar em algum lugar - isso apenas gera o código. Novamente, isso pode ser feito uma vez durante o desenvolvimento ou dinamicamente em tempo de execução.
Cade Roux
1

Existem duas maneiras em que posso fazer isso acontecer de maneira reutilizável. Uma é renomear todas as suas colunas com um prefixo para a tabela da qual elas vieram. Eu já vi isso muitas vezes, mas realmente não gosto. Acho que é redundante, causa muita digitação e você sempre pode usar aliases quando precisar cobrir o caso de um nome de coluna com uma origem pouco clara.

A outra maneira, que eu recomendaria que você fizesse na sua situação, se você se comprometer a ver isso, é criar visualizações para cada tabela que aliasse os nomes das tabelas. Então você se junta a essas visualizações, e não às tabelas. Dessa forma, você é livre para usar *, se desejar, livre para usar as tabelas originais com nomes de colunas originais, se desejar, e também facilita a gravação de consultas subseqüentes, porque você já fez o trabalho de renomeação nas visualizações.

Por fim, não estou claro por que você precisa saber de qual tabela cada uma das colunas veio. Isso importa? Em última análise, o que importa são os dados que eles contêm. Se o UserID veio da tabela User ou da tabela UserQuestion, realmente não importa. É importante, é claro, quando você precisar atualizá-lo, mas nesse momento você já deve conhecer seu esquema o suficiente para determinar isso.

RedFilter
fonte
"Finalmente, não estou claro por que você precisa saber de qual tabela cada uma das colunas veio. Isso importa?" <- 11 anos depois, um caso de uso é a verificação de estrutura no Go.
Lee Benson
1

Ou você pode usar o Red Gate SQL Refactor ou o SQL Prompt, que expande seu SELECT * em listas de colunas com um clique no botão Tab

portanto, no seu caso, se você digitar SELECT * FROM A JOIN B ... Vá para o final de *, botão Tab, voila! você verá SELECT A.column1, A.column2, ...., B.column1, B.column2 FROM A JOIN B

Ainda não é grátis

jerryhung
fonte
1

Não é possível fazer isso sem alias, simplesmente porque, como você fará referência a um campo na cláusula where, se esse campo existir nas 2 ou 3 tabelas em que você está ingressando? Não será claro para o mysql qual você está tentando referenciar.

kobejr
fonte
1

Resolvi um problema semelhante renomeando os campos nas tabelas envolvidas. Sim, tive o privilégio de fazer isso e entendo que todo mundo pode não ter. Adicionei prefixo para cada campo dentro de uma tabela que representa o nome da tabela. Portanto, o SQL postado pelo OP permaneceria inalterado -

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

e ainda fornecer os resultados esperados - facilidade de identificar a qual tabela os campos de saída pertencem.

Sam
fonte
0

select * geralmente gera código incorreto, pois novas colunas tendem a ser adicionadas ou a ordem das colunas muda nas tabelas com bastante frequência, o que geralmente interrompe o select * de maneiras muito sutis. Portanto, listar as colunas é a solução certa.

Quanto a como fazer sua consulta, não tenho certeza sobre o mysql, mas no sqlserver você pode selecionar nomes de colunas em syscolumns e criar dinamicamente a cláusula select.

Kozyarchuk
fonte
Aponte o ponto, mas, no meu contexto, preciso de algo genérico e dinâmico; portanto, meu código se adaptará a novas colunas sendo adicionadas / reordenadas / etc. Eu não quero ter que listar colunas individualmente.
foxdonut
5
Selecionar das syscolumns para criar dinamicamente uma instrução select é um truque terrível, e eu não a recomendaria na produção.
Juliet
0

Se estiver preocupado com as alterações do esquema, isso pode funcionar para você: 1. Execute uma consulta 'DESCRIBE table' em todas as tabelas envolvidas. 2. Use os nomes de campo retornados para construir dinamicamente uma sequência de nomes de colunas prefixados com o alias escolhido.

Chris Jacob
fonte
0

Há uma resposta direta à sua pergunta para aqueles que usam a MySQL C-API.

Dado o SQL:

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

Os resultados de 'mysql_stmt_result_metadata ()' fornecem a definição de seus campos da sua consulta SQL preparada na estrutura MYSQL_FIELD []. Cada campo contém os seguintes dados:

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

Observe os campos: catalog, table, org_name

Agora você sabe quais campos em seu SQL pertencem a qual esquema (também conhecido como catálogo) e tabela. Isso é suficiente para identificar genericamente cada campo de uma consulta sql de várias tabelas, sem a necessidade de criar um alias.

É mostrado que um produto real SqlYOG usa esses dados exatos de tal maneira que eles podem atualizar independentemente cada tabela de uma junção de várias tabelas, quando os campos PK estão presentes.

J Jorgenson
fonte
0

Desenvolvendo a partir desta solução , é assim que eu abordaria o problema:

Primeiro, crie uma lista de todas as ASinstruções:

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

Em seguida, use-o na sua consulta:

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

No entanto, isso pode precisar de modificações, porque algo semelhante é testado apenas no SQL Server. Mas esse código não funciona exatamente no SQL Server porque USING não é suportado.

Por favor, comente se você pode testar / corrigir este código, por exemplo, MySQL.

Antonio
fonte
0

Recentemente, deparei com esse problema no NodeJS e no Postgres.

Abordagem ES6

Não há nenhum recurso RDBMS que eu conheça que forneça essa funcionalidade; portanto, criei um objeto contendo todos os meus campos, por exemplo:

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

Definiu um redutor para concatenar as seqüências de caracteres junto com um nome de tabela:

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

Isso retorna uma matriz de seqüências de caracteres. Ligue para cada tabela e combine os resultados:

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

Saída da instrução SQL final:

console.log('SELECT ' + columns_joined.join(',') + ' FROM tab1, tab2 WHERE tab1.id = tab2.id');
Blair
fonte
De jeito nenhum! Isso é alguma injeção SQL hacky e não funciona com expressões.
ratijas 18/02
0

Eu implementei uma solução com base na resposta sugerindo o uso de colunas dummy ou sentinela no nó. Você o usaria gerando SQL como:

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

E depois o processamento da linha que você retorna do driver do banco de dados, como addPrefixes(row) .

Implementação (com base no fields/ rowsretornado pelo meu driver, mas deve ser fácil mudar para outros drivers de banco de dados):

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
}

Teste:

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)
  })
})
Carl G
fonte
0

O que faço é usar o Excel para concatenar o procedimento. Por exemplo, primeiro eu seleciono * e obtenho todas as colunas, cole-as no Excel. Em seguida, escreva o código necessário para cercar a coluna. Digamos que eu precisei de um anúncio anterior para várias colunas. Eu teria meus campos na coluna a e "como prev_" na coluna B e meus campos novamente na coluna c. Na coluna d eu teria uma coluna.

Em seguida, use concatanate na coluna e e junte-os, certificando-se de incluir espaços. Em seguida, recorte e cole isso no seu código sql. Também usei esse método para fazer declarações de caso para o mesmo campo e outros códigos mais longos que preciso fazer para cada campo em uma tabela de centenas de campos.

Nathan Michael
fonte
0

No postgres, uso as funções json para retornar objetos json ... depois de consultar, json_decode os campos com um sufixo _json.

IE:

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

depois, no PHP (ou em qualquer outra linguagem), percorro as colunas retornadas e json_decode () se elas tiverem o sufixo "_json" (também removendo o sufixo. No final, recebo um objeto chamado "tab1" que inclui todas as campos tab1 e ​​outro chamado "tab2" que inclui todos os campos tab2.

Joe Love
fonte
-1

PHP 7.2 + MySQL / Mariadb

O MySQL enviará vários campos com o mesmo nome. Mesmo no cliente do terminal. Mas se você quiser uma matriz associativa, precisará fazer as chaves sozinho.

Obrigado a @axelbrz pelo original. Eu o levei para o php mais recente e o limpei um pouco:

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'));
JasonWoof
fonte