SQL

From DreamHost
Jump to: navigation, search


SQL - short for Structured Query Language - is used for storing information in databases, and getting it back out again. It easily searches, sorts, filters, dices, chops, and analyzes information, making it easier to work with. (It also makes a mean carrot cake.)

If you're setting up a web site of low or moderate complexity, you don't need to know that much about SQL - the scripts you install take care of the aggravating work of talking to the database themselves. However, if you're the kind of person that likes to break a sweat and get your hands dirty, you might be interested in learning more about SQL.

Contents

Getting a Database

Getting a database at DreamHost to practice on is easy - just visit the Goodies section of the Control Panel.

Getting Connected

You can practice SQL commands in a few places. The easiest is probably to connect using the mysql command from your shell account.

Tables, Rows, and Columns

If you've ever used a spreadsheet, you already know how a database stores information (conceptually, at least - you really don't want to know how the data is actually stored!). Tables are used to store information that's directly related. You can have pretty much as many tables in a database as you want.

Just like the tables from your favorite high school textbook or encyclopedia, tables in a database have rows and columns.

Here's a simple table you might typically find in a database:

Crewmembers
ID LastName FirstName Rank SpecialTraits
1 NULL Spock Captain Turns green when embarrased
3 Chekov Pavel Commander Steers wessels with ease
2 Scott Montgomery Captain Possesses a unique understanding of 20th century computer technology
4 Kirk James Admiral Talks... with frequent... dramatic... pauses

The rows run horizontally. In this example, each row corresponds to a single, distinct Star Trek character. I'll leave the rest of the rows in this database to your imagination. If you're more of a TNG fan, for example, you might add an additional row for Picard, Riker, or maybe even Data.

The columns run vertically. Each row has columns which label and describe the information in a row. Don't worry if this doesn't make sense right now - there will be plenty of hands-on practice later.

Words of Warning

WARNING: If you're following along on your own database, be careful. Many of the commands I'll be introducing have the ability to really wreck your data. Please practice on a brand new database that doesn't contain anything of value (especially since the Happy DreamHost Database Creation Team lets you have as many as you need).

WARNING: Stop reading until you read the preceding paragraph.

WARNING: Okay, I mean it this time.

By the way, if you somehow missed or ignored all of that, you should know that there is generally no undo in SQL. So make sure you consider the effect of any query carefully before you run it. It might be a good idea to try any complex commands on a test database first.

Also, you should know that SQL varies slightly from database to database. If you're following along on MySQL, which DreamHost provides, you should have no problem. Otherwise, you might need to adjust the examples provided.

Creating the Table

Now that you've created a new database so you can practice safely, it's time to create the sample table I just showed you. How you do this depends on the database engine you're using; with MySQL, you might type a command something like this:

 CREATE TABLE Crewmembers (ID TINYINT(3) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
   LastName VARCHAR(50),
   FirstName VARCHAR(50),
   Rank VARCHAR(50),
   SpecialTraits TEXT);

If everything's okay, MySQL should hum a microsecond or two before helpfully replying with Query OK, 0 rows affected.

Basically, all that command does is create a new table with 5 columns. We describe the data each column is supposed to hold, and for the ID column, we ask MySQL to automatically number new rows and make a primary key. Primary keys are cool because they guarantee that even if all the other data is the same, we can still distinguish rows from each other. You'll see more about why this is important as we continue.

Now, let's fill up your new, empty table with the sample data. If you don't understand the following commands, don't worry - we have a little further to go first.

 INSERT INTO Crewmembers (ID, LastName, FirstName, Rank, SpecialTraits)
   VALUES (1, NULL, "Spock", "Captain", "Turns green when embarrased");
 
 INSERT INTO Crewmembers (ID, LastName, FirstName, Rank, SpecialTraits)
   VALUES (3, "Chekov", "Pavel", "Commander", "Steers wessels with ease");
 
 INSERT INTO Crewmembers (ID, LastName, FirstName, Rank, SpecialTraits)
   VALUES (2, "Scott", "Montgomery", "Captain",
   "Possesses a unique understanding of 20th century computer technology");
 
 INSERT INTO Crewmembers (ID, LastName, FirstName, Rank, SpecialTraits)
   VALUES (4, "Kirk", "James", "Admiral", "Talks... with frequent... dramatic... pauses");

