Saltar al contenido

¿Puedo combinar los resultados de varias columnas en una sola columna sin UNION?

Solución:

No me queda claro qué es una “forma más elegante”.

Oracle puede usar la siguiente declaración para convertir columnas en filas

select all_name
from foo
unpivot (all_name for col_name in (
  his_name, 
  her_name,
  other_name));

Este es el diagrama de sintaxis de la instrucción select

SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [FROM table_references
      [PARTITION partition_list]
    [WHERE where_condition]
    [GROUP BY col_name 
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY  position
      [ASC | DESC], ...]
    [LIMIT  row_count OFFSET offset]
    [PROCEDURE procedure_name(argument_list)]
    [INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR UPDATE | LOCK IN SHARE MODE]]

Ni el WHERE,GROUP BY, HAVING, LIMIT, SELECT, INTO, FOR UPDATE ni el LOCK IN SHARE MODE La cláusula puede aumentar el número de filas definidas por el FROM cláusula. Así que si table_references es igual a foo la consulta no puede contener más filas que la tabla foo.
Entonces MySQL no tiene una forma tan “elegante” de desvincular una tabla.

Una forma de realizar tal desvinculación sin el uso de UNION se puede hacer mediante la compra mediante una combinación. Queremos crear 3 filas para cada fila del foo tabla, por lo que creamos una tabla auxiliar que contiene tres filas y (cruz) unimos a la foo mesa. Ahora tenemos tres filas en nuestra consulta para cada fila en la tabla base foo. Cada fila de consulta se puede completar con los datos adecuados. En su lugar, la función ELT se puede utilizar IF o CASE.

Violín SQL

Configuración del esquema de MySQL 5.6:

create table foo (
  his_name varchar(10),
  her_name varchar(10), 
  other_name varchar(10));

insert into foo(his_name,her_name,other_name) values ('one','two','three');
insert into foo(his_name,her_name,other_name) values ('four','five','six');

create  table aux(line int);
insert into aux(line) values(1);
insert into aux(line) values(2);
insert into aux(line) values(3);

Consulta dinámica:

select elt(aux.line,foo.his_name,foo.her_name,foo.other_name) all_name
from foo  cross join  aux

Resultados:

| all_name |
|----------|
|      one |
|     four |
|      two |
|     five |
|    three |
|      six |

Por supuesto, hay diferentes formas de crear una tabla que contenga las tres filas con valores 1,2,3:

Violín SQL

Usando una mesa auxiliar:

create  table aux(line int);
insert into aux(line) values(1);
insert into aux(line) values(2);
insert into aux(line) values(3);

Usando una mesa auxiliar:

select line
from aux

usando una expresión constante:

select 1 line 
union all 
select 2 
union all 
select 3

contando números de fila: Lo encontré aquí

SELECT
 @rownum := @rownum + 1 line
 FROM
(SELECT @rownum := 0) r, INFORMATION_SCHEMA.COLUMNS t
where @rownum<3

usando una de las vistas del diccionario:

SELECT
 ordinal_position  line
 from INFORMATION_SCHEMA.COLUMNS t
where table_catalog='def'
and table_schema='information_schema'
and table_name='COLUMNS'
and ordinal_position between 1 and 3

Resultados:

| ORDINAL_POSITION |
|------------------|
|                1 |
|                2 |
|                3 |

UTILIZANDO UNION

Otros han enviado respuestas intentando la agregación para recopilar datos sin usar UNION

  • May 12, 2014 : Mejoras de consultas sin UNION
  • May 05, 2015 : Calcular valores de tres tablas relacionadas, sin usar join o union
  • Feb 20, 2012 : Agregación de datos SQL

En este caso, lo que hace UNION una necesidad absoluta es la fusión de tres columnas en una sola columna. Nada podría ser más elegante que usar UNION

SELECT her_name AS name FROM foo
UNION
SELECT his_name AS name FROM foo
UNION
SELECT other_name AS name FROM foo;

Esto produciría una lista distinta de nombres.

Si la intención es seleccionar algunas columnas y generar una lista de una sola columna de los valores distintos, entonces se necesita SQL dinámico para producir dicha consulta. Para este ejemplo, supongamos lo siguiente

  • mydb esquema
  • mesa llamada foo
  • columnas para seleccionar juntas
    • her_name
    • his_name
    • other_name

Aquí está el SQL dinámico para generar la misma consulta

USE mydb
SET group_concat_max_len = 1048576;
SELECT GROUP_CONCAT(
    CONCAT('SELECT ',column_name,' AS name FROM ',table_name)
    SEPARATOR ' UNION ')
INTO @sql
FROM information_schema.tables
WHERE table_schema=DATABASE() AND table_name='foo' AND column_name IN
('her_name','his_name','other_name');
SELECT @sqlG
PREPARE s FROM @sql;
EXECUTE s;
DEALLOCATE PREPEARE s;

los SELECT @sqlG te dejará ver el SQL generado

Sin programar formalmente un procedimiento almacenado, esto es lo mejor que se puede conseguir.

SIN UTILIZAR UNION

Si el objetivo es estrictamente no usar UNION, necesitas una tabla temporal con PRIMARY KEY:

CREATE TABLE names SELECT her_name name FROM foo WHERE 1=2;
ALTER TABLE names ADD PRIMARY KEY (name);
INSERT IGNORE INTO names (name) SELECT her_name FROM foo;
INSERT IGNORE INTO names (name) SELECT his_name FROM foo;
INSERT IGNORE INTO names (name) SELECT other_name FROM foo;
SELECT * FROM names;
DROP TABLE names;

MIRA MAMÁ, SIN UNIÓN !!!

Una semi-solución: estarán en columna. (Pero también están en una sola fila, más o menos).

SELECT CONCAT_WS("n", her_name, his_name, other_name) AS name FROM foo

Por ejemplo:

mysql> SELECT CONCAT_WS("n", province) FROM Provinces;
+---------------------------+
| CONCAT_WS("n", province) |
+---------------------------+
| Alberta                   |
| British Columbia          |
| Manitoba                  |
| New Brunswick             |
| Newfoundland and Labrador |
| Nova Scotia               |
...

Si va a una página web, considere "
"
en lugar de "n".

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *