SQL select join: è possibile aggiungere il prefisso a tutte le colonne come 'prefisso. *'?


206

Mi chiedo se questo è possibile in SQL. Supponi di avere due tabelle A e B e di effettuare una selezione sulla tabella A e di unirti alla tabella B:

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

Se la tabella A ha le colonne 'a_id', 'nome' e 'some_id' e la tabella B ha 'b_id', 'nome' e 'some_id', la query restituirà le colonne 'a_id', 'name', 'some_id ',' b_id ',' name ',' some_id '. Esiste un modo per aggiungere il prefisso ai nomi delle colonne della tabella B senza elencare ogni colonna singolarmente? L'equivalente di questo:

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

Ma, come detto, senza elencare ogni colonna, quindi qualcosa di simile:

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

Fondamentalmente qualcosa da dire "prefisso ogni colonna restituita da b. * Con 'qualcosa'". È possibile o sono sfortunato?

Grazie in anticipo per il vostro aiuto!

MODIFICA: i consigli su come non utilizzare SELECT * e così via sono consigli validi ma non rilevanti nel mio contesto, quindi si prega di attenersi al problema attuale - è possibile aggiungere un prefisso (una costante specificata nella query SQL) a tutti i nomi di colonna di una tabella in un join?

EDIT: il mio obiettivo finale è quello di essere in grado di fare un SELECT * su due tabelle con un join ed essere in grado di dire, dai nomi delle colonne che ottengo nel mio set di risultati, quali colonne provengono dalla tabella A e quali colonne sono arrivate dalla tabella B. Ancora una volta, non voglio elencare le colonne singolarmente, devo essere in grado di fare un SELECT *.


Cosa ti aspetti esattamente dal risultato della tua domanda? Sono confuso
GregD,

GregD: Voglio che tutti i nomi delle colonne che escono da b. * Siano preceduti da una costante che ho specificato. Ad esempio, anziché "nome" e "numero", desidero specificare, ad esempio, il prefisso "special_" e ottenere "special_name" e "special_number". Ma non voglio farlo individualmente per ogni colonna.
foxdonut,

6
Quando eseguo una SELEZIONE rapida per visualizzare colonne da più tabelle, a volte seleziono "AAAAA", A. *, "BBBBB", B. * DA Tabella A COME UNISCI Tabella B COME B SU A.ID = B.ID in modo che I almeno avere un identificatore di tabella durante la scansione lungo le file
Kristen,

Risposte:


35

Vedo due possibili situazioni qui. Innanzitutto, vuoi sapere se esiste uno standard SQL per questo, che puoi utilizzare in generale indipendentemente dal database. No non c'è. In secondo luogo, si desidera conoscere un prodotto dbms specifico. Quindi è necessario identificarlo. Ma immagino che la risposta più probabile sia che otterrai qualcosa come "a.id, b.id" poiché è così che dovresti identificare le colonne nella tua espressione SQL. E il modo più semplice per scoprire qual è l'impostazione predefinita, è semplicemente inviare una query del genere e vedere cosa si ottiene. Se si desidera specificare quale prefisso precede il punto, è possibile utilizzare "SELEZIONA * DA un AS my_alias", ad esempio.


11
Non sono sicuro di come questo risponda alla tua domanda. Sto usando MS SQL Server e aggiungo un alias dopo che il nome della tabella non aggiunge l'alias ai nomi delle colonne nel set di risultati.
paiego

74

Sembra che la risposta alla tua domanda sia no, tuttavia un trucco che puoi usare è assegnare una colonna fittizia per separare ogni nuova tabella. Funziona particolarmente bene se stai eseguendo il ciclo continuo di un set di risultati per un elenco di colonne in un linguaggio di scripting come Python o 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

Mi rendo conto che questo non risponde esattamente alla tua domanda, ma se sei un programmatore questo è un ottimo modo per separare le tabelle con nomi di colonna duplicati. Spero che questo aiuti qualcuno.


24

Capisco perfettamente perché ciò sia necessario - almeno per me è utile durante la prototipazione rapida quando ci sono molti tavoli necessari da unire, inclusi molti join interni. Non appena il nome di una colonna è lo stesso in un secondo jolly di campo "jointable. *", I valori dei campi della tabella principale vengono sostituiti con i valori jointable. Errore soggetto a, frustrante e una violazione di DRY quando è necessario specificare manualmente i campi della tabella con alias più e più volte ...

