Networking

Unix and Linux network configuration. Multiple network interfaces. Bridged NICs. High-availability network configurations.

Applications

Reviews of latest Unix and Linux software. Helpful tips for application support admins. Automating application support.

Data

Disk partitioning, filesystems, directories, and files. Volume management, logical volumes, HA filesystems. Backups and disaster recovery.

Monitoring

Distributed server monitoring. Server performance and capacity planning. Monitoring applications, network status and user activity.

Commands & Shells

Cool Unix shell commands and options. Command-line tools and application. Things every Unix sysadmin needs to know.

Home » Commands & Shells, Data, Featured, MySQL

Convert XLSX to a MySQL Table

Submitted by on October 14, 2021 – 11:49 am

Some people find it hard to let go of Excel even when the situation is ripe for a database. And so dozens of different versions of the same spreadsheet edited by many people are floating around Sharepoint, and nobody quite knows which one to use.

Instead of changing everyone’s mind, I found the best I can do is maintain my own version of the spreadsheet in a database table. Eventually, when people get thoroughly confused, they’ll come to me.

I needed a shell script to take an arbitrary Excel spreadsheet and convert it into a database table. And I didn’t want to create the table manually either: I wanted it to be generated dynamically based on the spreadsheet itself.

And so here it is below (and you can also get it from my GitHub repo). You can install it like so:

curl -s0 -k -o ~/excel_to_mysql.sh "https://raw.githubusercontent.com/igoros777/kw/master/excel_to_mysql.sh" && chmod 755 ~/excel_to_mysql.sh && ln -s ~/excel_to_mysql.sh /usr/bin/excel2mysql

The script relies on your spreadsheet having column headers. The script will also sanitize the input data as best as it can to work with MySQL. All the columns created will be VARCHAR(255). Additionally, you need to have unoconv installed to allow the script to convert XLSX to CSV. I have some instructions for this here.

The syntax is simple:

excel2mysql -f /path/to/spreadsheet.xlsx -d <db_name> [-u <db_user>] [-h <db_host>] [-p <db_pass>] [-t <table_name>]

And here’s the script:

#!/bin/bash
#
#                                      |
#                                  ___/"\___
#                          __________/ o \__________
#                            (I) (G) \___/ (O) (R)
#                                   Igor Os
#                               igor@igoros.com
#                               www.igoros.com
#                                 2021-01-22
# ----------------------------------------------------------------------------
# Convert a basix Excel spreadsheet into a database table
# ----------------------------------------------------------------------------

while getopts ":f:h:d:u:p:t:" OPTION
do
    case "${OPTION}" in
    f)
            datafilexls="${OPTARG}" ;;
        h)
            db_host="${OPTARG}" ;;
        d)
            db_name="${OPTARG}" ;;
    u)
        db_user="${OPTARG}" ;;
    p)
        db_pass="${OPTARG}" ;;
    t)
      tbl_name="${OPTARG}" ;;
        \? ) echo "Unknown option: -$OPTARG" >&2; usage;;
    :  ) echo "Missing option argument for -$OPTARG" >&2; usage;;
    *  ) echo "Unimplemented option: -$OPTARG" >&2; usage;;
    esac
done

help() {
    this_script=$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")
cat << EOF
    SYNTAX:
        ${this_script} -f /path/to/spreadsheet.xlsx -d <db_name> [-u <db_user>] [-h <db_host>] [-p <db_pass>] [-t <table_name>]
EOF
}

configure() {
  if [ -z "${datafilexls}" ] || [ ! -f "${datafilexls}" ]; then
    help
    exit 11
  else
    datafile="${datafilexls%.*}.csv"
  fi
    if [ ! "${db_name}" ]; then
        help
        exit 15
    fi
    if [ ! "${db_user}" ]; then
        db_user="$(whoami)"
    fi
    if [ ! "${db_host}" ]; then
        db_host="localhost"
    fi
    if [ ! "${db_pass}" ]; then
        echo -n "Enter password for ${db_user}: "
        read -s db_pass
        echo
        if [ ! "${db_pass}" ]; then
            help
            exit 19
        fi
    fi
  if [ ! "${tbl_name}" ]; then
    tbl_name="$(basename "${datafilexls}" | sed -e 's/\./_/g' -e 's/\-/_/g' -e 's/ /_//g')"
    echo "Data will be loaded into ${tbl_name}"
  fi
  tmpdir="/var/tmp"
  if [ ! -d "${tmpdir}" ] ; then mkdir "${tmpdir}" ; fi
  table_create_sql="${tmpdir}/${this_script}_table_create.sql"
  if [ -f "${table_create_sql}" ]; then /bin/rm -f "${table_create_sql}"; fi
  table_load_sql="${tmpdir}/${this_script}_table_load.sql"
  if [ -f "${table_load_sql}" ]; then /bin/rm -f "${table_load_sql}"; fi
  MYSQL="/usr/bin/mysql --batch --skip-column-names --max_allowed_packet=100M -h${db_host} -u${db_user} -p${db_pass} ${db_name} -e"
  MYSQL2="/usr/bin/mysql --batch --skip-column-names --max_allowed_packet=100M -h${db_host} -u${db_user} -p${db_pass} ${db_name}"
}

xls_convert() {
  unoconv -i FilterOptions=44,34,76,2,1/5/2/1/3/1/4/1 -f csv -d spreadsheet -o "${datafile}" "${datafilexls}"
  if [ ! -f "${datafile}" ]; then
    echo "Unable to convert "${datafilexls}" to CSV. Exiting..."
    exit 22
  fi
}

table_drop() {
  ${MYSQL} "DROP TABLE ${tbl_name};"
}

table_create() {
cat << EOF > "${table_create_sql}"
CREATE TABLE ${tbl_name} (
\`id\` INT(11) NOT NULL AUTO_INCREMENT,
  $(i=1; head -1 "${datafile}" | tr , '\n' | sed -r 's/ /_/g' | sed -r 's/[\(\)]//g' | \
  sed -e 's/\(.*\)/\L/' | sed 's@/@_@g' | sed 's/->/to/g' | sed 's/ $//g' | while read line
  do
    if [ ! -z "${line}" ]
    then
      echo "\`${line}\` VARCHAR(255),"
    else
      echo "\`field_${i}\` VARCHAR(255),"
    fi
    (( i = i + 1 ))
  done)
PRIMARY KEY (\`id\`),
UNIQUE INDEX \`id_UNIQUE\` (\`id\` ASC))
ENGINE = MyISAM ;;
EOF

${MYSQL2} < "${table_create_sql}"
}

data_load() {
cat << EOF2 > "${table_load_sql}"
LOAD DATA LOCAL INFILE '${datafile}' INTO TABLE ${tbl_name} \
FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES \
(\
$(i=1; head -1 "${datafile}" | tr , '\n' | sed -r 's/ /_/g' | sed -r 's/[\(\)]//g' | \
sed -e 's/\(.*\)/\L/' | sed 's@/@_@g' | sed 's/->/to/g' | sed 's/fdqn/fqdn/g' | while read line
do
if [ ! -z "${line}" ]
then
echo -n "${line}, "
else
echo -n "field_${i}, "
fi
(( i = i + 1 ))
done | sed 's/, $//g')
);
EOF2

${MYSQL2} < "${table_load_sql}"
}

# RUNTIME

configure
xls_convert
table_drop 2>/dev/null
table_create
data_load

 

Print Friendly, PDF & Email

Leave a Reply