Retreiving Information with SELECT

Basics

How's your database so far? We've done quite a bit - you added a new table and four new rows. If you want to see how your creation looks, you can use the SELECT command. It looks like this:

 SELECT * FROM Crewmembers;

That command basically says "Show me all the columns of all the rows from the table called 'Crewmembers'." Pretty simple, huh? Surprisingly enough, MySQL shows you the sample table from the previous section. Here it is again:

Crewmembers
ID LastName FirstName Rank SpecialTraits
1 NULL Spock Captain Turns green when embarrased
3 Chekov Pavel Commander Steers wessels with ease
2 Scott Montgomery Captain Possesses a unique understanding of 20th century computer technology
4 Kirk James Admiral Talks... with frequent... dramatic... pauses

Specifying Columns

The new table is well and good, but you may not be quite happy with it. "For now," you might be thinking, "all I want to know is the names of the fearless crew of the Enterprise. I could care less about their rank or odd hobbies. For that matter, I really don't want to see this primary key thingee the mean author is making me put in."

If you were to write a script to get only the names and filter out all the other information, it would have to be fairly complicated - not to mention a pain in the butt to write and a waste of DreamHost's network bandwidth. (And we certainly don't want to waste that - their prices are low for a reason, after all.)

Luckily, SQL is a pro at this sort of thing. Here's how you would do it:

 SELECT LastName, FirstName FROM Crewmembers;

...and here's what MySQL would tell you:

Crewmembers
LastName FirstName
NULL Spock
Chekov Pavel
Scott Montgomery
Kirk James

Wow! That's a lot easier to read. Don't worry about the missing information, by the way - all we've done is hide it. If you do the full SELECT command, it'll all be back, just as you left it.

Note that you can put the columns in any order you choose. Just because LastName comes before FirstName in the table doesn't mean it always have to be this way. You could just as easily type:

 SELECT FirstName, LastName FROM Crewmembers;

...and get:

Crewmembers
FirstName LastName
Spock NULL
Pavel Chekov
Montgomery Scott
James Kirk


Limiting

It might seem nice to get all the rows in your table back, but often you really don't want to do that. For example, say you give out lottery checks for a living. You probably have millions of rows to deal with - thousands from me alone! If you were to type something like SELECT * FROM entries;, the entries would scroll by so fast you couldn't possibly read them all.

SQL provides a solution. Instead of showing you all the rows in the result, you can ask the database to show you only a few. You do this by adding the LIMIT clause to your SELECT:

 SELECT FirstName, LastName FROM Crewmembers LIMIT 2;
Crewmembers
FirstName LastName
Spock NULL
Pavel Chekov

As you can see, you asked for two rows, and got two back.

MySQL even lets you pick where in the results you want to start from. For example, if Chekov isn't who you're looking for and you want to skip to the next page, you could type:

 SELECT FirstName, LastName FROM Crewmembers LIMIT 2,2;

The first 2 is the number of the first row you want. (I know, I know, you actually want the third row. Sometimes silly programmers count from 0 rather than 1, and it's something the rest of us have to learn to deal with.) The second 2 means we want to get up to two rows.

Crewmembers
FirstName LastName
Montgomery Scott
James Kirk

If we asked for 3 rows, 4, or a million, it wouldn't matter - MySQL will just give you as many as it has, then stop.

Sorting

If you just type SELECT commands, as we have been, the rows come back in an arbitrary order - usually the order we INSERTed them into the database, beginning with the oldest. Sometimes it's nice to get the rows in a different order instead. SQL makes it easy to tell the database what you want.

Say, for example, that I want to see all the crew in my table in order of rank. While I can't ask for Admirals to be first, followed by Captains, Commanders, and so forth, I can at least put them in alphabetical order. Here's how:

 SELECT Rank, FirstName, LastName FROM Crewmembers ORDER BY Rank;
Crewmembers
Rank FirstName LastName
Admiral James Kirk
Captain Spock NULL
Captain Montgomery Scott
Commander Pavel Chekov

What if I wanted to give poor Pavel an instant promotion? No problem. I just tell the database to sort in descending order:

 SELECT Rank, FirstName, LastName FROM Crewmembers ORDER BY Rank DESC;
Crewmembers
Rank FirstName LastName
Commander Pavel Chekov
Captain Spock NULL
Captain Montgomery Scott
Admiral James Kirk

You can also sort without showing the column you're sorting on. If I typed SELECT FirstName, LastName FROM Crewmembers ORDER BY Rank;, it would work just as you might expect.

If you're adventurous, you can even sort by multiple columns at the same time. For example, if I wanted to make sure Spock always followed Scotty, I could do this (give this query a moment to sink in):

 SELECT FirstName, LastName FROM Crewmembers ORDER BY Rank ASC,
   FirstName ASC LIMIT 3;
Crewmembers
FirstName LastName
James Kirk
Montgomery Scott
Spock NULL

If you're wondering why Kirk is there, rather than Chekov, the reason is that the sort always happens before the limit. Since Kirk's rank of Admiral sorted before Chekov's rank of Commander, he got pushed to the fourth row, and wasn't lucky enough to appear in the results.

Searching

One of the most obvious uses of a database is to search for things. In SQL, most searches happen in a WHERE clause. You can think of WHERE as a way of saying, "but only if." Take this query, for example:

 SELECT * FROM Crewmembers WHERE LastName = "Kirk";

What you're really saying is, "Show me all columns of all rows in the table Crewmembers, but only if the last name is Kirk."

Sure enough, MySQL happily responds with:

Crewmembers
ID LastName FirstName Rank SpecialTraits
4 Kirk James Admiral Talks... with frequent... dramatic... pauses

All the other combinations of the modifiers above work. Try this query:

 SELECT LastName, FirstName FROM Crewmembers WHERE FirstName <> "Pavel"
   ORDER BY ID DESC LIMIT 2;

The only thing that should seem new to you is the <>. That means "not equal to." Some of the other comparison operators you'll see are <, >, <=, and =>.

No answer key for you this time. Try to look at the query, and the data, and figure out what the result will be. Then try it in MySQL and see if you're getting the hang of it.

Other Searches

In addition to the simple comparison operators, you can use many other operators to describe your searches. If you've worked with a search engine, you might recognize the booleans - AND and OR. They help modify a search and allow you to make more than one comparison at a time.

Say we're planning a birthday party for Scotty. We want to invite only Jim and Spock. (Poor Chekov's promotion didn't last long). Here's one way to accomplish that:

 SELECT FirstName FROM Crewmembers WHERE FirstName = "James" OR FirstName = "Spock";
Crewmembers
FirstName
Spock
James

Similarly, you can use AND if you have a combination of comparisons you need to make that should all be true.

SQL supports wildcards using the LIKE operator. A wildcard lets you match a pattern of characters instead of exact text. You use a percent sign to signify the letters you want to fill in, like this:

 SELECT FirstName FROM Crewmembers WHERE FirstName LIKE "%a%";

This will return "Pavel" and "James", because only they have an A in their first names. If you want to leave a space for exactly one unknown character, use the underscore. For example:

 SELECT FirstName FROM Crewmembers WHERE FirstName LIKE "Pa_el";

...gives you Pavel.


Adding Data with INSERT

A database wouldn't be much fun if it didn't let you easily add data to it. SQL lets you add new rows to a database with INSERT. You've already seen a few INSERT statements earlier in this tutorial. Let's look at one again:

 INSERT INTO Crewmembers (LastName, FirstName, Rank, SpecialTraits)
   VALUES ("Kirk", "James", "Admiral", "Talks... with frequent... dramatic... pauses");

This query tells the database, "Create a new row in the table Crewmembers. The last name should be "Kirk", the first name should be "James", the rank should be "Admiral", and the special traits are "Talks... with frequent... dramatic... pauses". MySQL will add the row and then (hopefully) tell you Query OK, 1 row affected (0.00 sec).

While there's several ways to format an INSERT, I prefer this method because it lets you add data without having to deal with pesky details like remembering what order you created the columns in and what happens if you leave a column back.

Most database packages will automatically assign a default value to columns that aren't specified. For example, because we defined the ID column of Crewmembers to be AUTO_INCREMENT when we created the table, it'll automatically get the next higher number in the table.

Why Primary Keys are Important

Oh, no!! What have we done?!?!

I just realized that when we executed that last query, we added a second, duplicate Admiral Kirk to the table. (Okay, I had this planned all along, but it sure got your heart pumping, huh?) See for yourself:

 SELECT ID, FirstName, LastName FROM Crewmembers WHERE LastName = "Kirk";

You can verify that the rest of the row is identical, if you're so inclined.

So, what do we do? Luckily, the primary key, which I've been ignoring until now, ensures that every row has a unique identifier that can be quickly used to weed out duplicates. You may be thinking to yourself, "Sure, but what happens if I accidentally re-use an ID?" It's no problem, because the database will say, "Hey, stupid! That number's taken already!"

 INSERT INTO Crewmembers (ID, LastName, FirstName, Rank, SpecialTraits)
   VALUES (4, "Kirk", "James", "Admiral", "Talks... with frequent... dramatic... pauses");

When I run that query, I get ERROR 1062 (23000): Duplicate entry '4' for key 1, because 4 is already assigned to one of the Kirks. Your wording will vary slightly, but it probably won't call you names.

Modifying Rows with UPDATE

If you need to fix a row because of a typo, outdated information, or a scatterbrained tutorial, you can use the UPDATE statement. The most basic form of UPDATE looks like the following query. However, don't type it. I'll explain why in a moment.

 UPDATE Crewmembers SET FirstName = "Jean-Luc";

As I said, don't run this query. The reason you don't want to do this is that it will make the change to every row, which is almost always not want you want. If I were to run that query and then do a subsequent SELECT, I'd get something like this:

Crewmembers
ID LastName FirstName Rank SpecialTraits
1 NULL Jean-Luc Captain Turns green when embarrased
3 Chekov Jean-Luc Commander Steers wessels with ease
2 Scott Jean-Luc Captain Possesses a unique understanding of 20th century computer technology
4 Kirk Jean-Luc Admiral Talks... with frequent... dramatic... pauses
5 Kirk Jean-Luc Admiral Talks... with frequent... dramatic... pauses

That's not a very good result. So, if we can't do that, how do we change just the rows we want? Actually, all we need to do is use the same WHERE syntax we learned for SELECTs. Try this query out:

 UPDATE Crewmembers SET SpecialTraits = "Hates Klingons"
   WHERE FirstName = "James" AND LastName = "Kirk";

MySQL will respond, telling you that two rows were affected. Let's take a look at how the table looks now. Write the necessary SELECT to get the following table:

ID FirstName LastName SpecialTraits
1 Spock NULL Turns green when embarrased
3 Pavel Chekov Steers wessels with ease
4 James Kirk Hates Klingons
5 James Kirk Hates Klingons
2 Montgomery Scott Possesses a unique understanding of 20th century computer technology

As you can see, you can change multiple rows at the same time without too much trouble. However, if you're only making one change at a time, the safest way to decide what row to update is to use the primary key, like this:

 UPDATE Crewmembers SET FirstName = "Jim" WHERE ID = 4;

Removing Rows with DELETE

Personal tools