SELECT S.NAME_OF_SCHOOL, S.AVERAGE_STUDENT_ATTENDANCE, D.COMMUNITY_AREA_NAME
FROM chicago_public_schools S
LEFT JOIN
chicago_socioeconomic_data D = D.COMMUNITY_AREA_NUMBER
ON S.COMMUNITY_AREA_NUMBER = 98; WHERE D.HARDSHIP_INDEX
Joins & Stored Procedures
Dump to MySQL
- We’ll use MySQL for this project
- We’ll create and load the tables using dump files downloaded to the local drive
- chicago_public_schools - Too long to post image of column names
- chicago_crime
- chicago_socioeconomic_data
- Create db: Mysql_learners via phpMyAdmin
- Import the dump files for each table to create them all one by one
Joins
Task 1
- List the school names, community names and average attendance for communities with a hardship index of 98.
Task 2
- List all crimes that took place at a school.
- Include case number
- crime type
- community name.
- Community name and community area number is found in chicago_socioeconomic_data table
- Community area number and case number are found in crime table
- crimes at schools can be found in crime table using
WHERE LOCATION_DESCRIPTION LIKE 'SCHOOLS%'
- So we need to extract CASE_NUMBER , PRIMARY_TYPE based on WHERE above
- Then match with the socioeconomic data table ON COMMUNITY_AREA_NUMBER and extract the COMMUNITY_AREA_NAME from the intersection
SELECT C.CASE_NUMBER, C.PRIMARY_TYPE, D.COMMUNITY_AREA_NAME
FROM chicago_crime C
LEFT JOIN chicago_socioeconomic_data D= D.COMMUNITY_AREA_NUMBER
ON C.COMMUNITY_AREA_NUMBER 'SCHOOL%' WHERE C.LOCATION_DESCRIPTION LIKE
Views
For privacy reasons, you have been asked to create a view that enables users to select just
- the school name
- the icon fields from the CHICAGO_PUBLIC_SCHOOLS table
- By providing a view, you can ensure that users cannot see the actual scores given to a school, just the icon associated with their score.
- You should define new names for the view columns to obscure the use of scores and icons in the original table.
Task 1
- Write and execute a SQL statement to create a view showing the columns listed in the following table
- New column names as shown in the second column.
Column name in CHICAGO_PUBLIC_SCHOOLS | Column name in view |
---|---|
NAME_OF_SCHOOL | School_Name |
Safety_Icon | Safety_Rating |
Family_Involvement_Icon | Family_Rating |
Environment_Icon | Environment_Rating |
Instruction_Icon | Instruction_Rating |
Leaders_Icon | Leaders_Rating |
Teachers_Icon | Teachers_Rating |
CREATE VIEW Task_1 AS
SELECT NAME_OF_SCHOOL School_Name, Safety_Icon Safety_Rating, Family_Involvement_Icon Family_Rating, Environment_Icon Environment_Rating, Instruction_Icon Instruction_Rating, Leaders_Icon Leaders_Rating, Teachers_Icon Teachers_Rating FROM chicago_public_schools;
Task 2
- Write and execute a SQL statement that returns all of the columns from the view.
*
SELECT FROM Task_1;
Task 3
- Write and execute a SQL statement that returns just the school name and leaders rating from the view.
SELECT School_Name, Leaders_Rating FROM Task_1;
Stored Procedure
The icon fields are calculated based on the value in the corresponding score field. You need to make sure that when a score field is updated, the icon field is updated too. To do this, you will write a stored procedure that receives the school id and a leaders score as input parameters, calculates the icon setting and updates the fields appropriately.
Task 1
- Write the structure of a query to create or replace a stored procedure called UPDATE_LEADERS_SCORE that takes a in_School_ID parameter as an integer and a in_Leader_Score parameter as an integer.
$$
DELIMITER UPDATE_LEADERS_SCORE ( IN School_ID INTEGER, IN Leaders_Score INTEGER)
CREATE PROCEDURE
BEGIN
END$$
DELIMITER ;
Task 2
- Inside your stored procedure, write a SQL statement to update the Leaders_Score field in the CHICAGO_PUBLIC_SCHOOLS table for the school identified by in_School_ID to the value in the in_Leader_Score parameter.
$$
DELIMITER UPDATE_LEADERS_SCORE ( IN in_School_ID INTEGER, IN in_Leader_Score INTEGER)
CREATE PROCEDURE
BEGIN
UPDATE chicago_public_schools= in_Leader_Score
SET Leaders_Score = in_School_ID;
WHERE School_ID
END$$
DELIMITER ;
Task 3
Inside your stored procedure, write a SQL IF statement to
update the Leaders_Icon field in the CHICAGO_PUBLIC_SCHOOLS table for the school identified by in_School_ID using the table below
Remember that once a clause of the IF statement executes, no further checking occurs and processing moves to the code below the IF statement.
Score lower limit | Score upper limit | Icon |
---|---|---|
80 | 99 | Very strong |
60 | 79 | Strong |
40 | 59 | Average |
20 | 39 | Weak |
0 | 19 | Very weak |
$$
DELIMITER UPDATE_LEADERS_SCORE ( IN in_School_ID INTEGER, IN in_Leader_Score INTEGER)
CREATE PROCEDURE
BEGIN
UPDATE chicago_public_schools= in_Leader_Score
SET Leaders_Score = in_School_ID;
WHERE School_ID
> 0 AND in_Leader_Score < 20 THEN
IF in_Leader_Score
UPDATE chicago_public_schools= "Very weak"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 40 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Weak"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 60 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Average"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 80 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Strong"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 100 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Very Strong"
SET Leaders_Icon = in_School_ID;
WHERE School_ID
END IF;
END$$
DELIMITER ;
Task 4
- Run your code to create the stored procedure.
- Write a query to call the stored procedure, passing a valid school ID and a leader score of 50, to check that the procedure works as expected.
Before I do that I will create a view of the columns we need without changing their names (like we did in (Views above), shown below the code here is just the first few rows of the VIEW for comparison
CREATE VIEW Procedure_View AS
SELECT School_ID, NAME_OF_SCHOOL, Leaders_Score, Leaders_Icon
FROM chicago_public_schools;
*
SELECT FROM Procedure_View
- Now let’s run the Stored Procedure with School_ID = 610038 and Leaders_Score = 50
- The result should be a change from Weak to Average
- As you see in the result image below the Leaders_Score is 50, Leaders_Icon = Average for School_ID 610038
UPDATE_LEADERS_SCORE ( 610038, 50) CALL
Transactions
You realize that if someone calls your code with a score outside of the allowed range (0-99), then the score will be updated with the invalid data and the icon will remain at its previous value. There are various ways to avoid this problem, one of which is using a transaction.
Task 1
Update your stored procedure definition. Add a generic ELSE clause to the IF statement that rolls back the current work if the score did not fit any of the preceding categories.
You can add an ELSE clause to the IF statement which will only run if none of the previous conditions have been met.
$$
DELIMITER UPDATE_LEADERS_SCORE ( IN in_School_ID INTEGER, IN in_Leader_Score INTEGER)
CREATE PROCEDURE
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
UPDATE chicago_public_schools= in_Leader_Score
SET Leaders_Score = in_School_ID;
WHERE School_ID
> 0 AND in_Leader_Score < 20 THEN
IF in_Leader_Score
UPDATE chicago_public_schools= "Very weak"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 40 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Weak"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 60 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Average"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 80 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Strong"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 100 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Very Strong"
SET Leaders_Icon = in_School_ID;
WHERE School_ID
ELSE ROLLBACK WORK;
END IF;
END$$
DELIMITER ;
Task 2
Update your stored procedure definition again and rename it this time TRANS_UPDATE_LEADERS_SCORE
Add a statement to commit the current unit of work at the end of the procedure.
Remember that as soon as any code inside the IF/ELSE IF/ELSE statements completes, processing resumes after the END IF, so you can add your commit code there.
$$
DELIMITER TRANS_UPDATE_LEADERS_SCORE ( IN in_School_ID INTEGER, IN in_Leader_Score INTEGER)
CREATE PROCEDURE
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
UPDATE chicago_public_schools= in_Leader_Score
SET Leaders_Score = in_School_ID;
WHERE School_ID
> 0 AND in_Leader_Score < 20 THEN
IF in_Leader_Score
UPDATE chicago_public_schools= "Very weak"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 40 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Weak"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 60 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Average"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 80 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Strong"
SET Leaders_Icon = in_School_ID;
WHERE School_ID < 100 THEN
ELSEIF in_Leader_Score
UPDATE chicago_public_schools= "Very Strong"
SET Leaders_Icon = in_School_ID;
WHERE School_ID
ELSE ROLLBACK WORK;
END IF;
COMMIT WORK;
END$$
DELIMITER ;
Take a screenshot showing the SQL query.
Run your code to replace the stored procedure.
Write and run one query to check that the updated stored procedure works as expected when you use a valid score of 38.
Write and run another query to check that the updated stored procedure works as expected when you use an invalid score of 101.
Let’s run the Transaction with:
- Leaders_Score is 38, Leaders_Icon = Average for School_ID 610038 on the same school we ran earlier
- This should change the score to 38 and Icon to “WEAK”
TRANS_UPDATE_LEADERS_SCORE ( 610038, 38) CALL
- Then run it with same School_ID but use a score of 101 to see if it ROLLSBACK
- So the result should be the same
TRANS_UPDATE_LEADERS_SCORE ( 610038, 101) CALL