Estoy tratando de usar una instrucción select para obtener todas las columnas de una determinada tabla MySQL, excepto una. ¿Hay una manera simple de hacer esto?
EDITAR: hay 53 columnas en esta tabla (NO ES MI DISEÑO)
Estoy tratando de usar una instrucción select para obtener todas las columnas de una determinada tabla MySQL, excepto una. ¿Hay una manera simple de hacer esto?
EDITAR: hay 53 columnas en esta tabla (NO ES MI DISEÑO)
Respuestas:
En realidad, hay una manera, por supuesto, necesitas tener permisos para hacer esto ...
SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), '<columns_to_omit>,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table>' AND TABLE_SCHEMA = '<database>'), ' FROM <table>');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
Sustitución <table>, <database> and <columns_to_omit>
<column_name>
En las definiciones mysql (manual) no existe tal cosa. Pero si tiene una gran cantidad de columnas col1
, ... col100
, lo siguiente puede ser útil:
DROP TABLE IF EXISTS temp_tb;
CREATE TEMPORARY TABLE ENGINE=MEMORY temp_tb SELECT * FROM orig_tb;
ALTER TABLE temp_tb DROP col_x;
SELECT * FROM temp_tb;
DROP TABLE IF EXISTS temp_tb;
¿Una vista funcionaría mejor en este caso?
CREATE VIEW vwTable
as
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Tu puedes hacer:
SELECT column1, column2, column4 FROM table WHERE whatever
sin obtener la columna 3, aunque tal vez estabas buscando una solución más general?
Si desea excluir el valor de un campo, por ejemplo, por cuestiones de seguridad / información confidencial, puede recuperar esa columna como nula.
p.ej
SELECT *, NULL AS salary FROM users
salary
columna. Pero como se recupera después del *, sobrescribe el original. No es bonito, pero funciona.
Que yo sepa, no lo hay. Puedes hacer algo como:
SELECT col1, col2, col3, col4 FROM tbl
y elija manualmente las columnas que desee. Sin embargo, si quieres muchas columnas, entonces quizás solo quieras hacer:
SELECT * FROM tbl
e ignora lo que no quieres.
En su caso particular, sugeriría:
SELECT * FROM tbl
a menos que solo quieras unas pocas columnas. Si solo quieres cuatro columnas, entonces:
SELECT col3, col6, col45, col 52 FROM tbl
estaría bien, pero si desea 50 columnas, entonces cualquier código que haga que la consulta sea (¿demasiado?) difícil de leer.
Mientras probaba las soluciones de @Mahomedalid y @Junaid, encontré un problema. Entonces pensé en compartirlo. Si el nombre de la columna tiene espacios o guiones como el check-in, la consulta fallará. La solución simple consiste en utilizar una marca de retroceso alrededor de los nombres de columna. La consulta modificada está debajo
SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(CONCAT("`", COLUMN_NAME, "`")) FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;
Si la columna que no deseaba seleccionar tenía una gran cantidad de datos, y no deseaba incluirla debido a problemas de velocidad y seleccionó las otras columnas con frecuencia, le sugiero que cree una nueva tabla con el campo que normalmente no selecciona con una clave de la tabla original y elimine el campo de la tabla original. Únase a las tablas cuando ese campo adicional sea realmente requerido.
Puede usar DESCRIBE my_table y usar los resultados para generar la instrucción SELECT dinámicamente.
Mi principal problema son las muchas columnas que obtengo al unir tablas. Si bien esta no es la respuesta a su pregunta (cómo seleccionar todas las columnas excepto una de una tabla), creo que vale la pena mencionar que puede especificar obtener todas las columnas de una tabla en particular, en lugar de solo especificartable.
.
Aquí hay un ejemplo de cómo esto podría ser muy útil:
seleccionar usuarios. *, phone.meta_value como teléfono, zipcode.meta_value como código postal de los usuarios izquierda unirse a user_meta como teléfono on ((users.user_id = phone.user_id) AND (phone.meta_key = 'phone')) left join user_meta como código postal on ((users.user_id = zipcode.user_id) AND (zipcode.meta_key = 'zipcode'))
El resultado son todas las columnas de la tabla de usuarios y dos columnas adicionales que se unieron desde la metatabla.
Me gustó la respuesta @Mahomedalid
además de este hecho informado en el comentario de @Bill Karwin
. El posible problema planteado por@Jan Koritak
es cierto. Lo enfrenté, pero he encontrado un truco para eso y solo quiero compartirlo aquí para cualquiera que se enfrente al problema.
podemos reemplazar la función REPLACE con la cláusula where en la subconsulta de la instrucción Preparada de esta manera:
Usando mi tabla y nombre de columna
SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;
Entonces, esto va a excluir solo el campo id
pero nocompany_id
Es una buena práctica especificar las columnas que está consultando incluso si consulta todas las columnas.
Por lo tanto, le sugiero que escriba el nombre de cada columna en la declaración (excluyendo la que no desea).
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Solo haz
SELECT * FROM table WHERE whatever
Luego suelte la columna en su lenguaje de programación favorito: php
while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
unset($data["id"]);
foreach ($data as $k => $v) {
echo"$v,";
}
}
Estoy de acuerdo con la solución "simple" de enumerar todas las columnas, pero esto puede ser oneroso y los errores tipográficos pueden causar mucho tiempo perdido. Uso una función "getTableColumns" para recuperar los nombres de mis columnas adecuados para pegar en una consulta. Entonces todo lo que necesito hacer es eliminar aquellos que no quiero.
CREATE FUNCTION `getTableColumns`(tablename varchar(100))
RETURNS varchar(5000) CHARSET latin1
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE res VARCHAR(5000) DEFAULT "";
DECLARE col VARCHAR(200);
DECLARE cur1 CURSOR FOR
select COLUMN_NAME from information_schema.columns
where TABLE_NAME=@table AND TABLE_SCHEMA="yourdatabase" ORDER BY ORDINAL_POSITION;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO col;
IF NOT done THEN
set res = CONCAT(res,IF(LENGTH(res)>0,",",""),col);
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
RETURN res;
Su resultado devuelve una cadena delimitada por comas, por ejemplo ...
col1, col2, col3, col4, ... col53
Estoy de acuerdo en que no es suficiente Select *
, si ese que no necesita, como se menciona en otro lugar, es un BLOB, no desea que esa sobrecarga se arrastre.
Crearía una vista con los datos requeridos, luego puede Select *
hacerlo con comodidad, si el software de la base de datos los admite. De lo contrario, ponga los enormes datos en otra tabla.
Al principio pensé que podrías usar expresiones regulares, pero como he estado leyendo los documentos MYSQL parece que no puedes. Si fuera usted, usaría otro lenguaje (como PHP) para generar una lista de columnas que desea obtener, almacenarla como una cadena y luego usarla para generar el SQL.
Yo también quería esto, así que creé una función en su lugar.
public function getColsExcept($table,$remove){
$res =mysql_query("SHOW COLUMNS FROM $table");
while($arr = mysql_fetch_assoc($res)){
$cols[] = $arr['Field'];
}
if(is_array($remove)){
$newCols = array_diff($cols,$remove);
return "`".implode("`,`",$newCols)."`";
}else{
$length = count($cols);
for($i=0;$i<$length;$i++){
if($cols[$i] == $remove)
unset($cols[$i]);
}
return "`".implode("`,`",$cols)."`";
}
}
Entonces, cómo funciona es que ingrese la tabla, luego una columna que no desea o como en una matriz: matriz ("id", "nombre", "cualquier columna")
Entonces, en select, podría usarlo así:
mysql_query("SELECT ".$db->getColsExcept('table',array('id','bigtextcolumn'))." FROM table");
o
mysql_query("SELECT ".$db->getColsExcept('table','bigtextcolumn')." FROM table");
Estoy de acuerdo con la respuesta de @ Mahomedalid, pero no quería hacer algo como una declaración preparada y no quería escribir todos los campos, así que lo que tenía era una solución tonta.
Vaya a la tabla en phpmyadmin-> sql-> select, volcará la consulta: ¡copie, reemplace y listo! :)
Si bien estoy de acuerdo con la respuesta de Thomas (+1;)), me gustaría agregar la advertencia de que asumiré que la columna que no desea contiene casi ningún dato. Si contiene enormes cantidades de texto, xml o blobs binarios, tómese el tiempo para seleccionar cada columna individualmente. Su rendimiento sufrirá lo contrario. ¡Salud!
La respuesta publicada por Mahomedalid tiene un pequeño problema:
El código de función de reemplazo interno estaba reemplazando "<columns_to_delete>,
" por "", este reemplazo tiene un problema si el campo a reemplazar es el último en la cadena de concat debido a que el último no tiene la coma "," y no se elimina de la cuerda.
Mi propuesta:
SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME),
'<columns_to_delete>', '\'FIELD_REMOVED\'')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '<table>'
AND TABLE_SCHEMA = '<database>'), ' FROM <table>');
Sustitución <table>
,<database>
y `
La columna eliminada se reemplaza por la cadena "FIELD_REMOVED" en mi caso, esto funciona porque estaba tratando de proteger la memoria. (El campo que estaba eliminando es un BLOB de alrededor de 1 MB)
Basado en la respuesta @Mahomedalid, he realizado algunas mejoras para admitir "seleccionar todas las columnas excepto algunas en mysql"
SET @database = 'database_name';
SET @tablename = 'table_name';
SET @cols2delete = 'col1,col2,col3';
SET @sql = CONCAT(
'SELECT ',
(
SELECT GROUP_CONCAT( IF(FIND_IN_SET(COLUMN_NAME, @cols2delete), NULL, COLUMN_NAME ) )
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tablename AND TABLE_SCHEMA = @database
),
' FROM ',
@tablename);
SELECT @sql;
Si tiene muchos cols, use este sql para cambiar group_concat_max_len
SET @@group_concat_max_len = 2048;
Puede ser que tenga una solución a la discrepancia señalada de Jan Koritak
SELECT CONCAT('SELECT ',
( SELECT GROUP_CONCAT(t.col)
FROM
(
SELECT CASE
WHEN COLUMN_NAME = 'eid' THEN NULL
ELSE COLUMN_NAME
END AS col
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'
) t
WHERE t.col IS NOT NULL) ,
' FROM employee' );
Mesa :
SELECT table_name,column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'
================================
table_name column_name
employee eid
employee name_eid
employee sal
================================
Resultado de la consulta:
'SELECT name_eid,sal FROM employee'
Si siempre es la misma columna, puede crear una vista que no la tenga.
De lo contrario, no, no lo creo.
Puede usar SQL para generar SQL si lo desea y evaluar el SQL que produce. Esta es una solución general, ya que extrae los nombres de columna del esquema de información. Aquí hay un ejemplo de la línea de comandos de Unix.
Sustituyendo
echo $(echo 'select concat("select ", group_concat(column_name) , " from TABLE") from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1) | MYSQL
Realmente solo necesitará extraer los nombres de columna de esta manera solo una vez para construir la lista de columnas excluidas de esa columna, y luego simplemente usar la consulta que ha construido.
Entonces algo como:
column_list=$(echo 'select group_concat(column_name) from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1)
Ahora puede reutilizar la $column_list
cadena en las consultas que construya.
Me gustaría agregar otro punto de vista para resolver este problema, especialmente si tiene que eliminar una pequeña cantidad de columnas.
Puede usar una herramienta de base de datos como MySQL Workbench para generar la instrucción select por usted, por lo que solo tiene que eliminar manualmente esas columnas para la instrucción generada y copiarla en su script SQL.
En MySQL Workbench, la forma de generarlo es:
Haga clic derecho en la tabla -> enviar al Editor SQL -> Seleccionar toda la declaración.
La respuesta aceptada tiene varias deficiencias.
Todos estos problemas pueden superarse simplemente incluyendo backticks en el SEPARATOR
para su GROUP_CONCAT
y utilizando una WHERE
condición en lugar de REPLACE()
. Para mis propósitos (e imagino muchos otros), quería que los nombres de las columnas se devolvieran en el mismo orden en que aparecen en la tabla. Para lograr esto, aquí usamos una ORDER BY
cláusula explícita dentro de la GROUP_CONCAT()
función:
SELECT CONCAT(
'SELECT `',
GROUP_CONCAT(COLUMN_NAME ORDER BY `ORDINAL_POSITION` SEPARATOR '`,`'),
'` FROM `',
`TABLE_SCHEMA`,
'`.`',
TABLE_NAME,
'`;'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE `TABLE_SCHEMA` = 'my_database'
AND `TABLE_NAME` = 'my_table'
AND `COLUMN_NAME` != 'column_to_omit';
Llegué bastante tarde en encontrar una respuesta para esto, dicho es como siempre lo he hecho y, francamente, es 100 veces mejor y más ordenado que la mejor respuesta, solo espero que alguien lo vea. Y encontrarlo útil
//create an array, we will call it here.
$here = array();
//create an SQL query in order to get all of the column names
$SQL = "SHOW COLUMNS FROM Table";
//put all of the column names in the array
foreach($conn->query($SQL) as $row) {
$here[] = $row[0];
}
//now search through the array containing the column names for the name of the column, in this case i used the common ID field as an example
$key = array_search('ID', $here);
//now delete the entry
unset($here[$key]);
SELECT
declaración aquí, la palabra ni siquiera aparece una vez.
Select * es un antipatrón SQL. No debe usarse en el código de producción por muchas razones, incluyendo:
Se tarda un poco más en procesar. Cuando las cosas se ejecutan millones de veces, esas pequeñas partes pueden importar. Una base de datos lenta donde la lentitud es causada por este tipo de codificación descuidada es el tipo más difícil de ajustar.
Significa que probablemente esté enviando más datos de los que necesita, lo que causa cuellos de botella en el servidor y en la red. Si tiene una unión interna, las posibilidades de enviar más datos de los que necesita son del 100%.
Causa problemas de mantenimiento, especialmente cuando ha agregado nuevas columnas que no desea ver en todas partes. Además, si tiene una nueva columna, es posible que deba hacer algo en la interfaz para determinar qué hacer con esa columna.
Puede romper vistas (sé que esto es cierto en el servidor SQl, puede o no ser cierto en mysql).
Si alguien es lo suficientemente tonto como para reconstruir las tablas con las columnas en un orden diferente (lo cual no debe hacer pero sucede todo el tiempo), todo tipo de código puede romperse. Especialmente codifique un inserto, por ejemplo, donde de repente está colocando la ciudad en el campo address_3 porque no especifica, la base de datos solo puede ir en el orden de las columnas. Esto es lo suficientemente malo cuando cambian los tipos de datos, pero peor cuando las columnas intercambiadas tienen el mismo tipo de datos, ya que puede insertar datos incorrectos que son un desastre para limpiar. Debe preocuparse por la integridad de los datos.
Si se usa en una inserción, la romperá si se agrega una nueva columna en una tabla pero no en la otra.
Puede romper los disparadores. Los problemas de activación pueden ser difíciles de diagnosticar.
Agregue todo esto al tiempo que toma agregar los nombres de las columnas (diablos, incluso puede tener una interfaz que le permita arrastrar los nombres de las columnas (sé que lo hago en SQL Server, apuesto a que hay alguna forma de hacer esto es alguna herramienta que utiliza para escribir consultas mysql.) Veamos, "Puedo causar problemas de mantenimiento, puedo causar problemas de rendimiento y problemas de integridad de datos, pero bueno, ahorré cinco minutos de tiempo de desarrollo". en las columnas específicas que quieras.
También le sugiero que lea este libro: http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers-ebook/dp/B00A376BB2/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1389896688&sr=1- 1 y palabras clave = sql + antipatterns