• Aucun résultat trouvé

Performing Joins

Dans le document PHP 6 (Page 194-199)

Because relational databases are more com-plexly structured, they sometimes require special query statements to retrieve the information you need most. For example, if you wanted to know what messages are in the kindlingforum, you would need to first find the forum_idforkindling, and then use that number to retrieve all the records from the messagestable that have that forum_id.

This one simple (and, in a forum, often nec-essary) task would require two separate queries. By using a join, you can accomplish all of that in one fell swoop.

A join is an SQL query that uses two or more tables, and produces a virtual table of results.

The two main types of joins are innerand outer(there are subtypes within both).

An inner join returns all of the records from the named tables wherever a match is made.

For example, to find every message in the kindlingforum, the inner join would be writ-ten as (Figure 6.15)

SELECT * FROM messages INNER JOIN forums ON messages.forum_id = forums.forum_id WHERE forums.name = 'kindling'

This join is selecting every column from both tables under two conditions. First, the forums.namecolumn must have a value of kindling(this will return the forum_idof 6).

Second, the forum_idvalue in the forums table must match the forum_idvalue in the messagestable. Because of the equality com-parison being made across both tables (messages.forum_id = forums.forum_id), this is known as an equijoin.

Inner joins can also be written without for-mally using the term INNER JOIN:

SELECT * FROM messages, forums WHERE messages.forum_id = forums.forum_id AND forums.name = 'kindling'

When selecting from multiple tables, you must use the dot syntax (table.column) if the tables named in the query have columns with the same name. This is normally the case when dealing with relational databases because a primary key from one table will have the same name as a foreign key in another. If you are not explicit when refer-encing your columns, you’ll get an error (Figure 6.16).

Advanced SQL and MySQL

Performing Joins

continues on next page

Figure 6.15This join returns every column from both tables where the forum_idvalues represent the kindlingforum (6).

Figure 6.16Generically referring to a column name present in multiple tables will cause an ambiguity error. In this query, referring to just nameinstead of forums.namewould be fine, but it’s still best to be precise.

An outerjoin differs from an inner join in that an outer join could return records not matched by a conditional. There are three outer join subtypes: left,right, and full. An example of a left join is

SELECT * FROM forums LEFT JOIN messages

ON forums.forum_id = messages.forum_id

The most important consideration with left joins is which table gets named first. In this example, all of the forumsrecords will be returned along with all of the messages infor-mation, if a match is made. If no messages records match a forumsrow, then NULLvalues will be returned instead (Figure 6.17).

In both inner and outer joins, if the column in both tables being used in the equality comparison has the same name, you can simplify your query with USING:

SELECT * FROM messages INNER JOIN forums USING (forum_id)

WHERE forums.name = 'kindling'

SELECT * FROM forums LEFT JOIN messages

USING (forum_id)

Before running through some examples, two last notes. First, because of the complicated syntax with joins, the SQL concept of an alias—introduced in Chapter 5—will come in handy when writing them. Second, because joins often return so much information, it’s normally best to specify exactly what columns you want returned, instead of selecting them all (Figure 6.17, in its uncropped form, couldn’t even fit within my 22"monitor’s screen!).

Performing Joins

Figure 6.17An outer join returns more records than an inner join because all of the first table’s records will be returned. This join returns every forum name, even if there are no messages in a forum (like Modern Danceat bottom). Also, to make it legible, I’ve cropped this image, omitting the bodyand date_enteredcolumns from the result.

To use joins:

1. Retrieve the forum name and message subject for every record in the messages table (Figure 6.18).

SELECT f.name, m.subject FROM forums AS f INNER JOIN messages AS m USING (forum_id) ORDER BY f.name;

This query, which contains an inner join, will effectively replace the forum_idvalue in the messagestable with the correspon-dingnamevalue from the forumstable for each of the records in the messages table. The end result is that it displays the textual version of the forum name for each message subject.

Notice that you can still use ORDER BY

clauses in joins.

2. Retrieve the subject and date entered value for every message posted by the userfunny man(Figure 6.19).

SELECT m.subject,

DATE_FORMAT(m.date_entered, '%M %D,

%Y') AS Date FROM users AS u INNER JOIN messages AS m USING (user_id)

WHERE u.username = 'funny man';

This join also uses two tables, usersand messages. The linking column for the two tables is user_id, so that’s placed in the USINGclause. The WHEREconditional identifies the user being targeted, and the DATE_FORMAT()function will help for-mat the date_enteredvalue.

Advanced SQL and MySQL

Performing Joins

Figure 6.18A basic inner join that returns only two columns of values.

Figure 6.19A slightly more complicated version of an inner join, using the usersand messagestables.

continues on next page

3. Retrieve the message ID, subject, and forum name for every message posted by the user troutster(Figure 6.20).

SELECT m.message_id, m.subject, f.name FROM users AS u INNER JOIN messages AS m USING (user_id) INNER JOIN forums AS f USING (forum_id)

WHERE u.username = 'troutster';

This join is similar to the one in Step 2, but takes things a step further by incor-porating a third table. Take note of how a three-table inner join is written and how the aliases are used for shorthand when referring to the three tables and their columns.

4. Retrieve the username, message sub-ject, and forum name for every user (Figure 6.21).

SELECT u.username, m.subject, f.name FROM users AS u LEFT JOIN messages AS m USING (user_id) LEFT JOIN forums AS f

USING (forum_id);

If you were to run an inner join similar to this, a user who had not yet posted a message would not be listed (Figure 6.22).

So an outer join is required to be inclusive of all users. Note that the fully included table (here, users), must be the first table listed in a left join.

Performing Joins

Figure 6.21This left join returns for every user, every posted message subject, and every forum name. If a user hasn’t posted a message (like finchyat the bottom), their subject and forum name values will be NULL.

Figure 6.20An inner join across all three tables.

Tips

You can even join a table with itself (aself-join)!

Joins can be created using conditionals involving any columns, not just the pri-mary and foreign keys, although that’s most common.

You can perform joins across multiple databases using the database.table.column syntax, as long as every database is on the same server (you cannot do this across a network) and you’re connected as a user with permission to access every database involved.

Joins that do not include a WHEREclause (e.g.,SELECT * FROM urls, url_associations) are called fulljoins and will return every record from both tables. This construct can have unwieldy results with larger tables.

ANULLvalue in a column referenced in a join will never be returned, because

NULLmatches no other value, includ-ingNULL.

Advanced SQL and MySQL

Performing Joins

Figure 6.22This inner join will not return any users who haven’t yet posted messages (see finchyat the bottom of Figure 6.21).

Dans le document PHP 6 (Page 194-199)