SQL 15 Advanced SQL
SQL 15 Advanced SQL
Charles Severance
www.php-intro.com
Error Checking So Far
We get away with ignoring errors because they are rare and usually “big”
• Violation of a constraint
Start Simple
We just configure PDO to throw an error if anything goes wrong
<?php
$pdo = new PDO('mysql:host=localhost;port=8889;dbname=misc',
'fred', 'zap');
// See the "errors" folder for details...
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
php-intro/code/pdo/pdo.php
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("SELECT * FROM users where id = :xyz");
$stmt->execute(array(":pizza" => $_GET['id']));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ( $row === false ) {
$_SESSION['error'] = 'Bad value for id';
header( 'Location: index.php' ) ;
return;
}
php-intro/code/pdoerrors/error2.php
In Production Environments
• We do not want to have tracebacks in the user interface - may reveal
sensitive data
• Some errors are subtle and can be affected by user-entered data – length of
VARCHAR field, for example
http://en.wikipedia.org/wiki/Fuzz_testing
$sql = "INSERT INTO {$p}sample_map
(context_id, user_id, lat, lng, updated_at)
VALUES ( :CID, :UID, :LAT, :LNG, NOW() )
ON DUPLICATE KEY
UPDATE lat = :LAT, lng = :LNG, updated_at = NOW()";
$stmt = $PDOX->prepare($sql);
$stmt->execute(array(
':CID' => $CONTEXT->id, What could go
':UID' => $USER->id, wrong?
':LAT' => $_POST['lat'],
':LNG' => $_POST['lng']));
http://php.net/manual/en/pdostatement.execute.php
http://php.net/manual/en/pdo.errorinfo.php
$rows = $PDOX->queryDie(
"DELETE FROM {$p}attend WHERE link_id = :LI",
array(':LI' => $LINK->id)
);
tsugi/lib/vendor/Tsugi/Util/PDOX.php queryReturnError()
$sql = "INSERT INTO {$p}sample_map
(context_id, user_id, lat, lng, updated_at)
VALUES ( :CID, :UID, :LAT, :LNG, NOW() )
ON DUPLICATE KEY
UPDATE lat = :LAT, lng = :LNG, updated_at = NOW()";
$stmt = $PDOX->prepare($sql);
$stmt->execute(array(
':CID' => $CONTEXT->id,
':UID' => $USER->id,
':LAT' => $_POST['lat'],
':LNG' => $_POST['lng']));
tsugi/lib/vendor/Tsugi/Util/PDOX.php
Advanced Queries
LEFT JOIN
• For a normal JOIN, a row is included in the result of the SELECT if and
only if both sides of the ON clause are present.
- The order of the tables in the JOIN clause does not matter.
All the rows from the “left” table that match the WHERE clause are
included whether or not the ON clause finds a row in the “right” table.
Album.title Album.artist_id Artist.artist_id Artist.name
SELECT Users.name,Users.user_id,
Profile.user_id,Profile.laptop
FROM Users JOIN Profile ON Users.user_id = Profile.user_id
Users Profile
http://en.wikipedia.org/wiki/Cryptographic_nonce
http://tools.ietf.org/html/rfc5849#section-3.3
LTI Sample Launch Data
lti_version=LTI-1p0
lti_message_type=basic-lti-launch-request
context_id=456434513
context_title=SI301 – PHP
resource_link_id=120988f929-274612
user_id=292832126
roles=Instructor
lis_person_name_full=Charles R. Severance
lis_person_contact_email_primary = [email protected]
tool_consumer_instance_description=University of School
oauth_consumer_key=lmsng.school.edu
oauth_nonce=0ff19a855706012c33233dfb8ecd0c9c
...
http://developers.imsglobal.org/
tsugi/docs/lectures/02-Data-Model-Workbench.mwb
lti_nonce
lti_nonce
tsugi/lib/vendor/Tsugi/Core/LTIX.php loadAllData()
GROUP BY
• Sometimes instead of wanting all of the rows from a table, we want to
count the distinct values of a column.
http://dev.mysql.com/doc/refman/5.0/en/subqueries.html
An Example from Tsugi
tsugi/mod/peer-grade
SELECT S.submit_id, S.user_id, S.created_at,
count(G.user_id) AS grade_count
FROM {$CFG->dbprefix}peer_submit AS S
LEFT JOIN {$CFG->dbprefix}peer_grade AS G
ON S.submit_id = G.submit_id
WHERE S.assn_id = :AID AND S.user_id != :UID AND S.submit_id NOT IN
( SELECT DISTINCT submit_id from {$CFG->dbprefix}peer_grade
WHERE user_id = :UID)
GROUP BY S.submit_id, S.created_at
ORDER BY grade_count ASC, S.created_at ASC
LIMIT 10
tsugi/mod/peer-grade/peer_util.php loadUngraded()
http://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html
tsugi/mod/peer-grade/admin.php
SELECT S.user_id AS user_id, displayname, email,
S.submit_id as _submit_id,
MAX(G.points) as max_score, MIN(G.points) AS min_score,
COUNT(G.points) as scores,
COUNT(DISTINCT F.flag_id) as flagged,
MAX(S.updated_at) AS updated_at, user_key
FROM {$p}peer_assn AS A
JOIN {$p}peer_submit as S
ON A.assn_id = S.assn_id
JOIN {$p}lti_user AS U
ON S.user_id = U.user_id
LEFT JOIN {$p}peer_grade AS G
ON S.submit_id = G.submit_id
LEFT JOIN {$p}peer_flag AS F
ON S.submit_id = F.submit_id
WHERE A.link_id = :LID
GROUP BY S.submit_id
tsugi/mod/peer-grade/admin.php
SELECT S.assn_id, S.user_id AS user_id, email,
displayname, S.submit_id as submit_id,
MAX(points) as max_points, COUNT(points) as count_points,
C.grade_count as grade_count
FROM {$CFG->dbprefix}peer_submit as S
JOIN {$CFG->dbprefix}peer_grade AS G ON S.submit_id = G.submit_id
JOIN {$CFG->dbprefix}lti_user AS U ON S.user_id = U.user_id
LEFT JOIN (
SELECT G.user_id AS user_id, count(G.user_id) as grade_count
FROM {$CFG->dbprefix}peer_submit as S
JOIN {$CFG->dbprefix}peer_grade AS G
ON S.submit_id = G.submit_id
WHERE S.assn_id = :AID AND G.user_id = :UID
) AS C
ON U.user_id = C.user_id
WHERE S.assn_id = :AID AND S.user_id = :UID
tsugi/mod/peer-grade/peer_util.php computeGrade()
Summary
• More advanced error checking in PDO (it’s complex)
• LEFT JOIN
• GROUP BY
• Subqueries
• AS