Run Query to MySQL from a Bash Script - mysql

please help, whats wrong?
sudo -u root /etc/scripts/mysql.sh root 111111
#!/bin/bash
mysql --host=localhost --user=root --password=111111
mysql 1<< EOF
INSERT INTO
table1(id)
SELECT MAX(id) + 1 FROM table1;
EOF

You should just invoke MySQL once and specify the default database:
#!/bin/bash
mysql --host=localhost --user=root --password=111111 1 << EOF
INSERT INTO
table1(id)
SELECT MAX(id) + 1 FROM table1;
EOF

Use below script:
#!/bin/bash
USER='root'
PASS='root123'
mysql -u$USER -p$PASS mydb -e"insert into table1 (id) select (max(id) + 1) from table1;"
Note: As you are executing sql from same server so no need of localhost.
Now use as from directory where your script exists-
sh myscript.sh

Related

Insert timestamp into mysql column in shell

The following works for me:
mysql -u 'root' -h 8.8.8.88 mo -e 'UPDATE `path_last_updated`
SET timestamp="2012-01-03 00:00:00"'
However, the following does not:
TIMESTAMP=`date "+%Y-%m-%d-%T"`
mysql -u 'root' -h 8.8.8.88 mo -e 'UPDATE `path_last_updated`
SET timestamp=$TIMESTAMP'
How would I insert the timestamp from unix into my mysql table?
Update:
TIMESTAMP=`date "+%Y-%m-%d %T"`
mysql -u 'root' -h 8.8.8.88 mo -e "UPDATE `path_last_updated`
SET timestamp='$TIMESTAMP'"
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use near 'SET
timestamp='2013-01-31 15:46:00'' at line 1
Shell variable interpolation only works between double quotes ("), not single ('). You've also got backticks in there, which in a double-quoted string will be treated as an embedded shell command.
Try:
mysql -u 'root' -h 8.8.8.88 mo -e "UPDATE \`path_last_updated\`
SET timestamp='$TIMESTAMP'"
Also, fwiw, you have an extra dash (-) in your format for the date command, between the %d and %T.
ALTER TABLE to make it easier:
ALTER TABLE path_last_updated ADD date_entered timestamp DEFAULT CURRENT_TIMESTAMP
And then in shell:
mysql -u 'root' -h 8.8.8.88 mo -e "UPDATE path_last_updated SET timestamp=DEFAULT"

Bash select with string return

I'm executing the following query, to update the data in my database:
mysql -u root -ppassword -e "UPDATE table SET data = 1 WHERE id = 5"
Is there a way to execute the same query, but with the SELECT statement ? Of course there is, but how can I fetch the returned value then? Is that even possible?
mysql -u root -ppassword -e "UPDATE table SET data = 1 WHERE id = 5; SELECT data FROM table WHERE id = 5"

How to echo print statements while executing a sql script

We have a simple sql script which needs to be executed against a MySQL database and we would like print log statements on the progress of the script (e.g. Inserted 10 records into foo or Deleted 5 records from bar). How do we do this?
I would like to know the syntax to be used for insert/update/delete statements.
How do I know about the number of rows affected by my statement(s).
I would also like to control printing them using a ECHO off or on command at the top of the script.
The script should be portable across Windows / Linux OS.
This will give you are simple print within a sql script:
select 'This is a comment' AS '';
Alternatively, this will add some dynamic data to your status update if used directly after an update, delete, or insert command:
select concat ("Updated ", row_count(), " rows") as '';
I don't know if this helps:
suppose you want to run a sql script (test.sql) from the command line:
mysql < test.sql
and the contents of test.sql is something like:
SELECT * FROM information_schema.SCHEMATA;
\! echo "I like to party...";
The console will show something like:
CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME
def information_schema utf8
def mysql utf8
def performance_schema utf8
def sys utf8
I like to party...
So you can execute terminal commands inside an sql statement by just using \!, provided the script is run via a command line.
\! #terminal_commands
Just to make your script more readable, maybe use this proc:
DELIMITER ;;
DROP PROCEDURE IF EXISTS printf;
CREATE PROCEDURE printf(thetext TEXT)
BEGIN
select thetext as ``;
END;
;;
DELIMITER ;
Now you can just do:
call printf('Counting products that have missing short description');
What about using mysql -v to put mysql client in verbose mode ?
For mysql you can add \p to the commands to have them print out while they run in the script:
SELECT COUNT(*) FROM `mysql`.`user`
\p;
Run it in the MySQL client:
mysql> source example.sql
--------------
SELECT COUNT(*) FROM `mysql`.`user`
--------------
+----------+
| COUNT(*) |
+----------+
| 24 |
+----------+
1 row in set (0.00 sec)
You can use print -p -- in the script to do this example :
#!/bin/ksh
mysql -u username -ppassword -D dbname -ss -n -q |&
print -p -- "select count(*) from some_table;"
read -p get_row_count1
print -p -- "select count(*) from some_other_table;"
read -p get_row_count2
print -p exit ;
#
echo $get_row_count1
echo $get_row_count2
#
exit

How to feed mysql queries from bash

I'm trying to make a bash script that creates a mysql user and database but I can't find a way to feed the sql into mysql, I'm trying with this format:
mysql < echo "query"
But that is not working, see the example below:
mysql --host=localhost --user=user --password=password < echo "CREATE USER 'testuser'#'localhost' IDENTIFIED BY 'jakdJxct8W';
CREATE DATABASE IF NOT EXISTS 'testuser_dev' DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON 'testuser_dev' . * TO 'testuser'#'localhost';
CREATE DATABASE IF NOT EXISTS 'testuser_qa' DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON 'testuser_qa' . * TO 'testuser'#'localhost';"
How to feed mysql with the queries?
Try like this:
echo "select 1" | mysql
Try using a here document like this:
mysql --host=localhost --user=user --password=password << END
CREATE USER 'testuser'#'localhost' IDENTIFIED BY 'jakdJxct8W';
CREATE DATABASE IF NOT EXISTS 'testuser_dev' DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON 'testuser_dev' . * TO 'testuser'#'localhost';
CREATE DATABASE IF NOT EXISTS 'testuser_qa' DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON 'testuser_qa' . * TO 'testuser'#'localhost';
END
Alternatively place all you commands in text file and run it:
mysql --host=localhost --user=user --password=password < commands.sql
mysql --batch --silent -e 'SHOW TABLES';
Batch and silent are handy if you are planning to pipe the output
The reason your attempt did not work was because the < expects a file name and you fed it a string. You would have to do something like
echo "YOURQUERYSTRINGHERE">tmpfile
mysql --host=localhost --user=user --password=password dbname <tmpfile
ken's suggestion of
mysql --host=localhost --user=user --password=password -e "QUERY" dbname
can work, but if you try to use bash variables in your query you can fall foul of parameter expansion. eg
QUERY="select * from $MYTABLE WHERE name=\"silly#place.com\";"
mysql --host=localhost --user=user --password=password -e "$QUERY" mydbname
may not do what you expect.
One option is use
echo "$QUERY"|mysql --host=localhost --user=user --password=password mydbname
which works if the query string contains appropriate quoting. Another option is the "here" document as suggested by dogbane.
Have you tried mysql -e query?
cat <<EOD | mysql [-u user] [-ppassword] [database]
select 1;
select 2;
select 3;
EOD
in your case
cat <<EOD | mysql -u root -p
CREATE DATABASE IF NOT EXISTS testuser_dev DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON testuser_dev.* TO "testuser"#"localhost";
CREATE DATABASE IF NOT EXISTS testuser_qa DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON testuser_qa.* TO "testuser"#"localhost";
FLUSH PRIVILEGES;
EOD
For big queries in a bash script, you can try:
read -d '' SQL_QUERY_1 << EOF
SELECT prod.id as id, prod.title as title, comp.name as company, pho.id as photo_id, pho.image as photo_name
FROM products as prod
JOIN accounts as comp
ON comp.id = prod.account_id
JOIN photos as pho
ON pho.id = prod.featured_photo_id;
EOF
echo ${SQL_QUERY_1} | mysql

How do I kill all the processes in Mysql "show processlist"?

Because I see a lot of processes there, and the "time" column shows big values for all of them.
Mass killing operation saves time. Do it in MySql itself:
Run these commands
mysql> select concat('KILL ',id,';') from information_schema.processlist
where user='root' and time > 200 into outfile '/tmp/a.txt';
mysql> source /tmp/a.txt;
Reference
---------edit------------
if you do not want to store in file, store in a variable
Just run in your command prompt
> out1=$(mysql -B test -uroot -proot --disable-column-names -e "select concat('KILL ',id,';') from information_schema.processlist where user='root' and time > 200;")
> out2= $(mysql -B test -uroot -proot --disable-column-names -e "$out1")
You need to kill them one by one, MySQL does not have any massive kill command. You can script it in any language, for example in PHP you can use something like:
$result = mysql_query("SHOW FULL PROCESSLIST");
while ($row=mysql_fetch_array($result)) {
$process_id=$row["Id"];
if ($row["Time"] > 200 ) {
$sql="KILL $process_id";
mysql_query($sql);
}
}
I have also searched how to parse through MySQL the command SHOW PROCESSLIST and ended with a one-liner in a Shell:
mysqladmin processlist -u <USERNAME> -p<PASSWORD> | \
awk '$2 ~ /^[0-9]/ {print "KILL "$2";"}' | \
mysql -u <USERNAME> -p<PASSWORD>
mysqladmin processlist will print a table with the thread ids;
awk will parse from the second column only the numbers (thread ids) and generate MySQL KILL commands;
and finally the last call to mysql will execute the passed commands.
You can run grep before the awk command to filter a particular database name.
Only for mariaDB
It doesn't get simpler then this, Just execute this in mysql prompt.
kill USER username;
It will kill all process under provided username. because most of the people use same user for all purpose, it works!
I have tested this on MariaDB not sure about mysql.
The following will create a simple stored procedure that uses a cursor to kill all processes one by one except for the process currently being used:
DROP PROCEDURE IF EXISTS kill_other_processes;
DELIMITER $$
CREATE PROCEDURE kill_other_processes()
BEGIN
DECLARE finished INT DEFAULT 0;
DECLARE proc_id INT;
DECLARE proc_id_cursor CURSOR FOR SELECT id FROM information_schema.processlist;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN proc_id_cursor;
proc_id_cursor_loop: LOOP
FETCH proc_id_cursor INTO proc_id;
IF finished = 1 THEN
LEAVE proc_id_cursor_loop;
END IF;
IF proc_id <> CONNECTION_ID() THEN
KILL proc_id;
END IF;
END LOOP proc_id_cursor_loop;
CLOSE proc_id_cursor;
END$$
DELIMITER ;
It can be run with SELECTs to show the processes before and after as follows:
SELECT * FROM information_schema.processlist;
CALL kill_other_processes();
SELECT * FROM information_schema.processlist;
Or... in shell...
service mysql restart
Yeah, I know, I'm lazy, but it can be handy too.
I recently needed to do this and I came up with this
-- GROUP_CONCAT turns all the rows into 1
-- #q:= stores all the kill commands to a variable
select #q:=GROUP_CONCAT(CONCAT('KILL ',ID) SEPARATOR ';')
FROM information_schema.processlist
-- If you don't need it, you can remove the WHERE command altogether
WHERE user = 'user';
-- Creates statement and execute it
PREPARE stmt FROM #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
That way, you don't need to store to file and run all queries with a single command.
KILL ALL SELECT QUERIES
select concat('KILL ',id,';')
from information_schema.processlist
where user='root'
and INFO like 'SELECT%' into outfile '/tmp/a.txt';
source /tmp/a.txt;
If you don't have information_schema:
mysql -e "show full processlist" | cut -f1 | sed -e 's/^/kill /' | sed -e 's/$/;/' ; > /tmp/kill.txt
mysql> . /tmp/kill.txt
This snipped worked for me (MySQL server 5.5) to kill all MySQL processes :
mysql -e "show full processlist;" -ss | awk '{print "KILL "$1";"}'| mysql
We can do it by MySQL Workbench. Just execute this:
kill id;
Example:
kill 13412
That will remove it.
I'd combine bash and mysql:
for i in $(mysql -Ne "select id from information_schema.processlist where user like 'foo%user' and time > 300;"); do
mysql -e "kill ${i}"
done
Here is a solution that you can execute without relying on the operating system:
STEP 1: Create a stored procedure.
DROP PROCEDURE IF EXISTS kill_user_processes$$
CREATE PROCEDURE `kill_user_processes`(
IN user_to_kill VARCHAR(255)
)
READS SQL DATA
BEGIN
DECLARE name_val VARCHAR(255);
DECLARE no_more_rows BOOLEAN;
DECLARE loop_cntr INT DEFAULT 0;
DECLARE num_rows INT DEFAULT 0;
DECLARE friends_cur CURSOR FOR
SELECT CONCAT('KILL ',id,';') FROM information_schema.processlist WHERE USER=user_to_kill;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_rows = TRUE;
OPEN friends_cur;
SELECT FOUND_ROWS() INTO num_rows;
the_loop: LOOP
FETCH friends_cur
INTO name_val;
IF no_more_rows THEN
CLOSE friends_cur;
LEAVE the_loop;
END IF;
SET #s = name_val;
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT name_val;
SET loop_cntr = loop_cntr + 1;
END LOOP the_loop;
SELECT num_rows, loop_cntr;
END $$
DELIMITER ;
STEP 2: Call the stored procedure giving it the name of a database user whose processes you want to kill. You could rewrite the stored procedure to filter on some other criteria if you like.
CALL kill_user_processes('devdba');
mysqladmin pr -u 'USERNAME' -p'PASSWORD' | awk '$2~/^[0-9]+/{print $2}' | xargs -i mysqladmin -u 'USERNAME' -p'PASSWORD' kill {}
login to Mysql as admin:
mysql -uroot -ppassword;
And than run command:
mysql> show processlist;
You will get something like below :
+----+-------------+--------------------+----------+---------+------+-------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+--------------------+----------+---------+------+-------+------------------+
| 49 | application | 192.168.44.1:51718 | XXXXXXXX | Sleep | 183 | | NULL ||
| 55 | application | 192.168.44.1:51769 | XXXXXXXX | Sleep | 148 | | NULL |
| 56 | application | 192.168.44.1:51770 | XXXXXXXX | Sleep | 148 | | NULL |
| 57 | application | 192.168.44.1:51771 | XXXXXXXX | Sleep | 148 | | NULL |
| 58 | application | 192.168.44.1:51968 | XXXXXXXX | Sleep | 11 | | NULL |
| 59 | root | localhost | NULL | Query | 0 | NULL | show processlist |
+----+-------------+--------------------+----------+---------+------+-------+------------------+
You will see complete details of different connections. Now you can kill the sleeping connection as below:
mysql> kill 52;
Query OK, 0 rows affected (0.00 sec)
The following worked great for me:
echo "show processlist" | mysql | grep -v ^Id | awk '{print $1}' | xargs -i echo "KILL {}; | mysql"
for python language, you can do like this
import pymysql
connection = pymysql.connect(host='localhost',
user='root',
db='mysql',
cursorclass=pymysql.cursors.DictCursor)
with connection.cursor() as cursor:
cursor.execute('SHOW PROCESSLIST')
for item in cursor.fetchall():
if item.get('Time') > 200:
_id = item.get('Id')
print('kill %s' % item)
cursor.execute('kill %s', _id)
connection.close()
An easy way would be to restart the mysql server..
Open "services.msc" in windows Run, select Mysql from the list. Right click and stop the service. Then Start again and all the processes would have been killed except the one (the default reserved connection)
#! /bin/bash
if [ $# != "1" ];then
echo "Not enough arguments.";
echo "Usage: killQueryByDB.sh <db_name>";
exit;
fi;
DB=${1};
for i in `mysql -u <user> -h localhost ${DB} -p<password> -e "show processlist" | sed 's/\(^[0-9]*\).*/\1/'`; do
echo "Killing query ${i}";
mysql -u <user> -h localhost ${DB} -p<password> -e "kill query ${i}";
done;
Sometimes I have some zombies mysql processes that can't be killed (using MAMP Pro).
First get a list of all mysql processes:
ps -ax | grep mysql
Next kill every one of them with (replace processId with the first column in previous command result):
kill -9 processId
I used the command flush tables to kill all inactive connections which where actually the mass problem.
If you are using laravel then this is for you:
$query = "SHOW FULL PROCESSLIST";
$results = DB::select(DB::raw($query));
foreach($results as $result){
if($result->Command == "Sleep"){
$sql="KILL ". $result->Id;
DB::select(DB::raw($sql));
}
}
Of-course, you should use this use Illuminate\Support\Facades\DB; after your namespace.
Kill does not work if the running process is not yours. I merged some of these solutions and extended them to create a more simple one (at least to me).
m=mysql -p $password -h $host -u$user #you can also inline it of course
for i in `$m -e "show processlist" | awk '/$anySearchString/ {print $1}'`; do $m -e "call mysql.rds_kill($i);"; done
Query 1
select concat('KILL ',id,';') from information_schema.processlist where user='username' into outfile '/tmp/a.txt';
Query 2
source a.txt
This will enable you to kill all the queries in show processlist by specific user.