SQL: convert all columns to VarChar(255) - mysql

After some searching here on stackoverflow and on the web, I couldn't find the answer to my question. I'm not a real SQL talent, but I'm trying to covert all the columns in my table to varchar (255). It has about 600 columns which are all varchar, but the size limit varies. I would like them all to be 255. Is there a way to not having to do this manually? I work with MySQL.
Thanks!

You need to generate the alter table statement by pulling the data from the database.
select 'alter table MyTableName modify column ' + column_name + ' varchar(255);'
from information_schema where table_name = 'MyTableName'
And then paste the results of this command into the query window and run it -- making sure it does what you want it to do. Do a backup first.
Or you could make one big alter statement (if MySql wouldn't choke on it) by replacing the semicolon with a comma.

This isn't what you really need to do. You have something more important to do: NORMALIZE YOUR DATABASE
Now, It's impossible that you have a normalized table with 600 columns. Split your entities in that table correctly, following at least the 3rd normal form rules. After that, you'll have a much better database which is easier to mantain.
To do this, you'll need to drop your current table, therefore, you don't need to change all the types to varchar(255) because you'll fix them during the creation of other tables.
This would be a good start to read: http://en.wikipedia.org/wiki/Database_normalization (thanks to #Tim Schmelter from question's comments)

First of all as mentioned by others you better off normalize you data.
In the meantime you can achieve your goal with dynamic SQL like this
DELIMITER $$
CREATE PROCEDURE change_to_varchar255(IN _tname VARCHAR(64))
BEGIN
SET #sql = NULL;
SELECT GROUP_CONCAT(
CONCAT_WS(' ', 'CHANGE', COLUMN_NAME, COLUMN_NAME, 'VARCHAR(255)'))
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = _tname
AND DATA_TYPE = 'varchar'
AND CHARACTER_MAXIMUM_LENGTH < 255
AND TABLE_SCHEMA = SCHEMA();
SET #sql = CONCAT_WS(' ', 'ALTER TABLE', _tname, #sql);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
Sample usage:
CALL change_to_varchar255('table1');
Here is SQLFiddle demo

If you are using PhpMyAdmin or other, you can also click on the button to modify the table.
When you are on the web page, press Ctrl+Shift+J under Windows or Cmd+Opt+J under Mac to open the console window in the Chrome Developer tools. Now enter the following command to replace all occurrences of the number 255 with 100 :
document.body.innerHTML = document.body.innerHTML.replace(/255/g, "100").
Finally, click on the button to execute the query.

Related

ı can't use variables in MySQL commands

set #tmpGuid = REPLACE( uuid(),'-',''); set #fieldName = concat('deneme' , '_' , #tmpGuid); ALTER TABLE table_name RENAME COLUMN deneme to #fieldName;
https://i.stack.imgur.com/ciQ44.png
how can use my variable on mysql commands
Variables are meant to store data, not code. In SQL, table and column names count as the latter. From User-Defined Variables:
User variables are intended to provide data values. They cannot be used directly in an SQL statement as an identifier or as part of an identifier, such as in contexts where a table or database name is expected, or as a reserved word such as SELECT.
Many DBMS don't allow DDL statements to be parameterised. I.e. alter, create statements and such.
However this doesn't mean it's impossible. What you'd need to do is convert your statement to dynamic SQL, which you can manipulate in every way possible (including inserting parameters into the string).
Then simply executing it.
In your example:
SET #tmpGuid = REPLACE( uuid(),'-','');
SET #fieldName = concat('deneme' , '_' , #tmpGuid);
SET #sql = CONCAT('ALTER TABLE table_name RENAME COLUMN deneme to ', #fieldName);
PREPARE dynamic_SQL FROM #sql;
EXECUTE dynamic_SQL;
DEALLOCATE PREPARE dynamic_SQL;
Ofcourse using dynamic SQL has it's own troubles, and opens up potential risks. But it's the only way to do something like this.
See it in action: Here

Mysql sum all columns starting with some letters

I am trying add one column in my Mysql database that sums all the columns starting by 'tokenvalid' which can take the value of 1 or 0.
And let's say I have 50 columns like that in my database (i.e. tokenvalid1, tokenvalid2 ...., tokenvalide50) with other columns between.
Please find below the code I would like to implement. I know that is not correct at all but it is just to give you an idea of what I am trying to do.
Thank you for your help!
'SELECT *, sum(column_name LIKE "tokenvalid"%) as total FROM points WHERE 1'
This post should help you. The post describes how to get the columns and then query for results.
MySQL Like statement in SELECT column_name
Something like this should help you.
SET #colname = (SELECT GROUP_CONCAT(`column_name`) from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='points' AND `column_name` LIKE 'tokenvalid%');
SET #table = 'points';
SET #query = CONCAT('SELECT SUM(',#colname,') FROM ', #table);
PREPARE stmt FROM #query;
EXECUTE stmt;
Similar to this answer by RocketDonkey
If the string is in your external application (like PHP), sure, just construct the MySQL statement.
If the string is inside a MySQL table, you can't. MySQL has no eval() or such function. The following is impossible:
Suppose you have a table 'queries' with a field "columnname" that refers to one of the column names in the table "mytable". There might be additional columns in 'queries' that allow you to select the columnname you want...
INSERT INTO queries (columname) VALUES ("name")
SELECT (select columnname from queries) from mytable
You can however work with PREPARED STATEMENTS. Be aware this is very hacky.
SELECT columnname from queries into #colname;
SET #table = 'mytable';
SET #s = CONCAT('SELECT ',#colname,' FROM ', #table);
PREPARE stmt FROM #s;
EXECUTE stmt;

How to delete all MySQL tables beginning with a certain prefix?

I've found another thread on this question, but I wasn't able to use its solutions, so I thought I'd ask with more clarity and detail.
I have a large MySQL database representing a vBulletin forum. For several years, this forum has had an error generated on each view, each time creating a new table named aagregate_temp_1251634200, aagregate_temp_1251734400, etc etc. There are about 20,000 of these tables in the database, and I wish to delete them all.
I want to issue a command that says the equivalent of DROP TABLE WHERE TABLE_NAME LIKE 'aggregate_temp%';.
Unfortunately this command doesn't work, and the Google results for this problem are full of elaborate stored procedures beyond my understanding and all seemingly tailored to the more complex problems of different posters.
Is it possible to write a simple statement that drops multiple tables based on a name like match?
There's no single statement to do that.
The simplest approach is to generate a set of statements, and execute them individually.
We can write a simple query that will generate the statements for us:
SELECT CONCAT('DROP TABLE `',t.table_schema,'`.`',t.table_name,'`;') AS stmt
FROM information_schema.tables t
WHERE t.table_schema = 'mydatabase'
AND t.table_name LIKE 'aggregate\_temp%' ESCAPE '\\'
ORDER BY t.table_name
The SELECT statement returns a rowset, but each row conveniently contains the exact SQL statement we need to execute to drop a table. (Note that information_schema is a builtin database that contains metadata. We'd need to replace mydatabase with the name of the database we want to drop tables from.
We can save the resultset from this query as a plain text file, remove any heading line, and voila, we've got a script we can execute in our SQL client.
There's no need for an elaborate stored procedure.
A little googling found this:
SELECT 'DROP TABLE "' + TABLE_NAME + '"'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'prefix%'
This should generate a script.
Source: Drop all tables whose names begin with a certain string
From memory you have to use prepared statements, for example: plenty of samples on stack exchange
I would recommend this example:
SQL: deleting tables with prefix
The SQL from above, this one includes the specific databasename - it builds it for you
SELECT CONCAT( 'DROP TABLE ', GROUP_CONCAT(table_name) , ';' )
AS statement FROM information_schema.tables
WHERE table_schema = 'database_name' AND table_name LIKE 'myprefix_%';
Here is a different way to do it:
MySQL bulk drop table where table like?
This will delete all tables with prefix "mg_"
No need to copy and paste rowsets and in phpadmin copying and pasting is problematic as it will cut off long table names and replace them with '...' ruining set of sql commands.
Also note that '_' is a special character so thats why 'mg_' should be encoded as 'mg\_'
(and FOREIGN_KEY_CHECKS needs to be disabled in order to avoid error messages)
SET FOREIGN_KEY_CHECKS = 0;
SET GROUP_CONCAT_MAX_LEN=32768;
SET #tables = NULL;
SELECT GROUP_CONCAT('`', table_name, '`') INTO #tables
FROM information_schema.tables
WHERE table_schema = (SELECT DATABASE()) and table_name like 'mg\_%';
SELECT IFNULL(#tables,'dummy') INTO #tables;
SET #tables = CONCAT('DROP TABLE IF EXISTS ', #tables);
PREPARE stmt FROM #tables;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET FOREIGN_KEY_CHECKS = 1;

MySQL bulk drop table where table like?

DROP TABLE (
SELECT table_name
FROM information_schema.`TABLES`
WHERE table_schema = 'myDatabase' AND table_name LIKE BINARY 'del%');
I know this doesn't work! What is the equivalent for something like this in SQL? I can whip out a simple Python script to do this but was just wondering if we can do something with SQL directly. I am using MySQL. Thank you!
You can use prepared statements -
SET #tables = NULL;
SELECT GROUP_CONCAT('`', table_schema, '`.`', table_name,'`') INTO #tables FROM information_schema.tables
WHERE table_schema = 'myDatabase' AND table_name LIKE BINARY 'del%';
SET #tables = CONCAT('DROP TABLE ', #tables);
PREPARE stmt1 FROM #tables;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
It will generate and execute a statement like this -
DROP TABLE myDatabase.del1, myDatabase.del2, myDatabase.del3;
A minor improvement to #Devart's answer:
SET #tables = NULL;
SELECT GROUP_CONCAT(table_schema, '.`', table_name, '`') INTO #tables FROM
(select * from
information_schema.tables
WHERE table_schema = 'myDatabase' AND table_name LIKE 'del%'
LIMIT 10) TT;
SET #tables = CONCAT('DROP TABLE ', #tables);
select #tables;
PREPARE stmt1 FROM #tables;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
This script should be executed repeatedly until the console's output is NULL
The changes are:
backtick (`) wrapping the table name (if it contains non standard characters)
added a LIMIT to avoid the truncation issue I commented about
added a "print" (select #tables;) to have some kind of control when to stop executing the script
If you just need to quickly drop a bunch of tables (not in pure SQL, so not directly answering this question) a one line shell command can do it:
echo "show tables like 'fsm%'" | mysql | tail +2 | while read t; do echo "drop table \`$t\`;"; done | mysql
I found it useful to add an IFNULL to Devart's solutions to avoid generating an error if there are no tables matching the query.
SET #tables = IFNULL(CONCAT('DROP TABLE ', #tables),'SELECT NULL;');
In addition to #Devart's answer:
If you have many tables, you may need to set group_concat_max_len:
SET group_concat_max_len = 4096;
You can do this quickly and easily if you have phpMyAdmin available and the requirement is to drop tables with a specific prefix. Go to the database you want, and show the list of all the tables. Since tables are shown in alphabetic order, the tables with the prefix for deletion will all appear together. Go to the first one, and click the tick box on the left hand side. Then scroll down to the last table with the prefix, hold down shift, and click the tick box. That results in all the tables with the prefix being ticked. Go to the bottom of the list, and select the action drop for all selected tables. Go through with the deletion, checking that the SQL generated looks right!

How can I "select *" from a table in MySQL but omit certain columns?

I have a table with the following columns:
id,name,age,surname,lastname,catgory,active
Instead of: SELECT name,age,surname,lastname,catgory FROM table
How can I make something like this: SELECT * FROM table [but not select id,active]
While many say it is best practice to explicitly list every column you want returned, there are situations where you might want to save time and omit certain columns from the results (e.g. testing). Below I have given two options that solve this problem.
1. Create a Function that retrieves all of the desired column names: ( I created a schema called functions to hold this function)
DELIMITER $$
CREATE DEFINER=`root`#`%` FUNCTION `getTableColumns`(_schemaName varchar(100), _tableName varchar(100), _omitColumns varchar(200)) RETURNS varchar(5000) CHARSET latin1
BEGIN
SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns
WHERE table_schema = _schemaName AND table_name = _tableName AND FIND_IN_SET(COLUMN_NAME,_omitColumns) = 0 ORDER BY ORDINAL_POSITION;
END
Create and execute select statement:
SET #sql = concat('SELECT ', (SELECT
functions.getTableColumns('test', 'employees', 'age,dateOfHire')), ' FROM test.employees');
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
2. OR without writing a function you could:
SET #sql = CONCAT('SELECT ', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM
information_schema.columns WHERE table_schema = 'test' AND table_name =
'employees' AND column_name NOT IN ('age', 'dateOfHire')),
' from test.eployees');
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
*Replace test with your own schema name
**Replace employees with your own table name
***Replace age,dateOfHire with the columns you want to omit (you can leave it blank to return all columns or just enter one column name to omit)
** **You can adjust the lengths of the varchars in the function to meet your needs
The only way to do that that I know if is to enumerate each column you do want... no negative filters that I'm aware of.
select name, age, surname, lastname, category from table
you can't do that, sorry. Actually you shouln't have done it if you could - specifying these things explicitly is always better, assume other developer adds new field and your application will fail
You are too advanced.
The only data language that I have seen that supports your syntax is the D language with its "...ALL BUT ..." construct:
Wikipedia - D Language Specification
There are some reference implementations available, but mostly for teaching purposes.
Unless there's some special extension in MySql you cannot do that. You either get all, or have to explicitly state what you want. It is best practice to always name columns, as this will not alter the query behaviour even if the underlying table changes.
There is no SQL syntax to support:
select * from table but not select id,active
If you want all but one or more columns, you have to explicitly define the list of columns you want.
You should not be using select * anyway. Enumerate the columns you want and only the columns you want, that is the best practice.
SET #sql = CONCAT('SELECT ',
(SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), '<columns_to_delete>,', '')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '<table>'
AND TABLE_SCHEMA = '<database>'),
' FROM <table>');
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
I'm fairly certain you can't. Probably the best way I can think of is to create SELECT name, age, surname, lastname, category FROM table as a view, then just SELECT * FROM view. I prefer to always select from a view anyway.
However, as others have pointed out, if another column gets added to the view your application could fail. On some systems as well (PostgreSQL is a candidate) you cannot alter the table without first dropping the view so it becomes a bit cumbersome.
If the reason is to avoid column duplication error without having to specify a long list of columns:
temporarily change the name of column that is a duplicate to enable the view to be created.
delete the duplicate column from the select and save view
rename the changed column name
If the reason is simply to omit a one or more columns:
create view and delete column/s from select