web-dev-qa-db-fra.com

SQL select join: est-il possible de préfixer toutes les colonnes en tant que 'préfixe. *'?

Je me demande si cela est possible en SQL. Supposons que vous ayez deux tables A et B, que vous sélectionniez sur la table A et que vous rejoigniez la table B:

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

Si la table A contient les colonnes 'a_id', 'name' et 'some_id' et que la table B contient 'b_id', 'name' et 'some_id', la requête renvoie les colonnes 'a_id', 'name' et 'some_id. ',' b_id ',' name ',' some_id '. Existe-t-il un moyen de préfixer les noms de colonne de la table B sans répertorier chaque colonne individuellement? L'équivalent de ceci:

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

Mais, comme mentionné, sans énumérer chaque colonne, quelque chose comme:

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

En gros, quelque chose à dire, "préfixe chaque colonne retournée par b. * Avec" quelque chose "". Est-ce possible ou suis-je à court de chance?

Merci d'avance pour votre aide!

EDIT: le conseil de ne pas utiliser SELECT *, etc., est un conseil valide mais non pertinent dans mon contexte. Veuillez vous en tenir au problème actuel. Est-il possible d’ajouter un préfixe (une constante spécifiée dans la requête SQL) à tous les noms de colonne d'une table dans une jointure?

EDIT: mon but ultime est de pouvoir faire un SELECT * sur deux tables avec une jointure et de pouvoir dire, à partir des noms des colonnes de ma série de résultats, quelles colonnes sont issues de la table A et de quelles colonnes de la table B. Encore une fois, je ne veux pas avoir à lister les colonnes individuellement, je dois pouvoir faire un SELECT *.

172
foxdonut

Je vois deux situations possibles ici. Tout d’abord, vous voulez savoir s’il existe un standard SQL que vous pouvez utiliser en général quelle que soit la base de données. Non, il n'y en a pas. Deuxièmement, vous voulez savoir en ce qui concerne un produit spécifique de dbms. Ensuite, vous devez l'identifier. Mais j'imagine que la réponse la plus probable est que vous obtiendrez quelque chose comme "a.id, b.id" puisque c'est ainsi que vous auriez besoin d'identifier les colonnes dans votre expression SQL. Et le moyen le plus simple de déterminer le type de défaut est simplement de soumettre une telle requête et de voir ce que vous récupérez. Si vous souhaitez spécifier le préfixe précédant le point, vous pouvez utiliser "SELECT * FROM a AS my_alias", par exemple.

34
dkretz

Il semble que la réponse à votre question est non, mais un hack que vous pouvez utiliser consiste à assigner une colonne factice pour séparer chaque nouvelle table. Cela fonctionne particulièrement bien si vous parcourez un jeu de résultats pour une liste de colonnes dans un langage de script tel que 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

Je sais que cela ne répond pas exactement à votre question, mais si vous êtes un codeur, c'est un excellent moyen de séparer les tables avec des noms de colonnes en double. J'espère que ça aide quelqu'un.

57
Wayne Bryan

Je comprends tout à fait pourquoi cela est nécessaire - du moins pour moi, c’est pratique lors du prototypage rapide, lorsque de nombreuses tables doivent être jointes, notamment de nombreuses jointures internes. Dès qu'un nom de colonne est identique dans un deuxième caractère générique de champ "jointable. *", Les valeurs de champ de la table principale sont remplacées par les valeurs de jointable. Soumis à l'erreur, frustrant et une violation de DRY lorsqu'il est nécessaire de spécifier manuellement les champs de la table avec des alias à plusieurs reprises ...

Voici une fonction PHP (Wordpress) pour y parvenir via la génération de code et un exemple d'utilisation. Dans l'exemple, il est utilisé pour générer rapidement une requête personnalisée qui fournira les champs d'une publication WordPress associée référencée via un advanced custom fields field.

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

Le résultat:

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
        )
)
19
Motin

La seule base de données que je connaisse est SQLite, en fonction des paramètres que vous avez configurés avec PRAGMA full_column_names et PRAGMA short_column_names. Voir http://www.sqlite.org/pragma.html

Autrement, tout ce que je peux vous recommander est de récupérer les colonnes d'un jeu de résultats par position ordinale plutôt que par nom de colonne, s'il est trop difficile pour vous de saisir les noms des colonnes dans votre requête.

C’est un bon exemple de la raison pour laquelle il est déconseillé d’utiliser SELECT * - car vous devrez éventuellement saisir tous les noms de colonne.

Je comprends la nécessité de prendre en charge les colonnes qui peuvent changer de nom ou de position, mais l’utilisation de caractères génériques rend cela plus difficile, pas plus simple.

10
Bill Karwin

