Back to documentation
# PODNAME: ETL::Yertl::Help::ysql
# ABSTRACT: A guide to using ysql to work with SQL databases

=head1 DESCRIPTION

C<ysql> is a simple utility for working with SQL databases. Any database
that Perl's L<DBI|http://dbi.perl.org> library has a L<DBD driver
for|https://metacpan.org/search?q=DBD%3A%3A> will work with this
utility.

C<ysql> allows for selecting, inserting, updating, and running arbitrary
SQL on a database. It also stores database configurations and even
queries for later use (so you don't have to re-type that long query over
and over).

=head1 Configure Databases

To use ysql, first we have to configure a database. This saves us from having
to type the full DBI data source name (C<dbi:mysql:host=dev;database=mydb>) every
time. Instead, we can refer to our database by a nice name, like "dev", or
"prod".

    $ ysql --config dev dbi:SQLite:database.db

Later, we can update our configuration if we need to:

    $ ysql --config dev --database=dev.db

We can examine our configuration as a YAML document:

    $ ysql --config dev
    ---
    database: dev.db
    driver: SQLite

Let's add a production database as well:

    $ ysql --config prod --driver=SQLite --database=prod.db

And now we can check both of our configs:

    $ ysql --config
    ---
    dev:
      database: dev.db
      driver: SQLite
    prod:
      database: prod.db
      driver: SQLite

=head1 Working with Data

Now that we've configured some databases, let's insert some data. First we need
to make some tables:

    $ ysql prod 'CREATE TABLE users ( id INTEGER PRIMARY KEY \
        AUTOINCREMENT, name VARCHAR, email VARCHAR )'
    $ ysql dev 'CREATE TABLE users ( id INTEGER PRIMARY KEY \
        AUTOINCREMENT, name VARCHAR, email VARCHAR )'

Next let's insert some data using plain SQL:

    $ ysql prod 'INSERT INTO users ( name, email ) \
        VALUES ( "preaction", "preaction@example.com" )'
    $ ysql prod 'INSERT INTO users ( name, email ) \
        VALUES ( "postaction", "postaction@example.com" )'

Now, let's query for our data:

    $ ysql prod 'SELECT * FROM users'
    ---
    email: preaction@example.com
    id: 1
    name: preaction
    ---
    email: postaction.example.com
    id: 2
    name: postaction

=head1 SQL Helpers

Since SQL is a standard language, and can be verbose at times, ysql
provides some helpers for generating queries quickly.

=head2 Selecting Data

To quickly select all the data in a table, we can use the C<--select>
helper:

    $ ysql prod --select users

To filter our results, we can add a C<--where> helper:

    $ ysql prod --select users --where 'name = "preaction"'

The C<--order-by> helper can sort our results for us:

    $ ysql prod --select users --order-by id

=head2 Inserting Data

Now, lets say we want to copy our production database to dev for testing. To do
that, Yertl allows us to read YAML from C<STDIN> and execute a query for each YAML
document. The C<--insert> helper makes this easy:

    $ ysql prod --select users | ysql dev --insert users

The insert helper does all the work of determining what fields the input
has and executing the correct C<INSERT INTO> SQL query for each document
to insert.

=head2 Deleting Data

Much like selecting data, we can delete data using the C<--delete>
helper.

    $ ysql prod --delete users

The C<--where> helper can limit which rows get deleted:

    $ ysql prod --delete users --where 'name = "postaction"'

=head1 Placeholders

Additional arguments on the command-line are treated as placeholder
values, which fill in any C<?> in the query.

    $ ysql prod 'SELECT * FROM users WHERE name=?' postaction

This is especially helpful when using saved queries, below, or when
using C<xargs(1)>.

=head1 Interpolation

When piping in data and running custom SQL, Yertl allows a special
interpolation syntax (starting with a C<$>) to pick parts of the
document to fill in the query. So, to copy our users from prod to dev
again, we could do:

    $ ysql prod 'SELECT * FROM users' |
        ysql dev 'INSERT INTO users ( id, name, email ) \
            VALUES ( $.id, $.name, $.email )'

C<$.id> picks the "id" field, C<$.name> the "name" field, etc...

We can also pipe in data and run a select query, useful when we need to
find related information, or see if our two databases have the same
user names:

    $ ysql prod --select users |
        ysql dev 'SELECT * FROM users WHERE name=$.name'

=head1 Converting Formats

Yertl uses YAML as its default output, but we can easily convert to JSON or CSV
using the L<yto utility|yto>.

    $ ysql prod 'SELECT * FROM users' | yto csv
    email,id,name
    preaction@example.com,1,preaction
    postaction@example.com,2,postaction

    $ ysql prod 'SELECT * FROM users' | yto json
    {
       "email" : "preaction@example.com",
       "id" : "1",
       "name" : "preaction"
    }
    {
       "email" : "postaction@example.com",
       "id" : "2",
       "name" : "postaction"
    }

=head1 Saved Queries

All these long queries would be a bear to type over and over again
(imagine if we had a bunch of joins to do). So, ysql allows you to save
queries for later use using the C<--save> option:

    $ ysql prod --save users 'SELECT * FROM users'
    $ ysql dev --save update_users 'UPDATE users SET \
        name=$.name, email=$.email WHERE id=$.id'

Then we can recall our query by the name we gave to the C<--save> option:

    $ ysql prod users | ysql dev update_users

If our saved query has a placeholder, we can give it a value as the next
argument:

    $ ysql prod --save find_user 'SELECT * FROM users WHERE name=?'
    $ ysql prod find_user preaction

=head1 SEE ALSO

=over 4

=item L<ysql>

The full documentation for the C<ysql> command

=item L<ETL::Yertl>

The main documentation

=back