tags:
- SQL
mysql -u root -h 127.0.0.1 -P 3306 -p
-u indicates the user. We provide the user we want to connect to the database as — root (synonymous with database admin, in this case).127.0.0.1 is the address of local host on the internet (our own computer).3306 is the port we want to connect to, and this is the default port where MySQL is hosted. Think of the combination of host and port as the address of the database we are trying to connect to!-p at the end of the command indicates that we want to be prompted for a password when connecting.SHOW DATABASES;
This returns some default databases already in the server.CREATE DATABASE `mbta`;
Instead of quotation marks, we use backticks to identify the table name and other variables in our SQL statements.mbta:
USE `mbta`;
cards TableTINYINT, SMALLINT, MEDIUMINT, INT or BIGINT based on the size of the number we want to store. The following table shows us the size and range of numbers we can store in each of the integer types.
These ranges assume that we want to use a signed integer. If we use unsigned integers, the maximum value we could store with each integer type would double.cards using an INT data type for the ID column. Since an INT can store a number up to 4 billion, it should be big enough for our use case!
CREATE TABLE `cards` (
`id` INT AUTO_INCREMENT,
PRIMARY KEY(`id`)
);
Note that we use the keyword AUTO_INCREMENT with the ID so that MySQL automatically inserts the next number as the ID for a new row.Should the ID column not be an unsigned integer? How can we denote that?
UNSIGNED while creating the integer.stations TableSHOW TABLES;
DESCRIBE command.
DESCRIBE `cards`;
CHAR — a fixed width string, and VARCHAR — a string of variable length. MySQL also has a type TEXT but unlike in SQLite, this type is used for longer chunks of text like paragraphs, pages of books etc. Based on the length of the text, it could be one of: TINYTEXT, TEXT, MEDIUMTEXT and LONGTEXT. Additionally, we have the BLOB type to store binary strings.ENUM and SET. Enum restricts a column to a single predefined option from a list of options we provide. For example, shirt sizes could be enumerated to M, L, XL and so on. A set allows for multiple options to be stored in a single cell, useful for scenarios like movie genres.stations table in MySQL.
CREATE TABLE `stations` (
`id` INT AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL UNIQUE,
`line` ENUM('blue', 'green', 'orange', 'red') NOT NULL,
PRIMARY KEY(`id`)
);
VARCHAR for the station name because names might be an unknown length. The line that a station is on, however, is one of the existing subway lines in Boston. Since we know the values this could take, we can use an ENUM type.UNIQUE and NOT NULL in the same way as we did with SQLite.Key field, the primary key is recognized by PRI and any column with unique values is recognized by UNI. The NULL field tells us which columns allow NULL values, which none of the columns do for the stations table.Can we use a table as the input to
ENUM?
SELECT statement but this might not be a good idea if the values within the table change over time. It may be best to explicitly state values as the options for ENUM.If we do not know how long a piece of text will be and use something like
VARCHAR(300)to represent it, is that okay?
swipes TableDATE, YEAR, TIME, DATETIME and TIMESTAMP (for more precise times) to store our date and time values. The last three allow an optional parameter to specify the precision with which we want to store the time.REAL data type. Here, our options are FLOAT and DOUBLE PRECISION as shown in the table below.
swipes table.
CREATE TABLE `swipes` (
`id` INT AUTO_INCREMENT,
`card_id` INT,
`station_id` INT,
`type` ENUM('enter', 'exit', 'deposit') NOT NULL,
`datetime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`amount` DECIMAL(5,2) NOT NULL CHECK(`amount` != 0),
PRIMARY KEY(`id`),
FOREIGN KEY(`station_id`) REFERENCES `stations`(`id`),
FOREIGN KEY(`card_id`) REFERENCES `cards`(`id`)
);
DEFAULT CURRENT_TIMESTAMP to indicate that the timestamp should be auto-filled to store the current time if no value is provided.Key field has a new value, MUL (multiple) for the foreign key columns, indicating that they could have repeating values since they are foreign keys.When we add constraints to a column, is there a precedence with which they take effect?
Does MySQL have type affinities?
INT and VARCHAR but unlike SQLite, it will not allow us to enter data of a different type and try to convert it.ALTER TABLE `stations`
MODIFY `line` ENUM('blue', 'green', 'orange', 'red', 'silver') NOT NULL;
line column and change its type, such that the ENUM now includes silver as an option.MODIFY in addition to the ALTER TABLE construct we are familiar with from SQLite.collections in the MFA database. A view current_collections displayed all the collections not marked as deleted. We will now use a stored procedure in MySQL to do something similar.USE `mfa`;
collections table, we see that the deleted column is not present and needs to be added to the table.
ALTER TABLE `collections`
ADD COLUMN `deleted` TINYINT DEFAULT 0;
Given that the deleted column only has values of 0 or 1, it is safe to use a TINYINT. We also assign the default as 0 because we want to keep all the collections already in the table.; to something else. Unlike SQLite, where we could type in multiple statements between a BEGIN and END (which we need for a stored procedure here) and end them with a ;, MySQL prematurely ends the statement when it encounters a ;.
delimiter //
CREATE PROCEDURE `current_collection`()
BEGIN
SELECT `title`, `accession_number`, `acquired`
FROM `collections`
WHERE `deleted` = 0;
END//
Notice how we use empty parantheses next to the name of the procedure, perhaps reminiscent of functions in other programming languages. Similar to functions, we can also call stored procedures to run them.;.
delimiter ;
collections table because we haven’t soft-deleted anything yet.
CALL current_collection();
UPDATE `collections`
SET `deleted` = 1
WHERE `title` = 'Farmers working at dawn';
Can we add parameters to stored procedures, ie, call them with some input?
Can we call one procedure from another, like with functions?
Can you leave any notes or comments in tables in MySQL?
schema.sql file describing the intent behind different parts of the schema, but there may be ways to add comments in SQL tables as well.transactions to log artwork being bought or sold, which we can create here as well.
CREATE TABLE `transactions` (
`id` INT AUTO_INCREMENT,
`title` VARCHAR(64) NOT NULL,
`action` ENUM('bought', 'sold') NOT NULL,
PRIMARY KEY(`id`)
);
collections because it is being sold, we would also like to update this in the transactions table. Usually, this would be two different queries but with a stored procedure, we can give this sequence one name.
delimiter //
CREATE PROCEDURE `sell`(IN `sold_id` INT)
BEGIN
UPDATE `collections` SET `deleted` = 1
WHERE `id` = `sold_id`;
INSERT INTO `transactions` (`title`, `action`)
VALUES ((SELECT `title` FROM `collections` WHERE `id` = `sold_id`), 'sold');
END//
delimiter ;
The choice of the parameter for this procedure is the ID of the painting or artwork because it is a unique identifier.CALL `sell`(2);
We can display data from the collections and transactions tables to verify that the changes were made.sell on the same ID more than once? There is a danger of it being added multiple times to the transactions table. Stored procedures can be considerably improved in logic and complexity by using some regular old programming constructs. The following list contains some popular constructs available in MySQL.

cards, let’s see what data types are available to us in PostgreSQL.
We can observe that there are fewer options here than MySQL. PostgreSQL also provides unsigned integers, similar to MySQL. That would mean double the maximum value shown here can be stored in each inteeger type when working with unsigned integers.
psql postgresql://postgres@127.0.0.1:5432/postgres
We can log in as the default Postgres user or the admin.\l and it pulls up a list.CREATE DATABASE "mbta";
\c "mbta".\dt. Right now, though, we will see no tables within the database.cards table, as proposed. We use a SERIAL data type for the ID column.
CREATE TABLE "cards" (
"id" SERIAL,
PRIMARY KEY("id")
);
\d "cards". On running this, we see some information about this table but in a slightly different format from MySQL.How do you know in PostgreSQL if your query is resulting in an error?
stations table is created in a similar manner to MySQL.
CREATE TABLE "stations" (
"id" SERIAL,
"name" VARCHAR(32) NOT NULL UNIQUE,
"line" VARCHAR(32) NOT NULL,
PRIMARY KEY("id")
);
We can use VARCHAR in the same way as in MySQL. To keep things simple, we say that the "line" column id also of the VARCHAR type.swipes table next. Recall that the swipe type can mark entry, exit or deposit of funds in the card. Similar to MySQL, we can use an ENUM to capture these options, but do not include it in the column definition. Instead, we create our own type.
CREATE TYPE "swipe_type" AS ENUM('enter', 'exit', 'deposit');
TIMESTAMP, DATE, TIME and INTERVAL to represent date and time values. INTERVAL is used to capture how long something took, or the distance between times. Similar to MySQL, we can specify the precision with these types.DECIMAL type is called NUMERIC.swipes table as the following.
CREATE TABLE "swipes" (
"id" SERIAL,
"card_id" INT,
"station_id" INT,
"type" "swipe_type" NOT NULL,
"datetime" TIMESTAMP NOT NULL DEFAULT now(),
"amount" NUMERIC(5,2) NOT NULL CHECK("amount" != 0),
PRIMARY KEY("id"),
FOREIGN KEY("station_id") REFERENCES "stations"("id"),
FOREIGN KEY("card_id") REFERENCES "cards"("id")
);
For the default timestamp, we use a function provided to us by PostgreSQL called now() thst gives us the current timestamp!\q.CREATE USER 'carter' IDENTIFIED BY 'password';
SHOW DATABASES;
This only displays some of the default databases in the server.rideshare database with a rides table. In this table, we stored the names of riders, which is personally identifiable information (PII). We created a view called analysis which anonymized the names of the riders, intending to share only this view with an analyst or other user.analysis view with the user we just created, we would do the following while logged in as the root user.
GRANT SELECT ON `rideshare`.`analysis` TO 'carter';
USE `rideshare`;
analysis view. We can now see the data in this view, but not from the original rides table! We just demonstrated the benefit of MySQL’s access control: we can have multiple users accessing the database but only allow some to access confidential data.SELECT `id` FROM `users`
WHERE `user` = 'Carter' AND `password` = 'password';
SELECT `id` FROM `users`
WHERE `user` = 'Carter' AND `password` = 'password' OR '1' = '1';
bank database.accounts table is this.
SELECT * FROM `accounts`
WHERE `id` = 1 UNION SELECT * FROM `accounts`;
PREPARE `balance_check`
FROM 'SELECT * FROM `accounts`
WHERE `id` = ?';
The question mark in the prepared statement acts as a safeguard against the unintended execution of SQL code.SET @id = 1;
EXECUTE `balance_check` USING @id;
In the above code, imagine the SET statement to be procuring the user’s ID through the application! The @ is a convention for variables in MySQL.SET @id = '1 UNION SELECT * FROM `accounts`';
EXECUTE `balance_check` USING @id;
This also gives us the same results as the previous code — it shows us the balance of the user with ID 1 and nothing else! Thus, we have prevented a possible SQL injection attack.In this example of prepared statement, does it take into account only the first condition from the variable?
Is this similar to the reason we shouldn’t use formatted strings in Python to execute an SQL query?