SQL select join: ¿es posible prefijar todas las columnas como 'prefix. *'?

206

Me pregunto si esto es posible en SQL. Digamos que tiene dos tablas A y B, y hace una selección en la tabla A y se une en la tabla B:

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

Si la tabla A tiene las columnas 'a_id', 'name' y 'some_id', y la tabla B tiene 'b_id', 'name' y 'some_id', la consulta devolverá las columnas 'a_id', 'name', 'some_id ',' b_id ',' name ',' some_id '. ¿Hay alguna forma de prefijar los nombres de columna de la tabla B sin enumerar cada columna individualmente? El equivalente de esto:

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

Pero, como se mencionó, sin enumerar cada columna, entonces algo como:

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

Básicamente algo que decir, "prefijo cada columna devuelta por b. * Con 'algo'". ¿Es esto posible o no tengo suerte?

¡Gracias de antemano por tu ayuda!

EDITAR: el consejo sobre no usar SELECT *, etc., es un consejo válido pero no relevante en mi contexto, así que atente al problema en cuestión: ¿es posible agregar un prefijo (una constante especificada en la consulta SQL) a todos los nombres de columna de una tabla en una unión?

EDITAR: mi objetivo final es poder hacer un SELECCIONAR * en dos tablas con una combinación, y poder distinguir, a partir de los nombres de las columnas que obtengo en mi conjunto de resultados, qué columnas vinieron de la tabla A y qué columnas vinieron de la tabla B. Nuevamente, no quiero tener que enumerar columnas individualmente, necesito poder hacer un SELECT *.

Foxdonut
fuente
¿Qué esperas exactamente que sea el resultado de tu consulta? Estoy confundido
GregD 01 de
GregD: Quiero que todos los nombres de columna que salen de b. * Tengan el prefijo de alguna constante que especifique. Por ejemplo, en lugar de 'nombre' y 'número', quiero especificar, por ejemplo, el prefijo 'special_' y obtener 'special_name' y 'special_number'. Pero no quiero hacer esto para cada columna individualmente.
foxdonut
66
Cuando hago una SELECCIÓN rápida para ver columnas de varias tablas, a veces SELECTO 'AAAAA', A. *, 'BBBBB', B. * DE LA TABLA A COMO UNIR LA TABLA B COMO B EN A.ID = B.ID para que yo al menos tener un identificador de tabla al escanear a lo largo de las filas
Kristen
Posible duplicado: stackoverflow.com/questions/2595068/…
Andrioid

Respuestas:

35

Veo dos posibles situaciones aquí. Primero, desea saber si hay un estándar SQL para esto, que puede usar en general independientemente de la base de datos. No no hay. En segundo lugar, desea saber con respecto a un producto dbms específico. Entonces necesitas identificarlo. Pero imagino que la respuesta más probable es que obtendrá algo así como "a.id, b.id", ya que así es como debería identificar las columnas en su expresión SQL. Y la forma más fácil de averiguar cuál es el valor predeterminado es simplemente enviar una consulta y ver qué se obtiene. Si desea especificar qué prefijo viene antes del punto, puede usar "SELECT * FROM a AS my_alias", por ejemplo.

dkretz
fuente
11
No estoy seguro de cómo responde esto a tu pregunta. Estoy usando MS SQL Server y agrego un alias después de que el nombre de la tabla no agrega el alias a los nombres de las columnas en el conjunto de resultados.
paiego
74

Parece que la respuesta a su pregunta es no, sin embargo, un truco que puede usar es asignar una columna ficticia para separar cada nueva tabla. Esto funciona especialmente bien si está recorriendo un conjunto de resultados para una lista de columnas en un lenguaje de script como 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

Me doy cuenta de que esto no responde a su pregunta exactamente, pero si es un programador, esta es una excelente manera de separar tablas con nombres de columna duplicados. Espero que esto ayude a alguien.

Wayne Bryan
fuente
24

Entiendo totalmente por qué esto es necesario, al menos para mí es útil durante la creación rápida de prototipos cuando hay muchas tablas necesarias para unir, incluidas muchas uniones internas. Tan pronto como el nombre de una columna sea el mismo en un segundo comodín de campo "jointable. *", Los valores de campo de la tabla principal se anulan con los valores de tabletable. Propenso a errores, frustrante y una violación de DRY al tener que especificar manualmente los campos de la tabla con alias una y otra vez ...

