SQL & Active record:

Exploring your database

So many sqls...

SQLite3

Postgres

MySQL

Oracle

SQL Servers

How crud-y is sql?

CRUD

 

Create

 

Read

 

Update

 

Delete

HTML Verbs

 

post

 

get

 

patch/put

 

delete

SQL Commands

 

insert

 

select

 

update

 

delete

SQL project is go!

Let's start a new project...

$ rails new db_explore
$ cd db_explore

...and create a Resource called User...

$ rails g scaffold User name:string location:string age:integer
$ rake db:migrate

Then we need some data to explore: create five Users!

Console-ation prize

Let's use SQL querying to take a look inside our database...

Open the dbconsole:

$ rails dbconsole

SQLite version 3.7.12 2012-04-03 19:43:07

Enter ".help" for instructions

Enter SQL statements terminated with a ";"

sqlite>

Table roll call!

Perhaps you've simply forgotten what databases you even have on this project.

Don't worry! You can check for tables...

sqlite> .tables

schema_migrations users

sqlite>

Tell me *

In SQL, the asterisk (*) means "all". Let's pull all the data from the User table!


sqlite> select * from users;

1|Jude|Atlanta|19|2014-08-18 12:55:45.899020|2014-08-18 12:56:37.077430

2|Ellen|San Diego|65|2014-08-18 12:56:00.461203|2014-08-18 12:56:00.461203

3|Norah|Venice|32|2014-08-18 12:56:18.187149|2014-08-18 12:56:18.187149

4|Jason|Indianapolis|22|2014-08-18 12:56:31.751468|2014-08-18 12:56:31.751468

5|Leila|Edmonton|29|2014-08-18 12:56:54.591946|2014-08-18 12:56:54.591946

sqlite>

Tell Me What I

Want to Hear

Maybe we don't want to see everything.

Maybe we just want to see certain attributes (columns).

sqlite> select name, age from users;

Jude|19

Ellen|65

Norah|32

Jason|22

Leila|29

sqlite>

I don't do well in crowds...

What if we had hundreds of rows in our table?

Do we want to see all of those at once?

Nah – so let's “limit” what's returned...

sqlite> select * from users limit 2;

1|Jude|Atlanta|19|2014-08-18 12:55:45.899020|2014-08-18 12:56:37.077430

2|Ellen|San Diego|65|2014-08-18 12:56:00.461203|2014-08-18 12:56:00.461203

sqlite>

Notice, that's the first two users in our table.

let's get specific

What if we're looking for a certain person?


sqlite> select * from users where name = 'Jason';

4|Jason|Indianapolis|22|2014-08-18 12:56:31.751468|2014-08-18 12:56:31.751468

sqlite>

In this case, we use the 'where' clause to get specific.

 

You can also get a little more complex:

sqlite> select * from users where name = 'Leila' and age = 29;

5|Leila|Edmonton|29|2014-08-18 12:56:54.591946|2014-08-18 12:56:54.591946

sqlite>

Using 'or' is also an option.

he's between this tall and this short...

You can use greater and less than, too (with integers or floats, of course):

sqlite> select * from users where age > 30;

2|Ellen|San Diego|65|2014-08-18 12:56:00.461203|2014-08-18 12:56:00.461203

3|Norah|Venice|32|2014-08-18 12:56:18.187149|2014-08-18 12:56:18.187149

sqlite>

Wild card!

A cool feature of SQL querying is the 'wild card' (%).

 

Here's a case where we look up all the names that begin with 'J':

sqlite> select * from users where name like 'J%';

1|Jude|Atlanta|19|2014-08-18 12:55:45.899020|2014-08-18 12:56:37.077430

4|Jason|Indianapolis|22|2014-08-18 12:56:31.751468|2014-08-18 12:56:31.751468

sqlite>

make a change,

with sql

Just looking at the data is all well and good, but what about changing the data?

sqlite> select * from users where id = 1;
1|Jude|Atlanta|19|2014-11-10 23:31:26.585649|2014-11-10 23:31:26.585649
sqlite> update users set age = 25 where id = 1;
sqlite>
sqlite> select * from users where id = 1;
1|Jude|Atlanta|25|2014-11-10 23:31:26.585649|2014-11-10 23:31:26.585649
sqlite>

Nothing seems to happen when we "update", but check  again!

sql makes it so!