Je suis en quelque sorte du même bateau que OP - j'ai des dizaines de champs de 3 tables différentes auxquelles je m'associe, dont certaines portent le même nom (c'est-à-dire. Id, nom, etc.) Je ne veux pas lister chaque champ, ma solution a donc été d'aliaser les champs qui ont un nom commun et d'utiliser select * pour ceux qui ont un nom unique.

Par exemple : 

table a: id, prénom, champ1, champ2 ...

tableau b: id, prénom, champ3, champ4 ...

sélectionnez a.id comme aID, a.name comme aName, a. *, b.id comme bid, b.name comme bName, b. * .....

Lors de l’accès aux résultats, j’utilise les noms avec alias pour ces champs et ignore les noms "originaux".

Peut-être pas la meilleure solution mais cela fonctionne pour moi .... je suis utiliser mysql

5
bdt

Différents produits de base de données vous donneront des réponses différentes; mais vous vous exposez à des blessures si vous portez cela très loin. Vous feriez bien mieux de choisir les colonnes de votre choix et de leur attribuer vos propres alias pour que l'identité de chaque colonne soit parfaitement claire et que vous puissiez les distinguer dans les résultats.

5
dkretz

Cette question est très utile dans la pratique. Il est seulement nécessaire de lister toutes les colonnes explicites de la programmation logicielle, où vous devez faire très attention à toutes les conditions.

Imaginez, lors du débogage, ou essayez d’utiliser le SGBD comme outil de bureau quotidien, au lieu d’une implémentation modifiable de l’infrastructure sous-jacente abstraite du programmeur, nous devons coder beaucoup de SQL. Le scénario peut être trouvé partout, comme la conversion de base de données, la migration, l'administration, etc. La plupart de ces instructions SQL ne seront exécutées qu'une seule fois et ne seront plus jamais utilisées. Donner le nom de chaque colonne est une perte de temps. Et n'oubliez pas que l'invention du SQL ne concerne pas uniquement les programmeurs.

Habituellement, je vais créer une vue utilitaire avec les noms de colonnes préfixés, voici la fonction dans pl/pgsql, ce n’est pas facile, mais vous pouvez la convertir en d’autres langages de procédure.

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

Exemples:

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

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

Il n'y a pas de standard SQL pour cela.

Cependant, avec la génération de code (à la demande lors de la création ou de la modification des tables ou au moment de l'exécution), vous pouvez le faire assez facilement:

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)
2
Cade Roux

Je comprends tout à fait votre problème concernant les noms de champs dupliqués.

J'avais aussi besoin de ça jusqu'à ce que je code ma propre fonction pour la résoudre. Si vous utilisez PHP, vous pouvez l’utiliser ou coder le vôtre dans la langue que vous utilisez si vous disposez des fonctionnalités suivantes.

L'astuce ici est que mysql_field_table() renvoie le nom de la table et mysql_field_name() le champ de chaque ligne du résultat s'il contient mysql_num_fields() afin que vous puissiez les mélanger dans un nouveau tableau.

Ce préfixe toutes les colonnes;)

Cordialement,

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
axelbrz

Je ne peux pas faire cela sans aliasing, simplement parce que, comment allez-vous référencer un champ dans la clause where, si ce champ existe dans les 2 ou 3 tables que vous rejoignez? faire référence.

1
kobejr

Ou vous pouvez utiliser le refactor SQL Red Gate ou l'invite SQL, qui agrandit votre SELECT * en listes de colonnes en cliquant sur le bouton de tabulation

donc, dans votre cas, si vous tapez SELECT * FROM A JOIN B ... Allez à la fin de *, touche Tab, le tour est joué! vous verrezSELECT A.column1, A.column2, ...., B.column1, B.column2 DE A JOIN B

Ce n'est pas gratuit

1
jerryhung

J'ai résolu un problème similaire en renommant les champs des tables concernées. Oui, j'ai eu le privilège de le faire et je comprends que tout le monde peut ne pas l'avoir. J'ai ajouté un préfixe à chaque champ d'une table représentant le nom de la table. Ainsi, le SQL affiché par OP resterait inchangé -

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

et donnez toujours les résultats attendus - facilité d'identification de la table à laquelle appartiennent les champs de sortie.

1
Sam

Il existe une réponse directe à votre question pour ceux qui utilisent MySQL C-API.

Compte tenu du SQL:

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

Les résultats de 'mysql_stmt_result_metadata ()' donnent la définition de vos champs de votre requête SQL préparée dans la structure MYSQL_FIELD []. Chaque champ contient les données suivantes:

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

Notez les champs: catalogue, table, nom_org

Vous savez maintenant quels champs de votre code SQL appartiennent à quel schéma (catalogue) et à cette table . Cela suffit pour identifier de manière générique chaque champ à partir d'une requête SQL multi-tables, sans rien alias.