Aquí hay una función PHP (Wordpress) para lograr esto a través de la generación de código junto con un ejemplo de cómo usarlo. En el ejemplo, se usa para generar rápidamente una consulta personalizada que proporcionará los campos de una publicación de WordPress relacionada a la que se hizo referencia a través de un campo de campos personalizados avanzados .

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

La salida:

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

La única base de datos que sé que hace esto es SQLite, dependiendo de la configuración que configure con PRAGMA full_column_namesy PRAGMA short_column_names. Ver http://www.sqlite.org/pragma.html

De lo contrario, todo lo que puedo recomendar es buscar columnas en un conjunto de resultados por posición ordinal en lugar de por nombre de columna, si le resulta demasiado difícil escribir los nombres de las columnas en su consulta.

Este es un buen ejemplo de por qué es una mala práctica usarloSELECT * , porque eventualmente tendrá que escribir todos los nombres de columna de todos modos.

Entiendo la necesidad de admitir columnas que pueden cambiar el nombre o la posición, pero el uso de comodines hace que sea más difícil , no más fácil.

Bill Karwin
fuente
2
Tenga en cuenta que ambos full_column_namesy short_column_namesestán en desuso en SQLite.
isanae
6

Estoy en el mismo tipo de barco que OP: tengo docenas de campos de 3 tablas diferentes a las que me estoy uniendo, algunos de los cuales tienen el mismo nombre (es decir, id, nombre, etc.). No quiero enumerar cada campo, por lo que mi solución fue crear un alias de los campos que compartían un nombre y usar select * para aquellos que tienen un nombre único.

Por ejemplo :

tabla a: id, nombre, campo1, campo2 ...

tabla b: id, nombre, campo3, campo4 ...

seleccione a.id como aID, a.name como aName, a. *, b.id como bID, b.name como bName, b. * .....

Al acceder a los resultados, uso los nombres con alias para estos campos e ignoro los nombres "originales".

Tal vez no sea la mejor solución, pero funciona para mí ... estoy usando mysql


fuente
5

Diferentes productos de bases de datos le darán diferentes respuestas; pero te estás preparando para el dolor si llevas esto muy lejos. Es mucho mejor elegir las columnas que desee y darles sus propios alias para que la identidad de cada columna sea clara como el cristal y pueda distinguirlas en los resultados.

dkretz
fuente
1
Punto tomado, pero mi objetivo aquí es algo muy genérico, por lo que no ser explícito no es un problema. De hecho, tener que ser específico sería un problema.
foxdonut
Ver más presentación a continuación. Puede usar use dot.notation, que probablemente sea lo que obtendrá por defecto.
dkretz
Es importante para la legibilidad. Tenía la esperanza de hacer esto ahora porque tengo un proceso de CTE filtrado. ex. CTE_A -> CTE_B -> CTE_C -> CTE_D -> select / insert No hay necesidad de especificar las columnas que quiero hasta que la declaración de selección final y el rendimiento no sean una consideración.
ThomasRones
5

Esta pregunta es muy útil en la práctica. Solo es necesario enumerar todas las columnas explícitas en la programación de software, donde debe prestar especial atención para tratar todas las condiciones.

Imagínese cuando depure, o intente usar DBMS como herramienta diaria de oficina, en lugar de una implementación alterable de la infraestructura subyacente abstracta de un programador específico, necesitamos codificar una gran cantidad de SQL. El escenario se puede encontrar en todas partes, como la conversión de bases de datos, la migración, la administración, etc. La mayoría de estos SQL se ejecutarán solo una vez y nunca se volverán a usar, dado que los nombres de cada columna son solo una pérdida de tiempo. Y no olvide que la invención de SQL no es solo para uso de los programadores.

Por lo general, crearé una vista de utilidad con los nombres de columna prefijados, aquí está la función en pl / pgsql, no es fácil, pero puede convertirla a otros lenguajes de procedimientos.

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

Ejemplos:

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

Entiendo totalmente su problema con los nombres de campo duplicados.

También necesitaba eso hasta que codificara mi propia función para resolverlo. Si está usando PHP, puede usarlo o codificar el suyo en el idioma que está usando si tiene las siguientes facilidades.

El truco aquí es que mysql_field_table()devuelve el nombre de la tabla y mysql_field_name()el campo para cada fila en el resultado si se obtiene conmysql_num_fields() para que pueda mezclarlos en una nueva matriz.

Esto prefija todas las columnas;)

Saludos,

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

No hay un estándar SQL para esto.

