Bash mysql array do not get empty value - mysql

My Bash script makes an array from MySQL:
info_tmp=$(mysql --batch --silent -u root -ppassword database -e "SELECT id,info1,info2 FROM table WHERE id=1")
info=($(for i in $info_tmp;do echo $i;done))
info1=${info[1]}
My problem is, that, if info1 is an empty string in the database, then $info1 became info2.
How can I put an empty string into $info array?
Mysql Database:
Id | info1 | info2
1 | | data2
2 | data3 | data4
$info_tmp
1 data2
2 data3 data4
Thank you for your answer
This is the final code that worked (#Barmar):
IFS="|"
info_tmp=$(mysql --batch --silent -u root -ppassword database -e "SELECT CONCAT_WS('|', id,info1,info2) FROM table WHERE id=1")
info=(${info_tmp// / })
info1=${info[1]}

If there's a character that shouldn't appear in any of the columns, use that as a delimiter.
IFS="|"
info_tmp=$(mysql --batch --silent -u root -ppassword database -e "SELECT CONCAT_WS('|', id,info1,info2) FROM table WHERE id=1")
This works because bash doesn't merge sequences of non-whitespace delimiters in IFS, only whitespace characters.
I'm not sure what the point of the for loop that copies $info_tmp to $info is, but you need to do the same thing there. If you use whitespace as your word delimiter, you'll never be able to get empty array values from command substitution.

What about temporarily adding a single character in your for-loop:
info_tmp=$(mysql --batch --silent -u root -ppassword database -e "SELECT id,info1,info2 FROM table WHERE id=1")
info=($(for i in $info_tmp;do echo " "$i;done))
info1=$(${info[1]} | cut -c 2-)

Related

How to save multiple columns to bash arrays with 1 select in mysql

I'm trying to save multiple columns in bash arrays with one query, but I can't figure it out.
Now I have 3 SELECTs like this:
read -d \t -ra data1<<< $(mysql -u root -p'password' -D'users_info' -se 'SELECT data1 FROM users_logs')
read -d \t -ra data2<<< $(mysql -u root -p'password' -D'users_info' -se 'SELECT data2 FROM users_logs')
read -d \t -ra data3<<< $(mysql -u root -p'password' -D'users_info' -se 'SELECT data3 FROM users_logs')
and it's working, but I wonder, if this is an optimal way. I think that I could achieve this with one query.
I was trying to do something with mysql --batch and mapfile, but couldn't make it.
and output of running:
mysql -u root -p'password' -D'users_info' -se 'SELECT data1, data2, data3 FROM users_logs'
is:
somemail1#gmail.com 2 2z7bhxb55d3
somemail2#gmail.com 2 we3cq3micu9cn
somemail3#gmail.com 1 we3cq1dicu9cn
All those data are varchar(30).
Assuming the objective is to read a grid of data into multiple arrays (with each column being loaded into a separate array) ...
For dynamically generating/populating arrays using bash namerefs take a look at this answer.
If the number of arrays (and their names) are predefined ...
First some data to simulate the OP's output:
$ cat mysql.out
somemail1#gmail.com 2 2z7bhxb55d3
somemail2#gmail.com 2 we3cq3micu9cn
somemail3#gmail.com 1 we3cq1dicu9cn
NOTE: The following code assumes the column data does not include white space, eg, the above file has 3 columns and not 1 column with embedded spaces; otherwise OP will need to insure the stream of input has a well-defined column delimiter that can be used by the while loop
One bash loop idea:
unset data1 data2 data3
typeset -a data1 data2 data3
i=0
while read -r col1 col2 col3
do
(( i++ ))
data1[${i}]="${col1}"
data2[${i}]="${col2}"
data3[${i}]="${col3}"
done < mysql.out # replace this with ...
# done < <(mysql ... SELECT data1,data2,data3 ...) # this to have mysql results fed directly into 'while' loop
This gives us:
$ typeset -p data1 data2 data3
declare -a data1=([1]="somemail1#gmail.com" [2]="somemail2#gmail.com" [3]="somemail3#gmail.com")
declare -a data2=([1]="2" [2]="2" [3]="1")
declare -a data3=([1]="2z7bhxb55d3" [2]="we3cq3micu9cn" [3]="we3cq1dicu9cn")
If you don't mind the indices starting # 0 ...
unset data1 data2 data3
typeset -a data1 data2 data3
while read -r col1 col2 col3
do
data1+=("${col1}")
data2+=("${col2}")
data3+=("${col3}")
done < mysql.out
This gives us:
$ typeset -p data1 data2 data3
declare -a data1=([0]="somemail1#gmail.com" [1]="somemail2#gmail.com" [2]="somemail3#gmail.com")
declare -a data2=([0]="2" [1]="2" [2]="1")
declare -a data3=([0]="2z7bhxb55d3" [1]="we3cq3micu9cn" [2]="we3cq1dicu9cn")

How to get a value without characters like "- , + "?

This is the normal output:
mysql> select module_id from Modules where Module_name = 'STP_XENA';
+-----------+
| module_id |
+-----------+
| 3 |
+-----------+
1 row in set (0.00 sec)
Can I get answer for the query as only "3"
I need something like,
mysql> select module_id from Modules where Module_name = 'STP_XENA';
3
mysql>
But not from bash or console. Is there any option to do this ?
You cannot do it inside MySQL editor, AFAIK. If you execute the script from console, then adding -B switch can get you desired result.
> mysql -B -u username -p password -e "select module_id from Modules where Module_name = 'STP_XENA';" DBNAME
will yield value with column name:
module_id
3
Also, if you add --skip-column-names
> mysql -B --skip-column-names -u username -p password -e "select module_id from Modules where Module_name = 'STP_XENA';" DBNAME
will yield only value (minus column name):
3
HTH
EDIT: You may start mysql with --skip-column-names switch. I am not sure about -B though. If you are able to start with -B, then great.
You want to use the query result in something like a bash script?
If so, you could do with:
mysql -u{user} -p{password} -s -N -e "select module_id from Modules where Module_name = 'STP_XENA'" database_name
Example:
module_id = `mysql -u{user} -p{password} -s -N -e "select module_id from Modules where Module_name = 'STP_XENA'" database_name`
echo $module_id

Pass MySQL variables to script from command line

I have a MySQL update script I'd like to run from the command line, but I want to be able to pass a stage domain variable to the script.
I know this won't work, but it's the best way I can describe what I'm trying to do:
$ -uroot -hlocalhost mydatabase --execute "SET #domain = 'mydomain.dev' " < ./sql/update_domain.sql
Inside the script, I'm using the #domain variable, to update some configuration variables in a config table, using commands like this:
UPDATE my_cfg SET value = #domain WHERE name = 'DOMAIN';
Basically I want to prefix the SET #domain on the update_domain.sql file.
Any ideas how I can rectify my approach?
In your BATCH File :
mysql -e "set #domain=PARAMVALUE;source ./sql/update_domain.sql"
And in you SQL file :
UPDATE my_cfg SET value = #domain WHERE name = 'DOMAIN';
you can do that with sed like this:
echo "UPDATE my_cfg SET value = '#domain#' WHERE name = 'DOMAIN'" | sed 's/#domain#/mydomain.dev/' | mysql -uusername -ppassword dbname
or update.sql has UPDATE:
cat update.sql | sed 's/#domain#/mydomain.dev/' | mysql -uusername -ppassword dbname
This works for me:
system("(echo \"SET #domain = 'newstore.personera.abc';\"; cat sql/set_domain.sql) > /tmp/_tmp.sql")
system("mysql -uroot -hlocalhost newstore.personera.dev < /tmp/_tmp.sql")
system("rm /tmp/_tmp.sql")
...calling with system() from Capistrano.
I've found a better solution.
--init-command=name SQL Command to execute when connecting to MariaDB server.
mysql --init-command="SET #foo = 1; SET #bar = 2" -e "SELECT #foo, #bar, VERSION()"
Output:
+------+------+-------------------------------------+
| #foo | #bar | VERSION() |
+------+------+-------------------------------------+
| 1 | 2 | 10.6.3-MariaDB-1:10.6.3+maria~focal |
+------+------+-------------------------------------+
It also works with file redirection.

bash - SQL Query Outputs to variable

Im new in bash scripting.
I want to save sql-query outputs in variable, but
actually I must connect for every query to mysql with:
mysql -u $MYUSER -p$MYPASS -D database
and want to save every output in seperatly variable
sample query is: SELECT domain FROM domains WHERE user='$USER'
to
$variable1 = FIRST_OUTPUT
$variable2 = 2ND_OUTPUT
thank you
Taken from bash script - select from database into variable, you can read the query result into a variable.
Example
mysql> SELECT * FROM domains;
+-------+---------+
| user | domain |
+-------+---------+
| user1 | domain1 |
| user2 | domain2 |
| user3 | domain3 |
+-------+---------+
Usage
$ myvar=$(mysql -D$MYDB -u$MYUSER -p$MYPASS -se "SELECT domain FROM domains")
$ echo $myvar
domain1 domain2 domain3
echo is the bash command for output. You can then split $myvar into separate variables:
$ read var1 var2 var3 <<< $myvar
$ echo $var1
domain1
$ echo $var2
domain2
You can combine these two commands into a single one:
read var1 var2 var3 <<< $(mysql -D$MYDB -u$MYUSER -p$MYPASS -se "SELECT domain FROM domains")
It is possible to store the results into arrays (useful if you don't know how many records there):
$ read -ra vars <<< $(mysql -D$MYDB -u$MYUSER -p$MYPASS -se "SELECT domain FROM domains")
$ for i in "${vars[#]}"; do
$ echo $i
$ done
domain1
domain2
domain3
Another way of doing is:
dbquery=`mysql -D$MYDB -u$MYUSER -p$MYPASS -se "SELECT domain FROM domains"`
dbquery_array=( $( for i in $dbquery ; do echo $i ; done ) )
The first line stores all the output from the query in a varriable dbquery in a array-like-way. The second line converts the dbquery into an array dbquery_array with a simple for loop.
I did this
variable=mysql -u root -ppassworrd database << EOF
select MAX(variable) AS a from table where variable2 = 'SOMETEXT' AND day(datevalue) >= 22;
EOF
I hope it helps

Easiest way to get count val from mysql in bash

Maybe i should use python or perl but i dont know any.
I have 4 statements and i would like to check if there are any errors longer then an hour. My user is setup so i dont need to enter a mysql user/pass. This statement is in mysql_webapp_error_check.sh
#!/bin/bash
mysql testdb -e "select count(*) from tbl where last_error_date < DATE_SUB(NOW(), INTERVAL 1 HOUR);"
How do i make it give me the return value (count(*)) instead of printing to screen?
Then i'll write an if statement and output to stdout/err for cron to use to email me (otherwise i want the script to be silent so nothing is emailed unless theres a problem)
Searched the same, -s for silent works exactly for me.
#!/bin/bash
result=`mysql testdb -s -e "select count(*) from tbl where last_error_date < DATE_SUB(NOW(), INTERVAL 1 HOUR);"`
echo result = .$result.
PS.: There is also a --batch parameter in my mysql Ver 14.14 Distrib 5.1.49 which "Write fields without conversion. Used with --batch" so its a little off-topic here, but should be mentioned here.
in bash, you use $() syntax.
#!/bin/bash
ret=$(mysql testdb -e "select count(*) from tbl where last_error_date < DATE_SUB(NOW(), INTERVAL 1 HOUR);")
if [[ "$ret" > 0 ]];then
echo "there is count"
else
echo "no count"
fi
I usually do this:
var=`mysql -e "SELECT COUNT(*) FROM ...\G" | awk '/COUNT/{print $2}/'`
For my part I simply use grep -v to exclude the line printing count(*) from the return of MySQL.
So I get the counter like that:
db_name="NAME_DB";
db_user="USER_DB";
db_pwd="PWD_DB";
counter=`mysql -u${db_user} -p${db_pwd} ${db_name} -e "SELECT count(*) FROM my_table WHERE something = '1';" | grep -v "count"`;
echo "Count for request: $counter";
I use it for some Wordpress stuff this way, reading databases infos from the wp-config.php file:
wp_db_infos="wp-config.php";
wp_db=`cat ${wp_db_infos} | grep "DB_NAME" | awk -F ', ' '{print $2}' | awk -F "'" '{print $2}'`;
wp_user=`cat ${wp_db_infos} | grep "DB_USER" | awk -F ', ' '{print $2}' | awk -F "'" '{print $2}'`;
wp_pwd=`cat ${wp_db_infos} | grep "DB_PASSWORD" | awk -F ', ' '{print $2}' | awk -F "'" '{print $2}'`;
img_to_update=`mysql -u${wp_user} -p${wp_pwd} ${wp_db} -e "SELECT count(*) FROM wp_offres WHERE maj_img = '1';" | grep -v "count"`;
#!/bin/bash
echo show databases\; | mysql -u root | (while read x; do
echo "$x"
y="$x"
done
echo "$y"
)
local count=$(mysql -u root --disable-column-names --batch --execute "SELECT COUNT(*) FROM mysql.user WHERE user = '$DstDbName'")
if [[ "$count" > 0 ]]
then
fi
--batch - do clear output w/o borders
--disable-column-names - prints only row with value
no creasy AWK used :)