Un produit réel SqlYOG est montré pour utiliser ces données exactes dans un tel manoir qu’elles sont capables de mettre à jour indépendamment chaque table d’une jointure multi-table, lorsque les champs PK sont présents.

0
J Jorgenson

Je peux penser à cela de deux manières pour que cela soit réutilisable. L’une consiste à renommer toutes vos colonnes avec un préfixe pour la table d’où elles viennent. J'ai vu cela plusieurs fois, mais je n'aime vraiment pas ça. Je trouve que c'est redondant, cause beaucoup de dactylographie, et vous pouvez toujours utiliser des alias lorsque vous devez couvrir le cas d'un nom de colonne ayant une origine peu claire. 

L'autre façon, ce que je vous recommanderais de faire dans votre cas si vous êtes résolu à résoudre ce problème, consiste à créer des vues pour chaque table qui alias les noms de table. Ensuite, vous vous associez à ces vues plutôt qu’aux tables. De cette façon, vous êtes libre d'utiliser * si vous le souhaitez, libre d'utiliser les tables d'origine avec les noms de colonnes d'origine si vous le souhaitez, et cela facilite également l'écriture des requêtes ultérieures, car vous avez déjà renommé les tâches dans les vues.

Enfin, je ne vois pas pourquoi vous avez besoin de savoir de quelle table provenaient chacune des colonnes. Est-ce important? En fin de compte, ce qui compte, ce sont les données qu’ils contiennent. Que l'ID utilisateur provienne de la table User ou de la table UserQuestion n'a pas d'importance. Bien sûr, il est important de savoir quand vous devez le mettre à jour, mais à ce stade, vous devriez déjà connaître suffisamment votre schéma pour le déterminer.

0
RedFilter

Récemment rencontré ce problème dans NodeJS et Postgres.

Approche ES6

Je ne connais aucune fonctionnalité SGBDR fournissant cette fonctionnalité. J'ai donc créé un objet contenant tous mes champs, par exemple:

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

Défini un réducteur pour concaténer les chaînes avec un nom de table:

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

Cela retourne un tableau de chaînes. Appelez-le pour chaque table et combinez les résultats:

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

Produisez l'instruction SQL finale:

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

Développer à partir de cette solution , voici comment j'aborderais le problème:

Commencez par créer une liste de toutes les instructions 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

Puis utilisez-le dans votre requête:

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

Toutefois, cela pourrait nécessiter des modifications car quelque chose de similaire n’est testé que dans SQL Server. Mais ce code ne fonctionne pas exactement dans SQL Server car USING n'est pas pris en charge.

Veuillez commenter si vous pouvez tester/corriger ce code, par exemple. MySQL.

0
Antonio

J'ai implémenté une solution basée sur la réponse suggérant l'utilisation de colonnes factices ou sentinelles in node. Vous l'utiliseriez en générant du SQL comme:

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

Et ensuite, le post-traitement de la ligne que vous recevez de votre pilote de base de données, tel que addPrefixes(row).

Implémentation (basée sur la fields/rows renvoyée par mon pilote, mais devrait être facile à modifier pour d'autres pilotes de base de données):

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
}

Tester:

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

Ce que je fais est d'utiliser Excel pour concaténer la procédure. Par exemple, tout d’abord, je sélectionne * et récupère toutes les colonnes, puis je les colle dans Excel. Ensuite, écrivez le code dont j'ai besoin pour entourer la colonne. Supposons que je devais faire de la publicité pour plusieurs colonnes. J'aurais mes champs dans la colonne a et "comme prev_" dans la colonne B et mes champs à nouveau dans la colonne c. Dans la colonne d, j'aurais une colonne.

Ensuite, utilisez concatanate dans la colonne e et fusionnez-les en veillant à inclure des espaces. Ensuite, coupez et collez ceci dans votre code SQL. J'ai également utilisé cette méthode pour créer des déclarations de cas pour le même champ et d'autres codes plus longs que je dois faire pour chaque champ d'une table de plusieurs centaines.

0
Nathan Michael

select * crée généralement un mauvais code, car les nouvelles colonnes ont tendance à être ajoutées ou leur ordre change fréquemment dans les tables, ce qui annule généralement select * de manière très subtile. La liste des colonnes est donc la bonne solution.

Pour ce qui est de savoir comment faire votre requête, vous n'êtes pas sûr de mysql, mais dans sqlserver, vous pouvez sélectionner les noms de colonne dans syscolumns et construire dynamiquement la clause select.

0
Kozyarchuk

Si vous êtes préoccupé par les changements de schéma, cela pourrait fonctionner pour vous: 1. Exécutez une requête 'DESCRIBE table' sur toutes les tables impliquées. 2. Utilisez les noms de champs renvoyés pour construire de manière dynamique une chaîne de noms de colonnes précédés de l'alias choisi.

0
Chris Jacob