Sin embargo, con la generación de código (ya sea a pedido a medida que se crean o alteran las tablas o en tiempo de ejecución), puede hacer esto con bastante facilidad:

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
fuente
esto funcionaría pero la pregunta es bastante tonta. ¿Por qué no simplemente realizar una unión o subconsulta? ¿Por qué te unirías y aún querrías prefijos de tabla en los nombres de columna?
D3vtr0n
Cade: gracias por la información, eso es interesante. Desafortunadamente, generar / alterar la base de datos no es una opción en mi caso. Devtron: si está tratando de asignar la información que regresa de una consulta a diferentes propiedades de un objeto, esa información se vuelve muy útil.
foxdonut
1
A veces, los nombres de columna en diferentes tablas son iguales, pero no contienen los mismos valores. De ahí la necesidad de prefijarlos para distinguirlos en vistas o tablas derivadas (que deben tener todos los nombres de columna únicos).
Cade Roux
@Frederic, su código tiene que vivir en algún lugar; esto solo genera el código. Nuevamente, esto se puede hacer una vez durante el desarrollo o dinámicamente en tiempo de ejecución.
Cade Roux
1

Hay dos maneras en que puedo pensar para que esto suceda de una manera reutilizable. Una es renombrar todas las columnas con un prefijo para la tabla de la que provienen. Lo he visto muchas veces, pero realmente no me gusta. Creo que es redundante, causa muchos tipeos y siempre puede usar alias cuando necesite cubrir el caso de un nombre de columna que tiene un origen poco claro.

La otra forma, que recomendaría que haga en su situación si se compromete a hacerlo, es crear vistas para cada tabla que alias los nombres de las tablas. Luego te unes contra esas vistas, en lugar de las tablas. De esa forma, puede usar * si lo desea, usar las tablas originales con los nombres de columna originales si lo desea, y también facilita la escritura de consultas posteriores porque ya ha realizado el trabajo de cambio de nombre en las vistas.

Finalmente, no estoy claro por qué necesita saber de qué tabla provienen cada una de las columnas. ¿Esto importa? En última instancia, lo que importa son los datos que contienen. Si el ID de usuario proviene de la tabla Usuario o de la tabla Pregunta de usuario realmente no importa. Importa, por supuesto, cuando necesita actualizarlo, pero en ese punto ya debe conocer su esquema lo suficientemente bien como para determinarlo.

RedFilter
fuente
"Finalmente, no estoy claro por qué necesita saber de qué tabla provienen cada una de las columnas. ¿Importa esto?" <- 11 años después, un caso de uso es el escaneo de estructuras en Go.
Lee Benson
1

O puede usar Red Gate SQL Refactor o SQL Prompt, que expande su SELECT * en listas de columnas con un clic del botón Tabulador

así que en su caso, si escribe SELECT * FROM A JOIN B ... Vaya al final de *, botón Tab, ¡listo! verá SELECT A.column1, A.column2, ...., B.column1, B.column2 DESDE UNIRSE A B

Aunque no es gratis

jerryhung
fuente
1

No puede hacer esto sin alias, simplemente porque, ¿cómo va a hacer referencia a un campo en la cláusula where, si ese campo existe en las 2 o 3 tablas a las que se une? No estará claro para mysql a cuál está intentando hacer referencia.

kobejr
fuente
1

Resolví un problema similar al cambiar el nombre de los campos en las tablas involucradas. Sí, tuve el privilegio de hacer esto y entiendo que es posible que no todos lo tengan. Agregué un prefijo a cada campo dentro de una tabla que representa el nombre de la tabla. Por lo tanto, el SQL publicado por OP permanecería sin cambios:

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

y aún así dar los resultados esperados: facilidad para identificar a qué tabla pertenecen los campos de salida.

Sam
fuente
0

select * generalmente genera un código incorrecto, ya que las nuevas columnas tienden a agregarse o el orden de las columnas cambia en las tablas con bastante frecuencia, lo que generalmente rompe select * de una manera muy sutil. Por lo tanto, enumerar columnas es la solución correcta.

En cuanto a cómo hacer su consulta, no estoy seguro acerca de mysql, pero en sqlserver puede seleccionar nombres de columna de syscolumns y construir dinámicamente la cláusula select.