Ecco una funzione PHP (Wordpress) per raggiungere questo obiettivo attraverso la generazione di codice insieme a un esempio di come usarlo. Nell'esempio, viene utilizzato per generare rapidamente una query personalizzata che fornirà i campi di un post wordpress correlato a cui è stato fatto riferimento attraverso un campo di campi personalizzati avanzati .

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

Il risultato:

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

L'unico database che conosco è SQLite, a seconda delle impostazioni configurate con PRAGMA full_column_namese PRAGMA short_column_names. Vedi http://www.sqlite.org/pragma.html

Altrimenti tutto ciò che posso consigliare è di recuperare le colonne in un set di risultati in base alla posizione ordinale anziché al nome della colonna, se è troppo difficile per te digitare i nomi delle colonne nella tua query.

Questo è un buon esempio del perché è una cattiva pratica da usareSELECT * , perché alla fine dovrai comunque digitare tutti i nomi delle colonne.

Comprendo la necessità di supportare colonne che possono cambiare nome o posizione, ma l'uso di caratteri jolly rende più difficile , non più facile.


2
Si noti che entrambi full_column_namese short_column_namessono obsoleti in SQLite.
isanae,

6

Sono in una specie della stessa barca di OP - Ho decine di campi da 3 diverse tabelle a cui mi sto unendo, alcuni dei quali hanno lo stesso nome (es. Id, nome, ecc.). Non voglio elencare ogni campo, quindi la mia soluzione era quella di alias quei campi che condividevano un nome e usare select * per quelli che hanno un nome univoco.

Per esempio :

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

tabella b: id, nome, field3, field4 ...

seleziona a.id come aID, a.name come aName, a. *, b.id come offerta, b.name come bName, b. * .....

Quando si accede ai risultati, io uso i nomi con alias per questi campi e ignoro i nomi "originali".

Forse non è la soluzione migliore ma funziona per me .... sto usando mysql


5

DIVERSI prodotti di database ti daranno risposte diverse; ma ti stai preparando per il dolore se lo porti molto lontano. Stai molto meglio scegliendo le colonne che desideri e dando loro i tuoi alias in modo che l'identità di ogni colonna sia cristallina e puoi distinguerle nei risultati.


1
Punto preso, ma il mio obiettivo qui è qualcosa di molto generico, quindi non essere esplicito non è un problema. In effetti, dover essere specifici sarebbe un problema.
foxdonut,

Vedi ulteriori invii di seguito. Puoi usare dot.notation, che è probabilmente quello che otterrai come predefinito?
dkretz,

È importante per la leggibilità. Speravo di farlo proprio ora perché ho un processo CTE simile. ex. CTE_A -> CTE_B -> CTE_C -> CTE_D -> seleziona / inserisci Non è necessario specificare le colonne che voglio fino a quando l'istruzione di selezione finale e le prestazioni non sono considerate.
ThomasRones,

5

Questa domanda è molto utile in pratica. È necessario solo elencare tutte le colonne esplicite nella programmazione software, in cui si presta particolare attenzione a gestire tutte le condizioni.

Immagina durante il debug, o, prova a usare DBMS come strumento quotidiano per l'ufficio, invece di implementare qualcosa di alterabile nell'infrastruttura sottostante astratta del programmatore specifico, dobbiamo codificare molti SQL. Lo scenario può essere trovato ovunque, come conversione del database, migrazione, amministrazione, ecc. La maggior parte di questi SQL verrà eseguita una sola volta e non verrà mai più utilizzata, poiché i nomi di ogni colonna sono solo una perdita di tempo. E non dimenticare che l'invenzione di SQL non è solo per l'uso da parte dei programmatori.

Di solito creerò una vista utility con i nomi delle colonne con prefisso, qui è la funzione in pl / pgsql, non è facile ma è possibile convertirla in altri linguaggi di procedura.

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

Esempi:

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

Capisco perfettamente il tuo problema con i nomi dei campi duplicati.

Ne avevo bisogno fino a quando non ho codificato la mia funzione per risolverlo. Se stai usando PHP puoi usarlo, o codificare il tuo nella lingua che stai usando se hai le seguenti funzionalità.

Il trucco qui è che mysql_field_table()restituisce il nome della tabella e mysql_field_name()il campo per ogni riga del risultato, se presentemysql_num_fields() modo da poterli mescolare in un nuovo array.

Questo prefisso tutte le colonne;)

Saluti,

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

Non esiste uno standard SQL per questo.

Tuttavia, con la generazione di codice (su richiesta, poiché le tabelle vengono create o modificate o in fase di esecuzione), è possibile farlo abbastanza 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)

