This is a simple python 3 script to connect and run queries from the command line. It will export the data in many different file formats, and run many queries from a sql file.
E.g. run a simple select:
query "select * from example_table"
Output to an Excel spreadsheet:
query -o output.xlsx "select * from example_table"
Output as Json:
query --json "select * from example_table"
It uses JDBC to connect, so most databases can be used. i.e. any you have a JDBC driver for should work, see JayDeBeApi.)
- Install Python 3
- Install 3 python libraries:
pip install JayDeBeApi
pip install tabulate
pip install XlsxWriter
- Put
query
script in a folder on your path. - Put
query-completion.sh
somewhere andsource
it from your start bash/zsh script. - Download and place the JDBC drivers into a convenient folder.
- Setup
~/.ssh/secret_keys/query.properties
with each of the databases you want to connect to.
That's it, you should now be able to run query against a database.
query "select * from example_table"
-
Download and install Python 3
-
Install JayDeBeApi
pip install JayDeBeApi
-
Install Tabulate
pip install tabulate
-
Install XlsxWriter
pip install XlsxWriter
-
Put
query
script in a folder on your path, probably~/bin/
. -
Put
query-completion.sh
somewhere (~/bin/
) andsource
it from your start bash/zsh script. -
Download and copy the JDBC driver[s] for the databases you would like to connect to, you don't need them all just the ones you use.
- [MySQL](https://dev.mysql.com/downloads/connector/j/) - [Oracle](https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html) - [Oracle - Older versions](https://www.oracle.com/technetwork/jp/database/enterprise-edition/jdbc9201-083937-ja.html) - [Postgres](https://jdbc.postgresql.org/) - [SQLlite](https://github.com/xerial/sqlite-jdbc) - [SQL Server](https://docs.microsoft.com/en-us/sql/connect/jdbc/) - And many more.....
-
Setup a properties file which contains the connection details for each database you want to connect to.
Towards the top of the
query
script there is this line:PROP_FILE = str(Path.home()) + "/.ssh/secret_keys/query.properties"
By default query looks for a file in
~/.ssh/secret_keys/query.properties
. Within this file place the connection details for each database.db.default
will be thedefault
database. Here is an example using the latest (at the time of writing) MySQL driver, two databases are listed one MySQL,default
, and a MSSQL database,anotherdb.ro
.
[db.default]
db.default.driverpath=./JavaDBdrivers/mysql-connector-java-8.0.22.jar
db.default.driver=com.mysql.cj.jdbc.Driver
db.default.url=jdbc:mysql://localhost:3306/example
db.default.username=root
db.default.password=pa55word
[db.anotherdb.ro]
db.anotherdb.ro.driverpath=/home/jim/Downloads/Done/JavaDBdrivers/MicrosoftSQL/sqljdbc42.jar
db.anotherdb.ro.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
db.anotherdb.ro.url=jdbc:sqlserver://192.1.2.3:1433;databaseName=ADB
db.anotherdb.ro.username=auser
db.anotherdb.ro.password=apassword
I've included a Dockerfile so you can easily get a MySQL database and test data installed. The whole installation and setup of the database, literally takes 60 seconds from scratch (assuming you have docker installed). Here are the instructions:
- To build a MySQL image with the users/schema all setup use:
docker build -t="query-tool-database" .
- Then to run the image in a container on port 3306:
docker run --name query-tool-database -p 3306:3306 -d query-tool-database
You will now have a MySQL database which contains a schema called example which contains a table called example_table.
- If you need to you can connect to the terminal:
docker exec -i -t query-tool-database /bin/bash
- To stop and remove the container and image use the following:
docker stop query-tool-database
docker rm query-tool-database
docker rmi query-tool-database
In the query.properties
example above, the default
database will connect
to this docker database.
query --help
query -h
usage: query [-h]
[-d {default,anotherdb.ro}]
[-n] [-c] [-s] [-t] [-v]
[-j | -m | -f {plain,simple,github,grid,fancy_grid,pipe,orgtbl,
jira,presto,pretty,psql,rst,mediawiki,moinmoin,
youtrack,html,latex,latex_raw,latex_booktabs,textile} | -o OUTPUT]
[-l]
[sql_file_or_query]
query - A versatile command line query tool - v0.1 - Jim Cornmell DB
connection properties are read from {PROP_FILE}
positional arguments:
sql_file_or_query A query or sql file to run
optional arguments:
-h, --help show this help message and exit
-d {default,anotherdb.ro}, --database {default,anotherdb.ro}
Database to run queries against
-n, --no-header no header, default prints header row
-c, --count output total number of rows
-s, --show-query Show the query
-t, --show-time Show the time at which the query ran
-v, --verbose Show the count, query, time
-j, --json output Json
-m, --simple siMple format
-f {plain,simple,github,grid,fancy_grid,pipe,orgtbl,jira,presto,pretty,psql,
rst,mediawiki,moinmoin,youtrack,html,latex,latex_raw,latex_booktabs,textile},
--format {plain,simple,github,grid,fancy_grid,pipe,orgtbl,jira,presto,
pretty,psql,rst,mediawiki,moinmoin,youtrack,html,latex,
latex_raw,latex_booktabs,textile}
Format, options are listed
-o OUTPUT, --output OUTPUT
Output as CSV, XLSX, SQL, HTML, JSON file
-l, --list-databases Show the possible databases
query -d default "select * from example_table"
As this is the default database you do not need the -d option, so the following will work the same.
query "select * from example_table"
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
├──────┼─────────────────┼────────┤
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
Just use the name of your database connection from the query.properties file (remove the leading "db." though).
-
Use option
-d
for Database. -
query -d default "select * from example_table"
- Use option
-c
for Count. query -c "select * from example_table"
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
├──────┼─────────────────┼────────┤
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
2
- Use option
-s
for Show. query -s "select * from example_table"
select * from example_table
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
├──────┼─────────────────┼────────┤
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
- Use option
-t
for Time. query -t "select * from example_table"
2020-11-01 13:17:07.986766
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
├──────┼─────────────────┼────────┤
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
- Use option
-v
for Verbose. - Shorthand for using
-c
,-s
and-t
. query -v "select * from example_table"
select * from example_table
2020-11-01 13:17:42.948351
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
├──────┼─────────────────┼────────┤
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
2
query -j "select * from example.example_table"
{ "table": "example.example_table", "tableData": [{"id": 1, "name": "Carl Sagan", "year": 1934},{"id": 2, "name": "Richard Feynman", "year": 1918}]}
Note you can use the -v
option with this, but the output will not be adjusted
to be json complient:
query -v -j "select * from example_table"
select * from example.example_table
2021-03-04 09:59:42.201533
{ "table": "example.example_table", "tableData": [{"id": 1, "name": "Carl Sagan", "year": 1934},{"id": 2, "name": "Richard Feynman", "year": 1918}]}2
If you wish to name the table something else use -a as follows (this is also piped though jq for formatting).
query -j "select * from example.example_table" -a example.anothername | jq
And you should see:
{
"table": "example.anothername",
"tableData": [
{
"id": 1,
"name": "Carl Sagan",
"year": 1934
},
{
"id": 2,
"name": "Richard Feynman",
"year": 1918
}
]
}
You can also output directly to a json file as follows, note the file is appended to if it already exists:
query -o a.json -a schema_name.table_name "select * from example.example_table"
-
query -m "select * from example_table"
Shorthand for:
-
query -f simple "select * from example_table"
id name year
---- --------------- ------
1 Carl Sagan 1934
2 Richard Feynman 1918
query -n "select * from example_table"
╒═══╤═════════════════╤══════╕
│ 1 │ Carl Sagan │ 1934 │
├───┼─────────────────┼──────┤
│ 2 │ Richard Feynman │ 1918 │
╘═══╧═════════════════╧══════╛
query -f psql "select * from example_table"
+------+-----------------+--------+
| id | name | year |
|------+-----------------+--------|
| 1 | Carl Sagan | 1934 |
| 2 | Richard Feynman | 1918 |
+------+-----------------+--------+
query -f html "select * from example_table"
<table>
<thead>
<tr><th style="text-align: right;"> id</th><th>name </th><th style="text-align: right;"> year</th></tr>
</thead>
<tbody>
<tr><td style="text-align: right;"> 1</td><td>Carl Sagan </td><td style="text-align: right;"> 1934</td></tr>
<tr><td style="text-align: right;"> 2</td><td>Richard Feynman</td><td style="text-align: right;"> 1918</td></tr>
</tbody>
</table>
query -o file.csv "select * from example_table"
The contents of file.csv will be:
"id","name","year"
1, "Carl Sagan", 1934
2, "Richard Feynman", 1918
query -v -o file.xlsx "select * from example_table"
The contents of file.xlsx will be:
Rather than providing the query on the command line you can simply specify a sql file to run. If done each SQL command MUST end with a semi-colon.
Here is an example file, input.sql
, containing three SQL statements:
SELECT * FROM example_table;
SELECT * FROM example_table WHERE year > 1930;
SELECT * FROM example_table WHERE year < 1930;
query input.sql
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
├──────┼─────────────────┼────────┤
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
╒══════╤════════════╤════════╕
│ id │ name │ year │
╞══════╪════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
╘══════╧════════════╧════════╛
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
query -v input.sql
Reading input from SQL file input.sql...
SELECT
*
FROM
example_table
2020-11-01 16:57:40.831653
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
├──────┼─────────────────┼────────┤
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
2
SELECT
*
FROM
example_table
WHERE
year > 1930
2020-11-01 16:57:40.891882
╒══════╤════════════╤════════╕
│ id │ name │ year │
╞══════╪════════════╪════════╡
│ 1 │ Carl Sagan │ 1934 │
╘══════╧════════════╧════════╛
1
SELECT
*
FROM
example_table
WHERE
year < 1930
2020-11-01 16:57:40.893991
╒══════╤═════════════════╤════════╕
│ id │ name │ year │
╞══════╪═════════════════╪════════╡
│ 2 │ Richard Feynman │ 1918 │
╘══════╧═════════════════╧════════╛
1
You can also output to csv.
query -o file.csv input.sql
"id","name","year"
1, "Carl Sagan", 1934
2, "Richard Feynman", 1918
"id","name","year"
1, "Carl Sagan", 1934
"id","name","year"
2, "Richard Feynman", 1918
You can read many queries from a sql file and export to Excel XLSX file. Note that the resulting spreadsheet will have as many worksheets as there are queries. Sheet1 will be the first query, Sheet2 the second and so on.
query -o file.xlsx input.sql
Or use verbose to output info with each table.
query -v -o file.xlsx input.sql