Kozyarchuk
fuente
Punto tomado, pero en mi contexto, necesito algo genérico y dinámico, de modo que mi código se adaptará a las nuevas columnas que se agregan / reordenan / etc. No quiero tener que enumerar columnas individualmente.
foxdonut
55
Seleccionar entre syscolumns para construir dinámicamente una instrucción select es un truco terrible, y no lo recomendaría en producción.
Julieta
0

Si le preocupan los cambios de esquema, esto podría funcionar para usted: 1. Ejecute una consulta 'DESCRIBIR tabla' en todas las tablas involucradas. 2. Utilice los nombres de campo devueltos para construir dinámicamente una cadena de nombres de columna con el alias elegido.

Chris Jacob
fuente
0

Hay una respuesta directa a su pregunta para aquellos que usan MySQL C-API.

Dado el SQL:

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

Los resultados de 'mysql_stmt_result_metadata ()' dan la definición de sus campos de su consulta SQL preparada en la estructura MYSQL_FIELD []. Cada campo contiene los siguientes datos:

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

Tenga en cuenta los campos: catálogo, tabla, nombre_organización

Ahora sabe qué campos en su SQL pertenecen a qué esquema (también conocido como catálogo) y tabla. Esto es suficiente para identificar genéricamente cada campo de una consulta sql de varias tablas, sin tener que alias.

Se muestra que un producto real SqlYOG utiliza estos datos exactos de tal manera que pueden actualizar de forma independiente cada tabla de una combinación de varias tablas, cuando los campos PK están presentes.

J Jorgenson
fuente
0

Desarrollando a partir de esta solución , así es como abordaría el problema:

Primero cree una lista de todas las ASdeclaraciones:

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

Luego úselo en su consulta:

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

Sin embargo, esto podría necesitar modificaciones porque algo similar solo se prueba en SQL Server. Pero este código no funciona exactamente en SQL Server porque USING no es compatible.

Comente si puede probar / corregir este código, por ejemplo, MySQL.

Antonio
fuente
0

Recientemente me encontré con este problema en NodeJS y Postgres.

Enfoque ES6

No conozco ninguna característica RDBMS que brinde esta funcionalidad, por lo que creé un objeto que contiene todos mis campos, por ejemplo:

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

Definió un reductor para concatenar las cadenas junto con un nombre de tabla:

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

Esto devuelve una serie de cadenas. Llámalo para cada tabla y combina los resultados:

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

Salida de la declaración SQL final:

console.log('SELECT ' + columns_joined.join(',') + ' FROM tab1, tab2 WHERE tab1.id = tab2.id');
Blair
fuente
¡De ninguna manera! Esa es una inyección SQL hacky, y no funciona con expresiones.
Ratijas
0

Implementé una solución basada en la respuesta que sugiere el uso de columnas ficticias o centinelas en el nodo. Lo usaría generando 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

Y luego procese la fila que obtiene de su controlador de base de datos como addPrefixes(row).

Implementación (basada en fields/ rowsdevuelta por mi controlador, pero debería ser fácil de cambiar para otros controladores de base de datos):

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
}

Prueba:

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

Lo que hago es usar Excel para concatenar el procedimiento. Por ejemplo, primero selecciono * y obtengo todas las columnas, las pego en Excel. Luego escriba el código que necesito para rodear la columna. Digamos que necesitaba un anuncio anterior a un montón de columnas. Tendría mis campos en la columna a y "como prev_" en la columna B y mis campos nuevamente en la columna c. En la columna d tendría una columna.

Luego use concatanate en la columna e y combínelos, asegurándose de incluir espacios. Luego corta y pega esto en tu código sql. También he usado este método para hacer declaraciones de caso para el mismo campo y otros códigos más largos que necesito hacer para cada campo en una tabla de campo de cientos.

Nathan Michael
fuente
0

En postgres, uso las funciones json para devolver objetos json ... luego, después de consultar, json_decode los campos con un sufijo _json.

ES DECIR:

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

luego en PHP (o cualquier otro lenguaje), recorro las columnas devueltas y las json_decode () si tienen el sufijo "_json" (también eliminando el sufijo. Al final, obtengo un objeto llamado "tab1" que incluye todos campos tab1 y otro llamado "tab2" que incluye todos los campos tab2.

Joe Love
fuente
-1

PHP 7.2 + MySQL / Mariadb

MySQL le enviará múltiples campos con el mismo nombre. Incluso en la terminal del cliente. Pero si desea una matriz asociativa, tendrá que hacer las claves usted mismo.

Gracias a @axelbrz por el original. Lo porté a un php más nuevo y lo limpié un poco:

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
fuente