sqlite> insert into users (name, location, age) values ('Sam', 'Pensacola', 33);
sqlite> select * from users where name = 'Sam'
6|Sam|Pensacola|33||
sqlite>

We can create new entries with SQL:

The only problem:

SQL will not provide 'created_at' and 'updated_at' like Rails does.

:-(

Sql, dump it!

sqlite> delete from users where name = 'Jason';

sqlite> select * from users;

1|Jude|Atlanta|25|2014-08-18 12:55:45.899020|2014-08-18 12:56:37.077430

2|Ellen|San Diego|65|2014-08-18 12:56:00.461203|2014-08-18 12:56:00.461203

3|Norah|Venice|32|2014-08-18 12:56:18.187149|2014-08-18 12:56:18.187149

5|Leila|Edmonton|29|2014-08-18 12:56:54.591946|2014-08-18 12:56:54.591946

6|Sam|Pensacola|33||

sqlite>

We can delete an entry via SQL...

Note that not only is Jason gone, but ID #4 is gone & the table hasn't been re-ordered. #4 is forever gone from this DB!

SQl, get me out of here!

You can't spend your whole life in dbconsole.

How do you get out of this place?

sqlite> .exit
$

Yup...that's all it takes.

get active! (record)

SQL is hard.

ActiveRecord is easy.

 

You've seen ActiveRecord name-checked in your Models:

class User < ActiveRecord::Base

end
  def index
    @users = User.all
  end

  def new
    @user = User.new
  end

And you've seen it at work in your Controllers:

dbconsole, you've met your match

ActiveRecord has its own special hideout:

$ rails console
Loading development environment (Rails 4.1.4)
1.9.3-p392 :001 >

That's my Ruby version (yes, I'm behind the times), followed by a line number for this session of rails console.

1.9.3-p392 :001 > User.all
  User Load (3.7ms)  SELECT "users".* FROM "users"
 => #<ActiveRecord::Relation [#<User id: 1, name: "Jude", location: "Atlanta", age: 25, 
created_at: "2014-11-10 23:31:26", updated_at: "2014-11-10 23:31:26">, #<User id: 2, 
name: "Ellen", location: "San Diego", age: 65, created_at: "2014-11-10 23:31:36", 
updated_at: "2014-11-10 23:31:36">, #<User id: 3, name: "Norah", location: "Venice", 
age: 32, created_at: "2014-11-10 23:31:46", updated_at: "2014-11-10 23:31:46">, 
#<User id: 4, name: "Jason", location: "Indianapolis", age: 22, created_at: 
"2014-11-10 23:31:58", updated_at: "2014-11-10 23:31:58">, #<User id: 5, name: "Leila", 
location: "Edmonton", age: 29, created_at: "2014-11-10 23:32:10", updated_at: 
"2014-11-10 23:32:10">, #<User id: 6, name: "Sam", location: "Pensacola", age: 33, 
created_at: nil, updated_at: nil>]>
1.9.3-p392 :002 >

ActiveRecord, let's see it all...

The output format may be uglier than SQL's, but the command is so much easier!

 

(Also, notice how it shows you the SQL query.)

1.9.3-p392 :002 > User.first
  User Load (0.2ms)  SELECT  "users".* FROM "users"   ORDER BY "users"."id" ASC LIMIT 1
 => #<User id: 1, name: "Jude", location: "Atlanta", age: 25, 
created_at: "2014-11-10 23:31:26", updated_at: "2014-11-10 23:31:26">
1.9.3-p392 :003 > User.last
  User Load (0.2ms)  SELECT  "users".* FROM "users"   ORDER BY "users"."id" DESC LIMIT 1
 => #<User id: 6, name: "Sam", location: "Pensacola", age: 33, created_at: nil, 
updated_at: nil>
1.9.3-p392 :004 >

We can look at specific entries...

We can give ActiveRecords specifics...

1.9.3-p392 :004 > User.find(3)
  User Load (0.3ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 3]]
 => #<User id: 3, name: "Norah", location: "Venice", age: 32, created_at: "2014-11-10 23:31:46", 
updated_at: "2014-11-10 23:31:46">
1.9.3-p392 :005 > User.where(name: "Jason")
  User Load (0.2ms)  SELECT "users".* FROM "users"  WHERE "users"."name" = 'Jason'
 => #<ActiveRecord::Relation [#<User id: 4, name: "Jason", location: "Indianapolis", age: 22, 
