curriculum/challenges/english/blocks/review-bash-and-sql/6724e46581a1742244e45b59.md
This is the process of organizing a relational database to reduce data redundancy and improve integrity.
Its benefits include:
1NF (First Normal Form)
students table into a separate student_phones table.2NF (Second Normal Form)
orders table into order_header and order_items to avoid attributes depending on only part of the key.3NF (Third Normal Form)
city_postal_code to a cities table instead of storing it with every order.BCNF (Boyce-Codd Normal Form)
Tip: Aim for 3NF in most designs for a good balance of integrity and performance.
SELECT, INSERT, UPDATE, DELETE, CREATE TABLE, ALTER TABLE, etc.Joins → Combines data from multiple tables (INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN).You can run SQL commands directly from the command line using the psql command-line client for PostgreSQL or similar tools for other databases.
For example, to run a SQL file in PostgreSQL:
psql -U username -d database_name -c "SELECT * FROM students;"
You can also execute MySQL commands directly:
mysql -u username -p database_name -e "SELECT * FROM students;"
# PostgreSQL
psql -U username -d database_name -f script.sql
# MySQL
mysql -u username -p database_name < script.sql
#!/bin/bash
DB_USER="school_admin"
DB_NAME="school"
# Insert student data
psql -U "$DB_USER" -d "$DB_NAME" -c \
"INSERT INTO students (name, age, major) VALUES ('Alice', 20, 'CS');"
#!/bin/bash
DB_USER="school_admin"
DB_NAME="school"
STUDENT_NAME="Bob"
AGE=21
psql -U "$DB_USER" -d "$DB_NAME" -c \
"INSERT INTO students (name, age) VALUES ('$STUDENT_NAME', $AGE);"
Tip: Sanitize variables to avoid SQL injection.
When you run SQL queries via psql, you can capture and process the returned values in your Bash scripts.
#!/bin/bash
DB_USER="school_admin"
DB_NAME="school"
# Get total student count
STUDENT_COUNT=$(psql -U "$DB_USER" -d "$DB_NAME" -t -A -c \
"SELECT COUNT(*) FROM students;")
echo "Total students: $STUDENT_COUNT"
Output → 42
#!/bin/bash
DB_USER="school_admin"
DB_NAME="school"
# Get top 3 students' names and ages
RESULTS=$(psql -U "$DB_USER" -d "$DB_NAME" -t -A -F"," -c \
"SELECT name, age FROM students LIMIT 3;")
echo "Top 3 students:"
echo "$RESULTS"
Output
Alice,20
Bob,21
Charlie,22
#!/bin/bash
DB_USER="school_admin"
DB_NAME="school"
# Get student names and majors
psql -U "$DB_USER" -d "$DB_NAME" -t -A -F"," -c \
"SELECT name, major FROM students;" | while IFS="," read -r name major
do
echo "Student: $name | Major: $major"
done
Shape of Output
Student: Alice | Major: CS
Student: Bob | Major: Math
Student: Carol | Major: Physics
It is a web security vulnerability where attackers insert malicious SQL code into input fields to manipulate the database.
This can lead to risky actions like:
An example of an SQL injection attack:
SELECT * FROM users WHERE username = ' " " OR "1"="1" -- ' AND password = 'anything';
This query would return all users because the condition OR "1"="1" is always true, allowing attackers to bypass login checks.
Use Prepared Statements: These separate SQL code from data, preventing injection. Here's an example (Node.js with pg):
client.query('SELECT * FROM users WHERE username = $1 AND password = $2', [username, password]);
Input Validation: Sanitize and validate all user inputs to ensure they conform to expected formats.
Least Privilege: Use database accounts with the minimum permissions necessary for the application.
Note: Never grant admin rights to application accounts.
The N+1 problem occurs when an application makes one query to retrieve a list of items (N) and then makes an additional query for each item to retrieve related data, resulting in N+1 queries.
Why It's Bad
-- 1: Get list of orders
SELECT * FROM orders LIMIT 50;
-- N: For each order, get customer
SELECT * FROM customers WHERE customer_id = ...;
Solution: Use JOINs or other set-based operations.
SELECT
orders.order_id,
orders.product,
orders.quantity,
customers.customer_id,
customers.name,
customers.email,
customers.address
FROM orders
JOIN customers
ON orders.customer_id = customers.customer_id
WHERE orders.order_id IN (SELECT order_id FROM orders LIMIT 50);
Always look for opportunities to combine related data into a single query.
Review the Bash and SQL topics and concepts.