questo funzionerebbe ma la domanda è piuttosto sciocca. perché non eseguire semplicemente un sindacato o una query secondaria. Perché dovresti aderire e vuoi ancora i prefissi delle tabelle nei nomi delle colonne?
D3vtr0n,

Cade: grazie per l'informazione, è interessante. Sfortunatamente, la generazione / modifica del database non è un'opzione nel mio caso. Devtron: se si sta tentando di mappare le informazioni che ritornano da una query a diverse proprietà di un oggetto, tali informazioni diventano molto utili.
foxdonut,

1
A volte i nomi delle colonne in tabelle diverse sono uguali, ma non contengono gli stessi valori. Da qui la necessità di prefissarli per distinguerli nelle viste o nelle tabelle derivate (che devono avere tutti i nomi di colonna univoci).
Cade Roux,

@Frederic, il tuo codice deve vivere da qualche parte - questo genera semplicemente il codice. Ancora una volta, questo può essere fatto una volta durante lo sviluppo o dinamicamente in fase di esecuzione.
Cade Roux,

1

Ci sono due modi a cui riesco a pensare per farlo accadere in modo riutilizzabile. Uno è rinominare tutte le colonne con un prefisso per la tabella da cui provengono. L'ho visto molte volte, ma davvero non mi piace. Trovo che sia ridondante, causa molta digitazione e puoi sempre usare gli alias quando devi coprire il caso di un nome di colonna che ha un'origine poco chiara.

L'altro modo, che ti consiglierei di fare nella tua situazione se ti impegni a vederlo, è quello di creare viste per ogni tabella che alias i nomi delle tabelle. Quindi ti unisci a quelle viste, piuttosto che ai tavoli. In questo modo, sei libero di usare * se lo desideri, libero di usare le tabelle originali con nomi di colonne originali se lo desideri, e semplifica anche la scrittura di eventuali domande successive perché hai già fatto il lavoro di ridenominazione nelle viste.

Infine, non sono chiaro il motivo per cui è necessario sapere da quale tabella proviene ciascuna delle colonne. È importante? In definitiva ciò che conta sono i dati che contengono. Non importa se UserID provenga dalla tabella User o dalla tabella UserQuestion. È importante, ovviamente, quando è necessario aggiornarlo, ma a quel punto dovresti già conoscere lo schema abbastanza bene per determinarlo.


"Infine, non sono chiaro il motivo per cui è necessario sapere da quale tabella proviene ciascuna delle colonne. È importante?" <- 11 anni dopo, un caso d'uso è la scansione strutt in Go.
Lee Benson,

1

Oppure puoi utilizzare Red Gate SQL Refactor o il prompt SQL, che espande il tuo SELECT * negli elenchi di colonne con un clic sul pulsante Tab

quindi nel tuo caso, se digiti SELEZIONA * DA UN JOIN B ... Vai alla fine di *, pulsante Tab, voilà! vedrai SELEZIONA A.column1, A.column2, ...., B.column1, B.column2 DA UN JOIN B

Non è gratuito però


1

Non posso farlo senza alias, semplicemente perché, come hai intenzione di fare riferimento a un campo nella clausola where, se quel campo esiste nelle 2 o 3 tabelle a cui ti stai unendo? Non sarà chiaro per mysql quale si sta cercando di fare riferimento.


1

Ho risolto un mio problema simile rinominando i campi nelle tabelle interessate. Sì, ho avuto il privilegio di farlo e capire che tutti potrebbero non averlo. Ho aggiunto il prefisso a ciascun campo all'interno di una tabella che rappresenta il nome della tabella. Pertanto, l'SQL pubblicato da OP rimarrebbe invariato -

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

e ancora fornire i risultati attesi - facilità di identificazione a quale tabella appartengono i campi di output.


0

select * di solito rende il codice errato, poiché le nuove colonne tendono ad essere aggiunte o l'ordine delle colonne cambia nelle tabelle abbastanza frequentemente, il che di solito interrompe select * in modi molto sottili. Quindi elencare le colonne è la soluzione giusta.

Per quanto riguarda come eseguire la query, non sei sicuro di mysql ma in sqlserver puoi selezionare i nomi delle colonne dalle colonne di sistema e creare dinamicamente la clausola select.


Punto preso, ma nel mio contesto, ho bisogno di qualcosa di generico e dinamico, quindi in effetti il ​​mio codice si adatterà alle nuove colonne da aggiungere / riordinare / ecc. Non voglio dover elencare le colonne singolarmente.
foxdonut,