created_at: "2014-11-10 23:31:58", updated_at: "2014-11-10 23:31:58">]>
1.9.3-p392 :006 >

Update in rails console

1.9.3-p392 :007> x = User.find(3)
  User Load (0.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 3]]
 => #<User id: 3, name: "Norah", location: "Venice", age: 32, created_at: "2014-11-10 23:31:46", 
updated_at: "2014-11-10 23:31:46">
1.9.3-p392 :008 > x.location = "Chicago"
 => "Chicago"
1.9.3-p392 :009 > User.find(3)
  User Load (0.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 3]]
 => #<User id: 3, name: "Norah", location: "Venice", age: 32, created_at: "2014-11-10 23:31:46", 
updated_at: "2014-11-10 23:31:46">
1.9.3-p392 :010 > x.save
   (0.1ms)  begin transaction
  SQL (0.6ms)  UPDATE "users" SET "location" = ?, "updated_at" = ? WHERE "users"."id" = 3  
[["location", "Chicago"], ["updated_at", "2014-11-11 11:52:22.885042"]]
   (0.9ms)  commit transaction
 => true
1.9.3-p392 :011 > User.find(3)
  User Load (0.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 3]]
 => #<User id: 3, name: "Norah", location: "Chicago", age: 32, created_at: "2014-11-10 23:31:46", 
updated_at: "2014-11-11 11:52:22">

Updating Rails Console is a bit more complicated than in SQL, but it's exactly how you'd update an entry in your Rails project.

The change isn't saved until we call 'x.save'.

The Power to create...

1.9.3-p392 :012 > newbie = User.new
 => #<User id: nil, name: nil, location: nil, age: nil, created_at: nil, updated_at: nil>

You can create a new instance of the Resource in Rails Console, but be careful...

Give your newbie a name, location and age. Active Record will take care of the rest....

1.9.3-p392 :013 > newbie.name = "Josephine"
 => "Josephine"
1.9.3-p392 :014 > newbie.location = "Santiago"
 => "Santiago"
1.9.3-p392 :015 > newbie.age = 41
 => 41
1.9.3-p392 :016 > newbie.save
   (0.1ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "users" ("age", "created_at", "id", "location", "name", "updated_at") 
VALUES (?, ?, ?, ?, ?, ?)  [["age", 41], ["created_at", "2014-11-11 12:51:03.809027"],  
["location", "Santiago"], ["name", "Josephine"], ["updated_at", "2014-11-11 12:51:03.809027"]]
   (1.1ms)  commit transaction
 => true
1.9.3-p392 :017 > User.where(name: "Josephine")
  User Load (0.3ms)  SELECT "users".* FROM "users"  WHERE "users"."name" = 'Josephine'
 => #<ActiveRecord::Relation [#<User id: 7, name: "Josephine", location: "Santiago", age: 41, 
created_at: "2014-11-11 12:51:03", updated_at: "2014-11-11 12:51:03">]>

...and the power to destroy

1.9.3-p392 :018 > User.find(7).destroy
  User Load (0.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 7]]
   (0.1ms)  begin transaction
  SQL (0.2ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 7]]
   (0.8ms)  commit transaction
 => #<User id: 7, name: "Josephine", location: "Santiago", age: 41, created_at: "2014-11-11 13:02:34", 
updated_at: "2014-11-11 13:02:34">
1.9.3-p392 :045 >

You cannot combine the .where() query and destroy.

You can assign the entry as a variable and then destroy:

1.9.3-p392 :045 > x = User.where(id: 2)
  User Load (0.2ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 2]]
 => #<User id: 2, name: "Ellen", location: "San Diego", age: 65, created_at: "2014-11-10 23:31:36", 
updated_at: "2014-11-10 23:31:36">
1.9.3-p392 :046 > x.destroy
   (0.1ms)  begin transaction
  SQL (0.2ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 2]]
   (0.9ms)  commit transaction
 => #<User id: 2, name: "Ellen", location: "San Diego", age: 65, created_at: "2014-11-10 23:31:36", 
updated_at: "2014-11-10 23:31:36">
1.9.3-p392 :047 > x.save
   (0.1ms)  begin transaction
   (0.0ms)  commit transaction
 => true

SQL & Active Record

By argroch

SQL & Active Record

Exploring your databases with SQL and ActiveRecord

  • 1,428