57

I've written a big sql script that creates a CSV file. I want to call a cronjob every night to create a fresh CSV file and have it available on the website.

Say for example I'm store my file in '/home/sites/example.com/www/files/backup.csv'

and my SQL is

SELECT * INTO OUTFILE '/home/sites/example.com/www/files/backup.csv'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM ( ....

MySQL gives me an error when the file already exists

File '/home/sites/example.com/www/files/backup.csv' already exists

Is there a way to make MySQL overwrite the file?

I could have PHP detect if the file exists and delete it before creating it again but it would be more succinct if I can do it directly in MySQL.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Derek Organ
  • 8,323
  • 17
  • 56
  • 75

7 Answers7

64

No, there's no way to overwrite it. From the docs:

file_name cannot be an existing file, which among other things prevents files such as /etc/passwd and database tables from being destroyed.

It might be a better idea to use a different filename each night, as having multiple backups means you can recover from problems that have existed for more than a day. You could then maintain a symlink that always points at the latest complete csv.

brian-brazil
  • 31,678
  • 6
  • 93
  • 86
9

Why not rm -f /home/sites/example.com/www/files/backup.csv in the script ran by cron?

You can run this from inside mysql. Just escape to the shell with \! For example:

Mysql> \! rm -f /home/sites/example.com/www/files/backup.csv

d-_-b
  • 21,536
  • 40
  • 150
  • 256
Flavius Stef
  • 13,740
  • 2
  • 26
  • 22
  • yea I can do that but it would be neater to do it in MySQL because loops through many databases and creates 100s of files. Looks like i may have to do it in PHP though. – Derek Organ Jun 06 '09 at 22:18
  • 1
    I went through this exact same process of trying to find a way and the conclusion was that you can't, as the docs mention, for security. – Artem Russakovskii Jun 06 '09 at 22:24
  • 1
    I've tried this.. but MySQL response was: "rm: cannot remove `/tmp/my-report-2013-10.csv': Operation not permitted" .. file permissions are 666. any thoughts? – lucasvscn Jan 29 '14 at 12:21
  • i like it, saves me having an additional cron. – Mark Jun 22 '15 at 09:36
  • 1
    executing `\! whoami` shows that user commands are executed with the user who started the mysql client, not the server. so, this user cannot delete the file; we get the error `rm: cannot remove `...': Operation not permitted` – David Portabella Apr 26 '18 at 13:51
3

There is no way.

Only one possible you can procedure with dynamic statement.

CREATE PROCEDURE export_dynamic(IN file_name char(64)) 
BEGIN 
set @myvar = concat('SELECT * INTO OUTFILE ',"'",file_name,"'",' FROM Table1') ; 
PREPARE stmt1 FROM @myvar; 
EXECUTE stmt1; 
Deallocate prepare stmt1; 
END; 
fedorqui
  • 275,237
  • 103
  • 548
  • 598
mani
  • 31
  • 1
3

For a job like this I would place it into a bash file, delete the file

#!/bin/bash
rm /path/to/backup.csv
./backup_sql_query.sh  <<-- This contains the script to backup to CSV.

The better option is to actually add a timestamp though. Disk space isn't expensive in this day and age.

user118659
  • 31
  • 1
2

3 steps to do this right. Your backup will be executed every night while you sleep (or not)

STEP 1 : Create a stored procedure for your SQL

CREATE PROCEDURE backupCSV()
SELECT * INTO OUTFILE '/home/sites/example.com/www/files/backup.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM ( ....

STEP 2 : Create a script "/home/backupCSV.sh" to delete old file and call the stored procedure

echo "$(date +"%Y-%m-%d %T") START MAINTENANCE SCRIPT "
rm /home/sites/example.com/www/files/backup.csv
echo "$(date +"%Y-%m-%d %T")    SUCCESS >> Old file deleted"
mysql --user=[user] --password=[password] [dataBaseName] --execute="CALL backupCSV();"
echo "$(date +"%Y-%m-%d %T")    SUCCESS >> New file created"
echo "$(date +"%Y-%m-%d %T") END MAINTENANCE SCRIPT "

STEP 3 : Update Crontab to execute the script everyday

# m h dom mon dow user  command

 0   3  * * *   root    sh -x /home/backupCSV.sh

STEP 4 (optionnal) : thanks me ;)

0

old question.. but there is an option OVERWRITE ON that you can add to the statement

SELECT * INTO OUTFILE '/home/sites/example.com/www/files/backup.csv'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n' OVERWRITE ON
...
da Bich
  • 494
  • 1
  • 4
  • 13
  • I've tested `OVERWRITE ON` with both MySQL 8.0 and MariaDB 10.3, both give "ERROR 1064 (42000) ... You have an error in your SQL syntax;". I also can't find mention of `OVERWRITE ON` in the documentation. So, which version / fork of MySQL supports this option? – dbdemon Jul 29 '18 at 16:16
  • 1
    Looks like Amazon RDS has the `OVERWRITE ON` option (when saving to S3 bucket): https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/AuroraMySQL.Integrating.SaveIntoS3.html – dbdemon Jul 29 '18 at 16:55
  • Correct.. sorry.. I'm using Amazon Rds (Aurora) – da Bich Jul 30 '18 at 19:34
0

Simply escape to a shell from within mysql and execute a rm command to remove the file before you attempt to write it. For example:

Mysql> \\! rm -f /home/sites/example.com/www/files/backup.csv
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
WxWizard
  • 460
  • 4
  • 6