5
Scegliere da colonne di sistema per creare dinamicamente un'istruzione select è un trucco terribile, e non lo consiglierei in produzione.
Juliet,

0

Se sei preoccupato per le modifiche allo schema, ciò potrebbe funzionare per te: 1. Esegui una query "DESCRIBE table" su tutte le tabelle interessate. 2. Utilizzare i nomi dei campi restituiti per costruire dinamicamente una stringa di nomi di colonne con il prefisso dell'alias scelto.


0

C'è una risposta diretta alla tua domanda per coloro che usano la C-API di MySQL.

Dato l'SQL:

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

I risultati di 'mysql_stmt_result_metadata ()' forniscono la definizione dei campi dalla query SQL preparata nella struttura MYSQL_FIELD []. Ogni campo contiene i seguenti dati:

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

Prendi nota dei campi: catalogo, tabella, nome_org

Ora sai quali campi nel tuo SQL appartengono a quale schema (aka catalogo) e tabella. Questo è sufficiente per identificare genericamente ogni campo da una query sql multi-tabella, senza dover alias nulla.

Un prodotto reale SqlYOG viene mostrato per utilizzare questi dati esatti in modo tale da poter aggiornare in modo indipendente ogni tabella di un join multi-tabella, quando sono presenti i campi PK.


0

Sviluppando da questa soluzione , è così che affronterei il problema:

Innanzitutto crea un elenco di tutte le ASdichiarazioni:

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

Quindi utilizzalo nella tua query:

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

Tuttavia, ciò potrebbe richiedere modifiche perché qualcosa di simile viene testato solo in SQL Server. Ma questo codice non funziona esattamente in SQL Server perché USING non è supportato.

Si prega di commentare se è possibile testare / correggere questo codice, ad esempio MySQL.


0

Recentemente ho riscontrato questo problema in NodeJS e Postgres.

Approccio ES6

Non ci sono funzionalità RDBMS che conosco che forniscono questa funzionalità, quindi ho creato un oggetto contenente tutti i miei campi, ad esempio:

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

Definito un riduttore per concatenare le stringhe insieme al nome di una tabella:

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

Ciò restituisce una matrice di stringhe. Chiamalo per ogni tabella e combina i risultati:

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

Emette l'istruzione SQL finale:

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

Non c'è modo! Questa è un'iniezione di SQL caotica e non funziona con le espressioni.
ratijas,

0

Ho implementato una soluzione basata sulla risposta che suggerisce l'utilizzo di colonne fittizie o sentinella nel nodo. Lo useresti generando SQL come:

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 quindi post-elaborazione della riga che si ottiene indietro dal driver del database come addPrefixes(row) .

Implementazione (basata su fields/ rowsrestituito dal mio driver, ma dovrebbe essere facile da modificare per altri driver 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
}

Test:

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

Quello che faccio è usare Excel per concatenare la procedura. Ad esempio, prima seleziono * e ottengo tutte le colonne, incollandole in Excel. Quindi scrivi il codice di cui ho bisogno per circondare la colonna. Supponiamo che dovessi pubblicare un'anteprima di un gruppo di colonne. Avrei i miei campi nella colonna a e "as prev_" nella colonna B e i miei campi di nuovo nella colonna c. Nella colonna d avrei una colonna.

Quindi utilizzare concatanate nella colonna e e unirli insieme, assicurandosi di includere spazi. Quindi taglialo e incollalo nel tuo codice sql. Ho anche usato questo metodo per fare dichiarazioni di casi per lo stesso campo e altri codici più lunghi che devo fare per ogni campo in una tabella di centinaia di campi.


0

In postgres, utilizzo le funzioni json per restituire invece oggetti json .... quindi, dopo l'interrogazione, json_decode i campi con un suffisso _json.

IE:

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

quindi in PHP (o in qualsiasi altra lingua), eseguo il ciclo attraverso le colonne restituite e json_decode () se hanno il suffisso "_json" (rimuovendo anche il suffisso. Alla fine, ottengo un oggetto chiamato "tab1" che include tutto campi tab1 e ​​un altro chiamato "tab2" che include tutti i campi tab2.


-1

PHP 7.2 + MySQL / Mariadb

MySQL ti invierà più campi con lo stesso nome. Anche nel client terminal. Ma se vuoi un array associativo, dovrai creare le chiavi da solo.

Grazie a @axelbrz per l'originale. L'ho portato su php più recente e l'ho ripulito un po ':

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'));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.