Placeholder Image

字幕列表 影片播放

  • [MUSIC PLAYING]

  • [MUSIC - FERGIE & Q TIP & GOONROCK, "A LITTLE PARTY NEVER KILLED NOBODY"]

  • FERGIE & Q-TIP & GOONROCK: (SINGING) Just one night,

  • all we got, just one nigh, all we got, just one night, all we

  • got, just one night, all we got.

  • A little party never killed nobody.

  • So we going to dance until we drop, drop, drop.

  • Mm, a little party never killed nobody.

  • Right here, right now, is all we got. skeeten-bod-op-bop.

  • [MUSIC - FERGIE & Q TIP &

  • GOONROCK, "A LITTLE PARTY NEVER KILLED NOBODY"]

  • (SINGING) A little party never killed nobody.

  • So we're going to dance until we drop.

  • Let's go.

  • A little party never killed nobody.

  • Right here, right now is all we got.

  • Oh, a little party never killed nobody.

  • So we're going to dance until we drop.

  • A little party never killed nobody.

  • [MUSIC - FERGIE & Q TIP &

  • GOONROCK, "A LITTLE PARTY NEVER KILLED NOBODY"]

  • MUPPET: [SNORING]

  • DAVID J. MALAN: All right.

  • This is CS50, and this is lecture 8.

  • And that was a look at the so-called CS50 hackathon, this annual tradition

  • with which we nearly end the semester that will start around 7:00 PM here

  • in Cambridge, will then end around 7:00 AM the next day in Cambridge.

  • And punctuating the evening will be quite a bit of work

  • on final projects, which is the overarching goal of the evening

  • to give students, both an academic and a very

  • social and collaborative environment in which to tackle

  • their final achievements in the course.

  • But also, as you gleaned there will be a bit of distraction, a bit of food

  • from Felipe's, typically, around 9:00 PM, a little bit of Domino's Pizza

  • around 1:00 AM.

  • And for those still standing as in the muppet there,

  • we'll treat you to breakfast at IHOP if you still have the energy.

  • Thereafter, we'll be the so-called CS50 Fair, the climax of everything

  • that you've done in CS50.

  • And more on that in the weeks to come.

  • So without further ado, where have we been these past several weeks?

  • Well, recall that, over the past couple of weeks,

  • we've been introducing web programming.

  • And most recently, did we try to tie together a lot of the topics

  • from the past few weeks.

  • HTML and CSS and JavaScript, and then Python, and then another framework,

  • another piece of software called Flask that

  • just made it easier and more possible to build web-based applications.

  • And the simplest example of that last week, recall,

  • looked a little something like this.

  • And this past week with the problems on similarities and survey,

  • have you been building your own web-based applications.

  • But they haven't quite had all of the pieces

  • that you might want to assemble into a web-based app.

  • And so today, we'll fill in those final blanks.

  • But recall that we've been trying to frame these applications, not

  • as one-offs or just tools that you built, but as part

  • of a common paradigm or a methodology.

  • And indeed, when you're learning computer science and software

  • engineering, you start to notice patterns in the software,

  • in the code that you're writing.

  • And humans tend to adopt these patterns because they save you time.

  • And then everyone can speak the same language, so to speak.

  • So MVC was the acronym we introduced last week, Model View Controller.

  • And that just speaks to this paradigm whereby

  • you organized certain type of code in one file, certain types of other code

  • and another file.

  • So your Python code goes in application.py.

  • Your HTML goes in your HTML files, your CSS in your CSS files, and so forth.

  • But what we didn't have last week was this thing here, really.

  • Model generally refers to your data.

  • And while survey, your most recent problem,

  • did have data, a CSV file that's arguably a model,

  • CSV is not terribly expressive.

  • You can pretty much just write rows to a text file, not unlike a spreadsheet.

  • But you can't really query it.

  • You can't easily insert or delete.

  • You pretty much would have to reconstruct the whole file.

  • And indeed, that's exactly what I did back in the day.

  • The very first web-based application I wrote back in sophomore or junior year

  • was the freshman intramural website.

  • And all I had available to me, both technologically and conceptually,

  • we're CSV files.

  • I had no idea what databases were, didn't realize how much easier they

  • could make my life.

  • So I stored all of the data behind these links here just

  • in very simple text files.

  • But today, will give you so much more power.

  • And especially, if you're coming into the class with an interest

  • in applying CS to other fields in medicine or the arts

  • or any world in which there's data, particularly,

  • in STEM and data science and the like, realize

  • that SQL has really become this incredibly powerful language

  • with which to solve problems in those and so many domains.

  • And ultimately, what your build, this coming week--

  • your very last CS50 problem set--

  • you have now peaked just about-- will be CD50

  • Finance, a web-based application by which you can buy,

  • or "buy" and sell stocks.

  • And so what you're going to do this coming week is write code

  • that implements a web application that resembles this whereby

  • your users and yourself will be able to register for an account,

  • log into that account.

  • You'll be given for free, thanks to us, 10,000 virtual dollars.

  • And then you can go ahead and buy and sell stocks via their symbol

  • using this application.

  • So for instance, if I go ahead and register myself here.

  • Let's say, username Malan, password 12345--

  • shouldn't have said that.

  • Go ahead and register here.

  • You'll see that, by default, I get this free $10,000 in virtual cash.

  • You know what, I'm going to go ahead and buy myself

  • a share of maybe Netflix, whose symbol is NFLX.

  • I'm going to go ahead and try to buy one share.

  • Voila.

  • And now you'll see that, not only do I have less cash left, about $9,600,

  • I now own a share of stock.

  • And if we reload this throughout the lecture, frankly,

  • the price might go a little up or a little down

  • because this web application you'll build

  • will also talk to an API, an Application Programming Interface--

  • so some third-party website that provides you with stock data.

  • So you ask it for the current price of a stock.

  • It gives you an answer in JSON format, if you

  • recall our short discussion of that.

  • And you'll integrate it, ultimately, into this interface.

  • So this will be the culmination of so many of the ideas

  • and the building blocks with which you've experimented.

  • But we need a few final pieces today.

  • So first and foremost, when I registered for this site, I created an account.

  • And indeed, I can go ahead and log out now.

  • And if I go ahead and log back in--

  • if no one's stolen my password yet, I can see my account and only my account.

  • But we haven't yet seen any mechanism in code

  • whereby you can implement this notion of logging in, right?

  • What is the underlying logic via which a website knows that you are logged in

  • or you're not logged in, right?

  • Clearly, when I went to this website just a moment ago,

  • it prompted me to log in because I was not because I had logged out.

  • But how did it know that?

  • And now that I am logged in, how does it know that I can click on "quote"

  • to get just the stock quote or "buy" just to buy a stock or "sell."

  • Why does it not prompt me every time I click a link to log back

  • in with my username or password?

  • What do you think?

  • AUDIENCE: Isn't cookies little files that

  • saves the data inside your browser's cache that let it know what's going on.

  • DAVID J. MALAN: Yeah, cookies--

  • little files that get saved by websites on your computer.

  • Now odds are, most everyone here has probably heard in some form,

  • cookies-- bad.

  • Maybe bad, privacy-invading, yes?

  • OK.

  • So true.

  • But most of the web would not work without them.

  • So someone else, what do you understand a cookie to be?

  • What is a cookie?

  • AUDIENCE: Basically saves your information

  • so you don't have to put it in every time.

  • DAVID J. MALAN: Yeah.

  • It saves your information so you don't have to put it in every time.

  • So in simplest form, it's exactly a combination of those answers.

  • Whereby, when I log into a website, you could

  • imagine that website just remembering my username and my password

  • by just saving them in a little file on my Mac or PC

  • so that the next time I visit a web page,

  • it just automatically sends them for me, so that the human doesn't

  • have to type them again and again.

  • Now let's find fault with that.

  • Feels like that would work, but what's a downside of that naive implementation?

  • What do you think instinctively?

  • AUDIENCE: The data is just out there?

  • DAVID J. MALAN: The data is just out there, right?

  • I have people in the office or at home or in a library

  • that I might not want to just be able to walk up to that computer

  • and just see this little text file planted on my computer.

  • Because then they could log in to my account by just digging around.

  • So it feels a little invasive.

  • Indeed, that's one of the threats of cookies.

  • So it turns out cookies or websites tend not to do that, at least,

  • if they're implemented well.

  • They instead just plant a really big random number on your hard drive

  • or in your computer's ram or memory.

  • So 1234567-- like, some really big number maybe with letters and numbers

  • maybe even some punctuation that uniquely identifies me.

  • And thereafter, any time I click a link on that same website,

  • after logging in, my browser, thanks to HTTP--

  • the language that browsers and servers speak that we discussed a few weeks

  • back--

  • just magically sends that same big random number

  • to the server again and again.

  • And so long as the server remembers that that big random number corresponds

  • to user name Malan, it can figure out whose account to show.

  • And why is it a big random number?

  • Why is it not just my password or my username?

  • Why am I proposing that it be a big random number?

  • AUDIENCE: Sometimes people can guess it by just using a random generator.

  • DAVID J. MALAN: Exactly.

  • In computer science, randomness is this incredibly powerful ingredient.

  • If you pick a big enough word or a big enough string

  • or sentence, the probability that some random adversary, or bad person

  • on the internet, is going to be able to guess or try

  • to guess that value is just so low, it's just not realistically

  • ever going to happen in your lifetime statistically.

  • And so random this gives us that capability.

  • And so you can think about this metaphorically in the real world

  • as being like a hand stamp.

  • If you've ever gone to an amusement park or a bar

  • or a club where you have to show your ID or you

  • have to pay for a ticket on the way in, sometimes they'll

  • stamp you with either visible or invisible ink.

  • And that's largely for efficiency so that, thereafter,

  • when you're in the amusement park, you can come and go.

  • And you don't have to repay or reprocess.

  • If you're in the bar or the club, you don't have to keep showing your ID.

  • They can check once, and then more efficiently let you come and go

  • as you please.

  • Because you're just presenting your hand or this virtual hand

  • stamp to the bouncer or to the gatekeeper at those places.

  • So cookies are exactly like that.

  • Unbeknownst to us all this time, anytime you visit a website into which you've

  • logged in, your browser is secretly but usefully

  • presenting a hand stamp to that server to remind it who you are.

  • Or rather, not really who you are, but of that big random number

  • so that, if the server remembers who that number belongs to,

  • it can figure out whose account to then show.

  • So put more concretely, if I actually pull up some of the HTTP examples

  • that we looked at in the past, let's consider this in context.

  • So almost everyone here has probably used Gmail at some point.

  • And you log in generally via page like this.

  • So it might be infrequent because you're not often

  • prompted to log into email because of-- surprise, surprise-- cookies

  • from Google being on your computer.

  • But let's see where those come from.

  • So when you request Google or gmail.com, you might send, in a virtual envelope,

  • so to speak, from your Mac or PC to the server, a message like this.

  • Families who've not seen this before, this

  • is what your browser is actually sending to a server in order

  • to request a home page of gmail.com.

  • Now, I'm going to simplify this a little bit

  • because there's a bunch of redirects--

  • HTTP 302s and 301's involved that aren't that interesting today.

  • So let's just assume that Gmail responds immediately.

  • Typically, Gmail would respond with this, saying 200 OK.

  • Here's the login page.

  • And here's a web page in text/html format.

  • But once you've logged in, what your Gmail actually does

  • is it also sends this.

  • Recall that we call these things HTTP headers--

  • key value pairs separated by colons that are semi-secretly sent from browser

  • to server and from server to browser.

  • Now we, more sophisticated developer types can see this stuff, right?

  • You can open up Chrome's network tab and start poking around.

  • And it's not secret per se.

  • It's just most people don't know it's there.

  • And what Google and other companies are doing is

  • they literally send a header called set-cookie, the value of which

  • is that big random value that the server has decided for you.

  • Your browser, assuming that it speaks HTTP properly,

  • should then save that value in RAM, your computer's memory,

  • or on your hard drive.

  • And then, every other click you make on gmail.com should send,

  • not just headers like this, but it should send the opposite header--

  • just cookie, not set-cookie, but cookie, which

  • is the presentation of that hand stamp.

  • And so every time you click a page on Gmail, or Facebook,

  • or almost any website into which you've logged in.

  • Those cookies have been planted on your computer.

  • Now recently, in both Europe and in the US,

  • have laws been passed that are increasingly putting pressure

  • on companies that operate internationally to present you

  • with cookie-based information, right?

  • You get these little pop-ups increasingly.

  • And you've been getting them for years in Europe saying,

  • can we plant cookies on your computer?

  • So given all of this, what might happen if you say

  • no, no cookies on my computer?

  • AUDIENCE: You have to keep logging in.

  • DAVID J. MALAN: You're going to have to keep logging in, right?

  • If you take away this fundamental HTTP feature, much of the web

  • breaks, or the user experience deteriorates significantly.

  • Now the flip side is cookies can be used, not only for good, so to speak,

  • but also for evil.

  • It turns out that there are a lot of ads on the internet, of course.

  • And that's what drives a lot of the revenue that makes it all possible.

  • Those ads typically come from image tags in your HTML or script tags

  • or some of the HTML tags we have seen in the class.

  • But they go to third-party servers, somewhereelse.com.

  • And the problem arises with cookies when those third parties are allowed

  • to plant cookies on your computer.

  • Because if you go to Google, and you go to Facebook,

  • and you go to Twitter-- bunches of websites.

  • Suppose they all have some middlemen advertising service advertising

  • on each of these websites.

  • That middlemen, so to speak, because they

  • have their ads and, therefore, their HTTP headers on this site,

  • and this site, and this site, there are big third parties

  • out there-- lots of them advertising networks-- that know everywhere

  • little old you is going because they see your cookie appearing

  • from multiple different other sites.

  • And so here's where cookies become, not a computer science, engineering feat,

  • but really a threat to one's privacy because they

  • can be used so easily for tracking.

  • And frankly, AT&T and Verizon, as an aside, got into trouble--

  • not enough people know this--

  • some years back when they started injecting, forcibly, additional HTTP

  • headers similar in spirit to this to all of people's cell phone traffic--

  • so not things you could even opt out of initially.

  • Because this was a way for advertisers and for themselves

  • to be able to track users.

  • So these HTTP headers on which cookies are based

  • are very powerful, but also very invasive.

  • And we're only now starting to see, societally and politically,

  • pushback on this very simple mechanism that, hopefully, we as CS types

  • just understand the mechanics of and, therefore, now the implications.

  • So let's see this in context, for instance.

  • Let me go ahead and open up a relatively small example in CS50 IDE.

  • For those unfamiliar, CS50 IDE is a web-based application

  • via which you can write programs in the cloud,

  • just using any browser on a Mac or PC.

  • I'm going to go ahead into my account here.

  • And I'm going to go into Store.

  • And I'm going to go into the Templates directory

  • and show that this example here has a few files.

  • This will look familiar to students in the room.

  • Application.py is the web-based application.

  • And then we have some template files, so to speak.

  • In my Terminal window here, I'm going to go ahead and, with just my keyboard,

  • go into this directory called Store in source 8, which is available online.

  • And I'm going to go ahead and do a flask run, which, for those unfamiliar,

  • is the command via which you can start a web server

  • and start running a web-based application.

  • So now that I have that, I'm going to go ahead and visit exactly this URL here.

  • And we'll see a relatively simple and super ugly web store.

  • Let me go ahead and zoom in a bit.

  • And this web store allows me to buy three things-- foos, bars,

  • and bazes, whatever those are.

  • And this is a very simple e-commerce-like site

  • where I just have to type the quantity of foos, bars, and bazes that I want.

  • And then I can go ahead and buy them.

  • So I'm going to go ahead and say, give me one foo, how about zero bars,

  • and these two bazes.

  • And I'm going to go ahead and click Purchase.

  • And now you'll see my shopping cart.

  • But if I continue shopping, you'll see that it

  • resets, just like if you keep browsing Amazon or whatever other website.

  • But if you want to check shopping cart again,

  • notice it's remembered what I'm looking for.

  • And in fact, you know what?

  • I'm going to go ahead and close the window.

  • Oops.

  • I actually lost the website.

  • But you know what?

  • If I go back to that URL and reopen, I see the storefront.

  • But if I view my shopping cart, it has remembered my state.

  • So notice the power now of cookies.

  • It's not just to remember with a hand stamp who you are.

  • But now you can remember anything about that user that you want, right?

  • A shopping cart on Amazon or any website is the best example of this

  • because it would be horrible, horrible, horrible for a User Experience or UX

  • if every time you click the darn link, you

  • lost the contents of your shopping cart because the website forgot who you are.

  • So this is a compelling feature to remember.

  • And it's cookies that implement this feature too.

  • Because more generally, what's going on with cookies is this.

  • When you set a cookie using the set-cookie header that

  • looked like this, there is a key value pair

  • to the right that we might call session, and that has the value.

  • Value is the hand stamp.

  • Session is just a term of art that refers to this abstraction

  • that you can think of really as a shopping cart.

  • But it doesn't have to have anything to do with actual shopping or e-commerce.

  • It's just a container in which you can store stuff.

  • So this is telling the website that my session value, my hand stamp

  • is 12345-- and big really random number.

  • The website can then say, you know what?

  • I'm going to store a container for you.

  • Let's call it a Python dictionary, or dict for you,

  • inside of which I can put anything I want.

  • And so in fact, when you go to a shopping cart like this,

  • what is the server actually doing?

  • Well, upon seeing your hand stamp, and realizing, oh, you are user 1234567.

  • Oh, that's username Malan.

  • Let me go ahead and grab the dictionary, the Python dict

  • from memory, or even from a CSV file if you want,

  • and show you the contents of your shopping cart.

  • Meanwhile, someone else, Brian visits the same exact website

  • and logs in with his account.

  • He's going to present a different hand stamp, presumably.

  • And so the website can look for a different dictionary

  • and show Brian the different contents of his shopping cart.

  • And the same for everyone in this room.

  • So this simple mechanism--

  • I mean, consider the power.

  • This is just a stupid text value key:value.

  • And from all of that does all of the web's capabilities now come.

  • And we won't look in too much detail into the code here,

  • but let me show one snippet of it.

  • If I go into application.py, the magic that makes this possible in flask

  • is just to import this additional feature.

  • You'll recall, from the past couple of problems

  • you've worked on, you import from flask a few things--

  • render template, redirect, request.

  • Well, if you Add session to that list, which

  • is the code abstraction of this hand-stamp idea, what you can now do

  • is this.

  • Let me scroll down to the juicy part here.

  • And notice that you can do lines of code now,

  • and for the next CS50 finance problem, lines of code like this.

  • Session is just a Python dictionary, or dict.

  • You can index into it using any word--

  • foo, or bar, or baz, just like you could with dictionaries more generally.

  • And you can store in it anything you want.

  • In my case, I want to store a number--

  • 0 foos, or 1 foo, or 2 foos or whatever.

  • So I can simply convert to an int, the user's request forms

  • item, whatever that is.

  • And let me wave my hand at some of the code above because it just

  • sets the whole thing up.

  • But the new line of code, the new feature

  • that now will empower us to build something like a stock trading website

  • is quite simply this line here.

  • Because what you can also do to remember that a user is logged in,

  • just go ahead and store in this so-called session,

  • a value of, like, true.

  • And if the value true is there, you can infer that the human is logged in.

  • And if there's no such value in the dictionary, they are not logged in.

  • And so we'll hold your hand a bit more in the next problem set

  • with this introduction of CS50 Finance.

  • And we'll write some of the code that handles the login,

  • so you can see by example how to do this.

  • But it'll be up to you thereafter to start

  • remembering what stocks a user actually has

  • using sessions to retain the fact that they've logged in already.

  • All right.

  • So that was a lot all at once.

  • But any questions on cookies and the feature they provide,

  • these things called sessions?

  • Anything at a all?

  • Yeah?

  • AUDIENCE: Is the session saved on the user side or the server?

  • DAVID J. MALAN: Is the session saved on the user side or the server?

  • Really good question.

  • And the answer can be it depends.

  • You could store on the user's client, on their browser.

  • And as the gentleman over here proposed, you could theoretically store literally

  • their user name and password-- maybe I proposed that earlier--

  • on their computer.

  • And that's bad for the reasons that we surmised earlier.

  • But you could also store the contents of their shopping cart, foos, bars,

  • and bazes.

  • That's not quite as invasive as storing their password.

  • But if you're buying things you don't really want people knowing,

  • that is then invasive.

  • So maybe we can do better.

  • And better is often, store it on the server.

  • So a well-designed website will typically

  • store only this big random value, the hand stamp, on the Mac or PC.

  • And then all of the interesting and maybe sensitive stuff

  • is stored in a database or CSV file or just the server's RAM or memory

  • like in a global variable.

  • Good question.

  • Other questions?

  • Other questions?

  • No.

  • All right.

  • So that's one problem solved.

  • We know now we can implement login forms.

  • And we know that we can remember that people are logged in.

  • So let's just stipulate that is now possible.

  • But over the past couple of weeks, it's not been incredibly powerful

  • to only have access to things like CSV files, comma separated values, which

  • create the illusion of Excel and Google Spreadsheets

  • and Apple Numbers like columns and rows.

  • Why?

  • Well, it's pretty much a linear search for everything, right?

  • A CSV file is just rows and rows and rows and rows of data.

  • And if you want to search for anything in that

  • file, like you might have wanted to for your survey implementation,

  • how do you find it?

  • Well, you open the file with Open.

  • You maybe use a for loop and iterate over every single line

  • looking for some value, and then you close the file.

  • That is big O of n.

  • And in the worst case, the thing you care about is at the very end.

  • And it's not terribly efficient.

  • Now, you can append to files pretty efficiently.

  • Recall that when we opened files with quote unquote, "A" for Append mode.

  • We did this with a brief example, instead of "W" for Write.

  • You get the operating system's help and add rose to the file

  • at the very bottom, which is more efficient.

  • But you can't insert things in the middle very efficiently.

  • You can't delete things very easily.

  • You would have to literally, for those kinds of scenarios, open the file,

  • read the whole darn thing, then write out parts of it

  • or add to it as you're writing out.

  • And so humans years ago realized, well, this is stupid.

  • All of us humans in the world are constantly

  • writing code to open files, change files, save files.

  • Why don't a few of us do an even better job of implementing that feature,

  • then share it with the world?

  • And thus were born, effectively, databases.

  • And these days, there are so many different types of databases--

  • you might be familiar with tools, commercial software like Oracle,

  • or SQL Server, or Microsoft Access.

  • And in the open source world, there's Postgres and MySQL,

  • and SQLite and others.

  • And many of them, as even those names imply,

  • use a special language called SQL, Structured Query Language, which

  • is the very last language we'll introduce

  • you to in CS50 unless you go off on your own with final projects

  • to pick up something more.

  • But with SQL, you have the ability to select data from a database,

  • to insert it, to delete it, to updated it.

  • All of the things that you could absolutely do with Python and CSVs,

  • it would just be so darn tedious to write those lines of code yourself.

  • So what's the right mental model?

  • Here is, I claim, essentially a database.

  • Like most everyone in this room has probably

  • used Google Spreadsheets, and if you've not, probably

  • Excel or maybe Apple Numbers.

  • So these are spreadsheets.

  • And they're essentially what you could call a relational database.

  • Relational-- implying that there's relationships

  • among the various data in the rows and the columns decided by you

  • or whoever made it.

  • And this is a spreadsheet of course.

  • And it has rows where your actual data goes.

  • And columns-- and what's noteworthy about the columns?

  • It's just conventional to do what with the columns,

  • especially in that first row?

  • AUDIENCE: Headers.

  • DAVID J. MALAN: Yeah, put some header values, right?

  • You could certainly put them in the left.

  • It's just humans prefer, it seems, to read top

  • to bottom instead of left to all the way to the right.

  • So we just adopted a conventioneers ago that your columns represent

  • different types of data, and the rows represent different values

  • for those fields or for those columns, so to speak.

  • So if you wanted to store a spreadsheet of values

  • for a bunch of students in a class or in a university,

  • one column might be ID number, like their Harvard ID or the Yale ID.

  • Another column might be their name, their email address, phone number, age,

  • and so forth.

  • And you could just lay that all out.

  • You can make it pretty and boldface the top and organize things and sort it.

  • But at some point, this isn't quite the right tool.

  • And in fact, I ran into this in grad school years

  • ago where I was analyzing large sets of data.

  • And it was just convenient to double-click on the CSV file,

  • open it in Excel, and just manipulate it and answer the data

  • questions that I had.

  • But back in the day, Excel actually had a limit of 65,536 rows.

  • Sounds like a lot--

  • and that's 2 to the 16th power, if you call the reference there.

  • And so humans at Microsoft decided years ago, that's enough.

  • And frankly, it kind of was.

  • Because even in the thousands of rows, like,

  • my Mac just became unusable because it was just too much memory being used.

  • So it was just an impractical limit anyway.

  • But at some point, you might want to store

  • 65,537 rows of data or hundreds of thousands of rows or millions of rows

  • or even more.

  • I mean, there are so many websites, Google and Facebook

  • and others that surely do this already.

  • You can't just use a program on your Mac or PC anymore.

  • You need to use fancier software.

  • But that fancier software often still works the same way.

  • You have one main file called a spreadsheet in our human world.

  • But in the server world, you might call it a database instead.

  • And whereas, in our human world, we might

  • have things called Sheets or individual spreadsheets within the bigger file,

  • in a database, you're going to have things called tables.

  • But they're the exact same thing with rows and columns.

  • And so when we want to actually store data,

  • we can actually store it in exactly those ways.

  • So let me go ahead and do this.

  • Let me go ahead and open up Google Spreadsheets just

  • as representative of a database.

  • And let me go ahead and create a new file here.

  • So New Spreadsheet-- and just so that we can represent things like students.

  • I'm going to call this spreadsheet Students.

  • And over here I'm going to put their ID number and their name, and what

  • are some other fields I rattled off that come to mind?

  • AUDIENCE: Email.

  • DAVID J. MALAN: Email.

  • AUDIENCE: Dorm.

  • DAVID J. MALAN: Say again.

  • AUDIENCE: Dorm.

  • DAVID J. MALAN: Dorm.

  • Good.

  • AUDIENCE: Sports and stuff they want to do.

  • DAVID J. MALAN: OK.

  • So sports they want to do, sure.

  • That's fine-- a little longer.

  • What else?

  • AUDIENCE: Graduation year.

  • DAVID J. MALAN: Graduation year, age, OK, good.

  • So graduation year, age, concentration--

  • OK, and we can probably keep going, and it just gets wider and wider.

  • And these are my columns, if you will, or the fields in the database.

  • And frankly, I could name this if I really want to be tidy here,

  • and I could call this Students.

  • And you know what?

  • Maybe I should call this not students but university.

  • Because I might want to have another tab here that we'll preemptively

  • name to, say, faculty.

  • And faculty probably have ID numbers, and they have names,

  • and they probably have departments, for instance.

  • And they also probably have emails and so forth.

  • So phone number is another one.

  • But I might want to kind of cluster these different types

  • of data in different spreadsheets because they're

  • kind of apples and oranges.

  • There might be some overlap, but they're distinct inside different sheets.

  • In the database world, you do the exact same thing,

  • except you call the whole thing a database,

  • and you call these things tables to be clear.

  • But more importantly, with a real database, so to speak,

  • you have to be a little more proactive about telling the database what

  • types of data you want to store.

  • Now, those of you who've used Google Spreadsheets and Apple

  • numbers and Excel know that you can go to the format menu or the data menu

  • or whatever, and you can show things to different decimal places.

  • You can turn things to percents.

  • And you can format the data.

  • But that doesn't tend to have any functional impact on your data.

  • It's just an aesthetic detail, like, how long or short do

  • you want to show the numbers to be in your columns and cells.

  • But with databases, you can actually provide juicy hints

  • to the database that will help that database store and find data for you

  • more efficiently.

  • For instance, there's this laundry list of data types

  • to which we have access in SQL.

  • So SQL is the language with which we're going to be able to query a database.

  • Frankly, in something like Google Spreadsheets and Microsoft Excel,

  • how do you find data?

  • We'll usually hit Command-F or Control-F, and you search for it.

  • That's not very programmatic.

  • You can do it with macros and such.

  • And we'll do this with code.

  • But with SQL, you're going to have to make a few decisions first.

  • SQL supports a few different data types, at least, in one of its forms.

  • So it turns out there's a lot of competition out there.

  • SQL is a general language.

  • But different companies and different nonprofit groups

  • have come up with their own dialects.

  • So much like we humans might speak--

  • bunches of us might speak Spanish.

  • Well, there are different variations of Spanish, not to mention

  • many, many, many other languages.

  • And so similarly, in the programming world,

  • as there's sort of a common subset of words in a language.

  • But then different companies and different people

  • might have added and subtracted their own features just because they think

  • that's better for their use cases.

  • So in SQLite, which is the database technology we will use in CS50 IDE,

  • and Android uses this, and it's very popular in other contexts

  • too, IOS as well--

  • they only have a few data types.

  • Blob, of all things, integer, numeric, real, and text.

  • Now what does that mean?

  • Well, it turns out, it means different things with different databases.

  • In another popular database, it's called Postgres or PostgreSQL.

  • This is a very popular one for high-performing websites.

  • So if you're trying to build a business, you're

  • trying to make an application used by everyone on campus, generally,

  • you would use a fancier technology than SQLite, which is, by definition,

  • lightweight.

  • And you'd do something like Postgres.

  • And so we'll introduce you to both of these dialects along the way

  • because each of them allows us to do different things

  • with a different degree of precision.

  • So in SQL, let's claim, even though it's a simplification,

  • there are at least these data types.

  • When deciding what type of data to store in your database table,

  • you have to decide, not just what it's called, like ID, and name, and email,

  • and dorm.

  • You have to decide what data type it is.

  • So we've kind of come full circle.

  • Because the last time we did this was in what language?

  • C.

  • So in SQL too you do this, but it's not to be nitpicky.

  • It's to actually improve performance.

  • So this is to help you get at that data more efficiently.

  • Because the more the server, the database, knows about your data,

  • the faster it can find it essentially.

  • So in the world of databases, you generally

  • have to decide, not just to store an integer, but either

  • a small int of integer, or a big int.

  • And generally speaking, at least in most databases, this might be 2 bytes.

  • This might be 4 bytes.

  • This might be 8 bytes.

  • So let's maybe impress the families here.

  • If you have a 32-bit integer, or 4 bytes,

  • what's the biggest integer you can store in your database?

  • (WHISPERS) 4 billion.

  • Someone please, impress.

  • AUDIENCE: 4 billion.

  • DAVID J. MALAN: 4 billion is exactly correct.

  • And it might be 4 billion positive values, or maybe it's only 2 billion

  • if you also want to have 2 billion or so negative numbers as well.

  • Big int uses 64-bit, which is just massively, massively bigger.

  • And tiny int or small int rather--

  • there's also tiny int in some dialects-- small int is just 2 bytes,

  • and it actually counts up as high as 65,535, as I alluded to earlier.

  • So you just need to decide.

  • Now, why would you choose one or the other, when you could just use big int

  • and store small numbers and big numbers alike?

  • Well, why might you just intuitively not want to make all of your integer values

  • in a database big ints.

  • It's just simple-- give me as much headroom as I want.

  • AUDIENCE: You would be using memory.

  • DAVID J. MALAN: Yeah.

  • You're just using memory unnecessarily, right?

  • Why use more memory than you need to?

  • Now, arguably-- god, memory is so cheap these days.

  • Computers are getting bigger and faster.

  • So in some contexts, it's not a big deal.

  • But if you have lots of data, and every one of your rows in a database

  • is 2 bytes bigger than needs to be, and you have 1 million rows,

  • that's already huge numbers of bytes that you're just wasting and throwing

  • away.

  • So it behooves you to actually give some thought to these data types.

  • Of course, you don't want to go too small

  • because, if you use a small int or maybe even an integer,

  • but business is so darn good that you have over 4 billion users or 4

  • billion rows or 4 billion foos and bars and bazes that have been sold,

  • which absolutely happens to the Googles and Facebooks of the world,

  • you better start using 64 bits to represent unique values instead of just

  • 32.

  • Because eventually, you'll run out.

  • Well, what else?

  • Besides integer values in SQL, you might want to use floating point values.

  • Those are real numbers that have decimal points in them.

  • This is quite like C. They're called a little something different.

  • And annoyingly, it uses two words in this case.

  • But a real number is a 32-bit value that is a floating point

  • value, like a float in C, and double precision

  • is like a double in C, which is 64-bits.

  • And that just lets you get even finer-grained control

  • over the decimal point as we've seen.

  • Because of course, you can't represent numbers precisely

  • because of imprecision, as we've seen in both Python and C.

  • Numeric is kind of a catch-all for a bunch of number-related things

  • that aren't quite integers or reals necessarily.

  • Boolean, a true or false value, dates if you

  • want to literally store, like, year, year, year, year, dash, month, month,

  • dash, day, day in a standard computer format,

  • even though human cultures vary how they write that.

  • Datetime if you want have a date and a time right after it--

  • numeric is actually a solution to a problem.

  • Turns out that, finally, after all this time,

  • we have a built-in mechanism for storing numbers precisely.

  • And this is perfectly timed because, in CS50 Finance, when

  • you're dealing with money, it would kind of be nice if you don't accidentally

  • round off how much money someone has either slightly lower or slightly

  • higher.

  • Those of you may be families especially because, from a few movies back

  • in the day, if you ever saw Superman III,

  • this is how some money was made by shaving fractions of pennies

  • off of computer systems and, more moderately, Office Space.

  • Office Space did this as well-- big scam trying to round off these pennies.

  • Well, if you use the right technology and language, with SQL,

  • you can actually specify a numeric data type, which is like a floating point

  • value, but you specify, essentially, the total number of digits you

  • want it to handle and how many of them should be after the decimal point.

  • So it's common in stock markets to actually use

  • four decimal points of precision.

  • So not just cents to the tenths and the hundredths place,

  • but to the thousandths and ten-thousandths place,

  • you can now specify that with a value of four for precision.

  • And you don't have to worry about those round

  • off errors we talked about before.

  • Time and time stamps-- just how much time

  • has passed since the date and date and time are also available to you in SQL.

  • And then lastly here, text values--

  • turns out you have a choice of values for when

  • it comes to deciding how many characters do you use to store your data.

  • You can use char, which just like in C with an array,

  • you have to decide in advance for a string how many bytes to use.

  • And if you say char 8, you are getting 8 bytes.

  • And if the name is Malan, M-A-L-A-N, you are wasting 3,

  • or if we null terminate it, 2 of those bytes.

  • But SQL introduces a solution that Python kind of gave us too.

  • Varchar as the name implies-- variable number of chars

  • allows you to specify just an upper bound.

  • So if you know that one of your columns is going to be called Name.

  • And a person's name might be M-A-L-A-N-- like five letters,

  • or maybe certainly more for people with longer last names are first names,

  • you can say varchar 100.

  • And that's the upper bound on how long it is.

  • But the database will be smart.

  • If you only need five characters or 5 bytes,

  • it won't waste 95 others for you.

  • It will optimize that for you.

  • And then lastly text, if you want to store tens of thousands,

  • like paragraphs or pages of text, that's even bigger than varchar

  • where you don't necessarily want a well-defined upper bound.

  • You just want a good chunk of memory.

  • But there are implications here.

  • And just quickly, char and varchar seem not even complimentary.

  • Just char seems unnecessary.

  • Why paint yourself into a corner and say give me

  • only 8 bytes when you could just say, eh, give me

  • up to 100 bites, and you, the database server,

  • figure out how many to actually use?

  • Why do these two data types exist?

  • Yeah?

  • AUDIENCE: Time.

  • DAVID J. MALAN: Time.

  • AUDIENCE: It would be longer to run.

  • DAVID J. MALAN: Yeah.

  • So time is spot on.

  • It might actually take longer to use one data type or the other.

  • How could that possibly be?

  • Well, if you've got a value like char where you specify

  • a precise number of characters like 8.

  • If you think about the columns in Google Spreadsheets and Excel,

  • every one of those columns, those cells is exactly the same width, right?

  • It's 8 bytes, 8 bytes, 8 bytes, 8 bytes.

  • And as soon as you have perfectly constant offsets--

  • this is byte 0, this is 8, this is 16, this is 24, this is 32,

  • and so forth, you reintroduce the capability

  • that in C we had with arrays.

  • You have random access doing simple, simple arithmetic-- multiplication,

  • addition, and subtraction, you can just jump to any element in a column

  • if it's using the same number of bytes for every cell.

  • But with varchar, if you need to have small narrow cells and wide cells,

  • you're going to have what's called a ragged array where

  • one side of it, the left-hand side, so to speak,

  • is going to be very straight and rigid.

  • But the other side my kind of vary based on how long the word is in that column.

  • And to your point about time, it's going to take the computer more time

  • to search a varchar field.

  • Because it can't just jump to the third element.

  • It has to search all of them, potentially.

  • But thankfully, at the end of the day, databases don't do that.

  • They don't just devolve into linear search.

  • CSVs devolve, for our purposes, into linear search.

  • The magic and the intellectual property and the secret sauce, so to speak,

  • that goes into databases--

  • Oracle SQL Server, Microsoft Access, Postgres, MySQL, and SQLite

  • is that really smart computer scientists have decided to implement algorithms

  • and fancy data structures, often tree-based--

  • if you recall our discussion of binary trees

  • or tries on a hash tables and those fancier data structures-- they

  • had baked those kinds of data structures and designs

  • into their database software.

  • They've made it freely available or commercially available.

  • And so we now just have an abstraction called a database

  • into which we can store data and just read it, update it, write it,

  • and change it quickly without having to implement all

  • of that low-level plumbing ourselves.

  • And so that's ultimately what a database is going to give us.

  • But we have to actually have access to a database to do that.

  • And we need to actually decide first to help

  • the database by telling it what to store where and how to store it as a type.

  • So why don't we do this?

  • Let me go ahead and do exactly that with a couple of examples.

  • Let me go ahead and open up CS50 IDE again,

  • our web-based programming environment.

  • And let me go into our Terminal window.

  • So for those unfamiliar, a terminal window is just this black and white

  • or this blue and white window in which you can type commands.

  • And rather than point and click and double click on things,

  • you can only do things textually in this window.

  • And it turns out that, in the world of SQLite,

  • we can actually use a command called SQLite3,

  • which allows us to create a database.

  • So in our human world, for CSVs, you've seen how, in code, you

  • can just create rows and columns.

  • You can literally type it in a text box.

  • SQLite is a database technology that uses binary format, 0s and 1s.

  • And so you're going to have to actually store your data differently

  • using a program.

  • So if I want to make a file called, for instance, froshims.db,

  • I can literally say SQLite three froshims.db,

  • and then I'm in this program.

  • This is a text-based program via which I can create my rows and columns.

  • And it, by designer, is going to be a little arcane for a moment.

  • It's going to look a little cryptic.

  • But if I want to go ahead and create a table, like a spreadsheet in here,

  • I'm going to literally type CREATE TABLE.

  • I'm going to call this registrants just like last week

  • when we were looking at froshims examples.

  • And the freshman intramural sports program

  • has students registering for sports.

  • So I'm going to have a registrants table here.

  • I'm going to go ahead now and specify that I

  • want a few columns for this database table, one of which I want to call ID,

  • one of which I want to call name, and one of which I want to call dorm.

  • So I'm going to keep-- whoops.

  • I didn't mean to hit Enter.

  • Let me just clean this up.

  • So now I have three columns, ID, name, and dorm.

  • And if I were to hit Enter, theoretically, it

  • should create a database.

  • It's not going to be graphical like Excel or Google Spreadsheets,

  • but it will exist in my IDE in a file called froshims.db.

  • But I can't just hit Enter yet.

  • Because I have to tell the database a bit more.

  • I need to tell it that, you know what?

  • My ID value should probably be an integer.

  • And you know what?

  • My name should probably be char, or varchar?

  • What should the name of a student be stored as?

  • AUDIENCE: varchar.

  • DAVID J. MALAN: Varchar, OK?

  • So varchar because they're going to vary, right?

  • If you can think of bunches of your friends,

  • they might have short names or long names.

  • OK, what's the upper bound?

  • What's the length of your friends' longest name?

  • AUDIENCE: 50.

  • DAVID J. MALAN: 16?

  • All right.

  • Is anyone in here having a name, first name and last, that's longer than 16?

  • AUDIENCE: That's 50, sorry.

  • DAVID J. MALAN: Oh, 50.

  • Sorry.

  • I heard 16, I thought.

  • Because you're not going be able to register for froshims

  • because the database is going to truncate.

  • And as an aside, if you've ever gone to a website and tried typing into a form

  • field and either your keyboard stops working

  • or you do type a long word or paragraph in, and then you hit Enter,

  • and it's some of it's gone, well, that's because the database likely

  • can only store so many bytes.

  • And frankly, this often happens on customer service forums, right?

  • They don't really want you being too verbose with the customer support

  • staff.

  • They'll cap the length of the field into which you're typing.

  • And they're also doing that on the database,

  • but also probably for practical human reasons,

  • they don't want to read a big complaint that's this long as well.

  • So 50-- anyone have a name longer than 50 characters?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: Yeah, not many names.

  • But you know what?

  • We have technology to answer this.

  • Longest name in world--

  • and it's this guy.

  • Guinness Book of World Records is probably right.

  • So his name is Barnaby Marmaduke Aloysius Benjy Cobweb Dartagnan Egbert

  • Felix Gaspar Humbert Ignatius Jayden Kasper Leroy Maximilian Neddy Obiajulu

  • Pepin Quilliam Rosenkranz Sexton Teddy Upwood Vivatma Wayland Xylon Yardley

  • Zachary Usansky.

  • But he also goes by Nick, apparently.

  • But OK.

  • Let me go ahead and highlight this.

  • And I could count this manually.

  • But I'm sure someone has made a website to count characters in a string.

  • There we go, lettercount.com.

  • OK.

  • Let's go ahead and paste that in, count the characters, 225--

  • so nick will not be registering unless we don't support just 16 or 50.

  • Looks like we need at least 225.

  • So at some point, you do have to make a decision.

  • And honestly, it's not always obvious.

  • You do have to specify that varchar is going to be-- eh, it could be 16,

  • could be 50, could be 225.

  • But you know what? if he has kids--

  • so let's just round up a bit and call it varchar 255, honestly,

  • only because it was a convention.

  • So back in the day, 255 tended to be the max length

  • for this field in older databases.

  • And that at least feels like it's probably enough wiggle room for names.

  • But you have to make a judgment call at some point.

  • We could ignore the problem say 1,000 characters.

  • But if that's never really going to happen,

  • and your potentially wasting space, you probably shouldn't.

  • Because even though it's an upper bound, you're sacrificing something like time,

  • potentially, to search that field if you're just

  • telling the database that it's going to be bigger than it ever actually

  • will be.

  • It needs to be more finely hinted.

  • So what about dorm?

  • Oh, god, now we have to do this again.

  • How do we do it with dorm?

  • What's the longest length of a dorm or a house on campus?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: I'm, like, OK [INAUDIBLE],, house maybe.

  • But honestly, at some point, it doesn't matter too much.

  • But being consistent is what matters.

  • It's a matter of style.

  • It's a matter of design.

  • At some point, you don't have to nitpick every little value.

  • But you should probably pick some reasonable value

  • that you could justify to a roommate or to a colleague or to a teaching fellow.

  • And then say this feels like enough without it being actually excessive.

  • And there's one last thing I'm going to do here is just

  • end my thought with a semicolon.

  • I apologize, they're back.

  • But at the end of my start here, if I haven't made any typographical errors,

  • and I'm going to go and hit Enter.

  • Nothing seems to happen.

  • And ironically, in CS50, in programming, nothing happening

  • is usually a good thing because it means no errors have happened.

  • If, in SQLite, I type schema, I can actually

  • just see a regurgitation of the table I just created.

  • But more importantly, I can start to insert data into this.

  • Now unfortunately, it's not yet graphical.

  • But if I want to insert data into this, I can do this.

  • INSERT INTO registrants-- well, what do you want to insert?

  • I want to go ahead and insert an ID, a name, and a dorm.

  • Well, with what values?

  • Well, with these values--

  • the ID will be-- the first registrant will be 1.

  • The first one to register will be Brian.

  • And his dorm, Brian where did you live?

  • BRIAN: Out on Pennypacker.

  • DAVID J. MALAN: Pennypacker.

  • So it's good.

  • That might be close to four timer too lengthwise.

  • So I'm going to go ahead and do this.

  • Here is an example of a SQL statement.

  • CREATE TABLE is one verb or expression you can use.

  • INSERT INTO is another.

  • You specify the name of the table, the fields of the table, and then values.

  • And now I'm capitalizing just to make clear what are SQL commands

  • and what are actually just words I, the human developer, chose.

  • But it's just a convention.

  • These uppercase words could probably be lower case in most contexts too.

  • But it helps things, I think visually, to distinguish.

  • Now I go ahead and enter.

  • Nothing seemed to happen.

  • That's probably a good thing.

  • Let's go ahead and register one other person.

  • I'll be the second registrant.

  • So maybe David from Matthews.

  • And so Matthews here, Enter.

  • And now, if I want to select all of the students in the database,

  • I can go ahead and say SELECT FROM--

  • or you know what?

  • Let's select everything as denoted in many languages by star,

  • from registrants semicolon enter, and there we have it.

  • It's kind of a tiny super simple, lightweight database.

  • But there are my rows and columns much like Excel

  • and Google Spreadsheets would lay them out for me.

  • But it gets better than this.

  • Suppose I want to search this database for all of the students who

  • registered for Matthews.

  • And suppose that time passes and more students

  • actually register for forshims.

  • I can actually filter this data.

  • I can do something like SELECT star FROM registrants WHERE

  • dorm equals quote unquote, "Matthews."

  • And so I can filter it, hit Enter, and now I get back just one row.

  • And if your should mind starts to wander--

  • wow, if I could introduce Python or JavaScript into this,

  • you know what I could do?

  • I could probably get back, not this and this ASCII-based table, this text

  • table.

  • Maybe I could get back an actual list of rows

  • so that I can actually do something with that data.

  • And that's, indeed, where we're going with this.

  • So if I want to select someone else, I could do hmm--

  • maybe SELECT just the NAME from registrants

  • where dorm equals "Mathews."

  • If I only care about knowing who registered,

  • I could do that and whittle it down to even less data.

  • So already, in just these few commands, I

  • can express so much more functionality than you could with a CSV.

  • To do this and CSV, you would have had to write all

  • of these lines of Python code yourself.

  • What if Brian moved?

  • So Brian really didn't like the Union dorm,

  • so we're going to go ahead and UPDATE registrants

  • and SET dorm equal to-- where do want to move to?

  • BRIAN: Canaday.

  • DAVID J. MALAN: "Canaday" WHERE--

  • I could do this a few ways.

  • What's your instinct?

  • How could I identify Brian and only Brian so--

  • I don't want to move to Canaday.

  • How do we move just Brian?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: Yeah.

  • Maybe we could WHERE name equals quote unquote "Brian" and Enter.

  • I like this, but someone find fault with this if you could.

  • AUDIENCE: Two Brians.

  • DAVID J. MALAN: If there are two Brians, we're moving both of them

  • are all three of them.

  • So maybe better, honestly, would be to say, mm,

  • let's just say where the ID equals 1.

  • Now, of course, I need to know Brian's Harvard ID number or whatnot.

  • But this is going to be more precise.

  • Because the supposition here is that the leftmost column or ID

  • field, by human convention, should be unique so that it uniquely identifies

  • the room so we can have as many Brians as we want,

  • but we're not going to confuse them.

  • If I go ahead and hit Enter now, nothing seems to happen.

  • But if I select star from registrants again, and hit Enter, notice now,

  • Brian has indeed been moved to Canaday.

  • So there are so many other things.

  • Brian, you know what?

  • You're not very good at sports the team concluded.

  • So delete from registrants WHERE ID equals 1.

  • And now if we select star from registrants, we have just me left.

  • But Brian is gone as well.

  • So we have the ability to INSERT, to SELECT, to UPDATE, and DELETE,

  • and CREATE, all the while filtering.

  • And we've only just scratched the surface here of what's possible.

  • Because it turns out, we can store so much data in these databases.

  • All of our students, all of our faculty--

  • if you're a company, you can start to store

  • all of the products in your database, all of the orders,

  • all of your customers.

  • But as soon as you start going down that road, well, gee, what's a customer?

  • Customers have names and ID numbers and maybe email addresses

  • and postal addresses.

  • Those are going to get messy-- phone numbers,

  • which are kind of like integers, but not quite.

  • So there are so many questions we still need to answer.

  • But feels like it's time for some fruit and some muffins.

  • So why don't we go ahead and take a five-minute break, turn on some music.

  • If parents need to depart, that's fine.

  • And we'll see you back here in five or so minutes.

  • All right.

  • So we're back.

  • And where we left off was exactly here using

  • SQLite3, which is the version 3 of the SQLite command, which

  • is just a text-based interface to the technology

  • that we should think of as SQLite.

  • SQLite is interesting and it's lightweight in the sense

  • that it's not a server, it's not fancy software that you have to run.

  • It literally stores all of your data in a file, but that, by convention,

  • ends in .db or maybe even .sqlite.

  • But it's just a binary file, 0s and 1s.

  • It's not text that you can open with Excel or something like that.

  • So it's not a CSV.

  • So it's stored on file.

  • This means that you don't need particular experience

  • with setting up a database server.

  • You don't need memory and software to actually run on the computer.

  • You can store everything locally, but you do pay a price.

  • Because recall from our past discussions, disks are slow.

  • And if you're storing your data on the disk,

  • it's not going to be nearly as fast as storing it only in RAM.

  • And that's why these other technologies like Postgres and MySQL,

  • and Microsoft Access, and SQL Server, and Oracle exist.

  • Those are fancier products where someone literally does double-click an icon

  • or run a command that runs a program that

  • stays running in the computer's memory and gives you even better performance.

  • But for our purposes, pedagogically SQLite is handy.

  • But we're still going to ask the questions about data types

  • because SQLite does support fancier data types like those in Postgres

  • and SQL Server, MySQL, and Oracle, and those are the lower-case ones

  • we introduced a bit ago.

  • But honestly, this is going to get tedious quickly.

  • Even I rarely remember exactly the right syntax when creating tables,

  • the order in which everything has to go.

  • So I tend to use a Graphical User Interface, or GUI myself.

  • And there are lots of tools out there.

  • But we've built one that's free and open source the CS50

  • IDE that just makes it a little easier to edit your SQL tables.

  • So I'm going to go ahead and Exit out of SQLite.

  • And I'm going to go ahead over here.

  • And you'll notice that we have all of the files

  • from today including, most recently, froshims.db.

  • That is the file I created with SQLite3.

  • But if you double-click it when using CS50 IDE,

  • it's actually going to open a program that's called phpLiteAdmin.

  • It happens to be written in another language called PHP,

  • has nothing to do with databases, just the name of the product here.

  • But it's a tool that, using pretty simple HTML tables,

  • just gives us a graphical user interface over the exact same functionality.

  • And personally, I just find this easier to use.

  • And pedagogically, it's going to be better

  • because it's going to show us the available data types for our table.

  • So for instance, notice here-- there's a lot going on the screen.

  • But a lot of this is just uninteresting details.

  • But notice here, I see a table called registrants.

  • And then I can browse it.

  • I can see its structure.

  • I can execute manual SQL by typing it in.

  • I can search it, insert.

  • I can do bunches of things to it.

  • And that's why this graphical user interface is just convenient.

  • Let me go ahead and click on registrants.

  • And by default, you'll see these tabs now, Browse, Structure, SQL, and then

  • a bunch of others.

  • And notice over here.

  • You'll see the one row and the one registrant who actually remains.

  • Because when we last left off, we removed Brian forcibly from the team.

  • So suppose I want to go ahead and add more rows just

  • for the sake of discussion.

  • I can just do it manually here.

  • I can go in here and I can say, let's say the third player

  • is going to be Veronica.

  • I think she was also in Matthews so I can just type that in here.

  • And I can just go ahead and click Insert.

  • But what's nice about phpLiteAdmin is that it will not only

  • insert the rows for you, it will show you

  • the SQLite code with which you could have done it yourself.

  • So it's a nice visual reinforcement of that exact same command.

  • And you'll notice they use double quotes instead of my single quotes before.

  • They're sometimes interchangeable, but not always.

  • So it's a wonderful way of just learning how you can actually

  • do this with the right SQL code so you're not oversimplifying it

  • with the GUI.

  • But you know what?

  • Let's do this.

  • I'm going to go ahead and start over because I

  • want to make some better decisions.

  • I'm going to go ahead and, literally, right-click or Control-click

  • this, delete froshims.db.

  • And let's actually start this from scratch.

  • Now previously when I did this, I could have,

  • in my Terminal window, gone ahead and done SQLite3 and then, what was it?

  • Froshims.db and created the file.

  • For now, I'm going to actually just go ahead and touch

  • a file called that name, which is a simple command that

  • just literally creates it, but puts nothing in it,

  • just so I have an empty file.

  • And you'll see that it just popped up again

  • on the left-hand side, which is handy.

  • And now I can double-click this version of it, which has nothing in it yet.

  • And I'm back to phpLiteAdmin.

  • But notice no table in database.

  • So let's start to ask some of the harder questions

  • as to actually how to create data in a database.

  • So let me go ahead and go to this field here-- create

  • new table on database froshims.

  • I'll go ahead and call it registrants again.

  • But how many fields?

  • So let's go with ID, name, and dorm, what else?

  • Email I heard earlier.

  • Age I heard earlier.

  • AUDIENCE: Sports you want to be in.

  • DAVID J. MALAN: Sorry.

  • So sports you want-- excuse me--

  • sports you want to be in.

  • OK. six fields, six fields, let's go with that.

  • So it's, actually, you know what?

  • Seven fields.

  • I want phone numbers too this time.

  • So let me go ahead and click Go.

  • And now you'll see just a GUI way of prompting you for all the answers

  • to the same questions as before.

  • And maybe this is clearer.

  • Maybe it's not.

  • But just no alternative to the memorizing

  • exactly what the commands need to be.

  • So top to bottom, here are all of the fields I need to decide on.

  • Ironically, the fields is just a synonym for columns.

  • And yet my columns are currently laid out in rows,

  • but that's just a UI issue.

  • So let me go ahead and decide.

  • By convention, my first field is almost always ID or probably should be.

  • And we'll see why this is powerful and just a little bit.

  • The data type for that, by convention, should be integer,

  • unless you've got a lot of data like a Facebook,

  • and then big int might make more sense.

  • But notice this Dropdown actually gives us

  • a nice menu of options just as before.

  • And you'll see in gray text, the category,

  • or in fancy terms, the affinity of these various types in SQLite

  • and in lower case black words here, you'll

  • see the actual data type supported by big popular databases like Postgres

  • that you might want to use for your final projects.

  • In fact, we're introducing these with eye

  • toward your using these for final projects in the cloud, not in CS50 IDE,

  • but actually getting your own domain name

  • and putting your website, if you do a web app, out there.

  • So here, we have all of my available types.

  • And under Integer, I'm going to go ahead and literally choose Integer for my ID.

  • All right.

  • Next, go ahead and Zoom Out.

  • Let me go ahead and choose a student's name.

  • Before did we do did we decide on char or varchar?

  • AUDIENCE: varchar.

  • DAVID J. MALAN: OK, varchar, and what size?

  • AUDIENCE: 255.

  • DAVID J. MALAN: 255.

  • So the user interface here just allows me to type it in.

  • So the syntax is a little different because it's a GUI, but 255.

  • But you know what?

  • The last field was dorm.

  • That too, I think we said varchar.

  • So let me choose that.

  • And 255, though, this one's a little more debatable.

  • I'm not sure what the right number is, so in the absence of clarity,

  • I'm just going to standardize on some same value without being too wasteful.

  • But notice there are a few questions here that we haven't come to.

  • But our perfect segue earlier hinted at this.

  • It turns out, you need to make a few other decisions

  • when designing a database.

  • If you know in advance that one of your fields

  • is the primary piece of data to uniquely identify users,

  • that's what's going to be called a primary key--

  • the column or fields that, guaranteed, is going to identify users uniquely.

  • So if you've got two Brians, each of them is going to have its own ID.

  • That therefore, is your primary key, not the name field Brian.

  • So I'm going to tell the database, this is the primary key.

  • And it's going to help me keep track of that uniqueness.

  • Moreover, this is a fancy feature.

  • Before, I was manually and very arbitrarily

  • saying Brian will be number 1, I'll be number 2, Veronica will be number 3.

  • That's tedious.

  • Like, computer should be able to solve that problem for me.

  • I don't want to think about who is idea number what.

  • You can auto-increment the field.

  • So if I actually check this box, SQL for me

  • will just plus-plus, plus-plus the idea field every time

  • I insert a new name and a new dorm.

  • I don't have to even bother specifying an ID anymore.

  • Now there's another column here, not null,

  • where you can specify this column should never be null.

  • And this is important because, if you're building a website that has important

  • data that you must have from the users-- like,

  • your app won't work without the user's username or their password

  • or their email address--

  • you can say not null.

  • And your database will ensure that you can't even

  • insert a row into this database unless you give it a value for that field.

  • So it helps you protect you against yourself.

  • Because you could certainly implement that

  • logically in Python or any language.

  • But the database is a final gauntlet as well.

  • A default value doesn't really make sense here.

  • But for certain types of fields, you can say, database,

  • insert the current time or the current date for me?

  • Now, why might you want that?

  • Why date and time by default?

  • Why might that be useful?

  • AUDIENCE: When the account was created?

  • DAVID J. MALAN: When the account was created, when they bought

  • a foo, when they shipped a bar-- any number of reasons.

  • You might just want to know, what is the time right now?

  • But you don't have to write code for that.

  • The database can answer those questions for you.

  • So just so much more functionality than we got, of course, with CSVs alone.

  • So name, should it be a primary key?

  • No.

  • Otherwise, we couldn't have two Brians.

  • And generally, your primary key will be one field, though,

  • theoretically you could make joint columns if you wanted.

  • But generally, it'll be a single one.

  • Should we auto-increment Brian-- so it's, like, well--

  • Brian28, or Brian2, Brian3, and so forth?

  • No.

  • Doesn't really make sense.

  • Not null?

  • Probably.

  • I want all of the freshmen's names so that we

  • know who is signing up for sports.

  • And dorm?

  • Yeah, not null.

  • But oh, corner case--

  • can anyone think of a corner case where dorm maybe

  • should kind of sort of be null?

  • AUDIENCE: They're off-campus.

  • DAVID J. MALAN: They commute, they're off-campus--

  • it's not many students.

  • But if you have 1%, 5% of students living off-campus,

  • this is a design question now.

  • And all of us have probably visited some website

  • where you just can't fill out the form in the right way

  • because you don't fit their mold or their expectations.

  • And that's just because of a poor design decision.

  • So let's allow it to be null just in case.

  • Now what else?

  • We said a phone number was when I proposed.

  • Gosh, there's no phone number type.

  • So what do you want to go with?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: I'm sorry?

  • AUDIENCE: [INAUDIBLE] varchar.

  • DAVID J. MALAN: Varchar.

  • OK.

  • So we can pick varchar and maybe use 10 or so for 10 digits in the US,

  • at least, though, maybe, like, 12 with the dashes, or 13 with the parentheses,

  • or--

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: What's that?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: I hear murmuring.

  • Sorry.

  • AUDIENCE: A small int.

  • DAVID J. MALAN: A small int and just treated

  • as a number, maybe that could work too.

  • Another alternative?

  • Anything else?

  • AUDIENCE: [INAUDIBLE] precision.

  • DAVID J. MALAN: Precision-- so a specific number.

  • AUDIENCE: [INAUDIBLE] make sure you have the correct number.

  • DAVID J. MALAN: Good.

  • So not a bad instinct.

  • But it turns out with the numeric data type, where you specify scale

  • as it's called-- the total number of digits in precision--

  • that's generally meant for floating point values-- so

  • real numbers with decimal points.

  • Because even though you're specifying a max limit,

  • you don't require that many digits.

  • It's just a max.

  • Yeah?

  • AUDIENCE: I would think that giving it--

  • doing some sort of chars would be a bad design because then you

  • can enter nonnumerical values.

  • DAVID J. MALAN: Yeah.

  • We can kind of find fault, I think, both of these ideas, though both of them

  • are reasonable.

  • If you allow for char or varchar, I could

  • type in like foo or bar or baz and not a number.

  • So maybe we should go with int.

  • But can someone think of a counter-example to why

  • you shouldn't use integer?

  • AUDIENCE: It's got a variable length to it, doesn't it?

  • So you'd get whatever number--

  • DAVID J. MALAN: Variable length.

  • But if we actually do the math, maybe 65,

  • maybe-- there are enough bytes there.

  • We could use a big int, and that gives us a really long phone number.

  • So there's probably a reasonable max.

  • Yeah?

  • AUDIENCE: Let's say [INAUDIBLE] in between [INAUDIBLE] integer.

  • DAVID J. MALAN: Hyphens and parentheses.

  • We have to decide, do we want to support those?

  • And honestly, all of us are perhaps a little US-centric right now, most of us

  • here.

  • But when you make a local call in some zones, like, you type 0 first.

  • And some human might type 0 as their number.

  • But what's going to happen if you type 0 into an integer field?

  • AUDIENCE: You're going to ignore it.

  • DAVID J. MALAN: You're going to ignore it.

  • So now there's that corner case.

  • So dammit.

  • Like, there's no way to solve this problem it would seem.

  • So what's best?

  • We have to make a compromise and just accept

  • that we have to solve this with code.

  • AUDIENCE: Varchar.

  • DAVID J. MALAN: Varchar?

  • All right.

  • So varchars or char.

  • All right.

  • So maybe let's simplify the problem.

  • No one from outside the US can take freshman intramural sports.

  • That simplifies the world.

  • Because if we only support US phone numbers, now we can say 10 digits.

  • And if we say, you know what?

  • I don't care about the hyphens or the parentheses.

  • I can use code, JavaScript or Python, to throw away the syntax.

  • And I can just store 10 digits.

  • Maybe char 10 is sufficient--

  • 3 for the area code, then the rest of the number, the all seven digits

  • thereof.

  • But you could find fault with this too.

  • And we're really alienating that international population on campus.

  • But again, these are just non-obvious design decisions.

  • And so here we are, at the end of the semester.

  • We don't always have good answers.

  • And reasonable people will disagree.

  • But let me simplify our assumptions and just do US numbers, 10 digits,

  • and trust that I will use code in Python or some other language

  • to throw away the syntax, the punctuation and whatnot

  • of parentheses and hyphens.

  • And I'll make sure the human hasn't typed in any letters of the alphabet.

  • I can do that in code.

  • And you know we can do that even in JavaScript when a human submits a form.

  • We'll leave for the end, sports, what was it sports--

  • AUDIENCE: Sports they want to do.

  • DAVID J. MALAN: Sports they might want to do.

  • So this is a good example of, you shouldn't really have spaces

  • in your field name, so the convention would be sports_they_ really or might

  • or let's just call it sports in this case.

  • We'll come back to that.

  • I think there were two other ideas we had.

  • Phone number.

  • AUDIENCE: Email.

  • DAVID J. MALAN: Email.

  • OK.

  • Email is a good one.

  • What should that one be?

  • There's no email type, unfortunately, even though there

  • is an HTML, an input type for email.

  • AUDIENCE: Varchar.

  • DAVID J. MALAN: What's that?

  • AUDIENCE: Varchar.

  • DAVID J. MALAN: Yeah, I feel like we probably need a varchar here.

  • But here, a little non-obvious, what is the longest email address in the world?

  • Maybe it's Nick's?

  • So I don't know.

  • But let's pick a reasonable upper bound that we can maybe

  • be comfortable with as a group.

  • And let's see-- anything else here?

  • No?

  • OK.

  • And was there one more field?

  • AUDIENCE: Graduation year.

  • DAVID J. MALAN: Oh, grad-- oh, age.

  • Let's go with age.

  • So age-- finally, something simple.

  • What you want this to be?

  • AUDIENCE: Small int.

  • DAVID J. MALAN: Small int, right.

  • We will not support people older than 65,535 years old.

  • Someone want to find fault with this idea though?

  • I would argue, there's no one right answer to any of these.

  • AUDIENCE: You need month.

  • DAVID J. MALAN: Month--

  • oh, it depends.

  • Do we want month?

  • AUDIENCE: Yeah.

  • We might need [INAUDIBLE].

  • AUDIENCE: --then you need the date, the year.

  • DAVID J. MALAN: So you're assuming we want birth date.

  • I think I've called it age.

  • So maybe that's the problem.

  • Like, if it's age, small int's fine.

  • Like, you can be 0 years old or 65,000 years old.

  • We have a good range.

  • AUDIENCE: All about the age, date of birth.

  • DAVID J. MALAN: If it's age, I think we're OK.

  • But I think you allude to a good point, which is, why would we maybe want

  • to store birth date and not age?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: Yeah.

  • The damn thing's always changing, otherwise, right?

  • Like, I'm going to have to update my database tomorrow and then

  • the next day, let alone every hour or every minute just

  • because my users' ages are changing.

  • Like, that seems silly.

  • Let me, instead, fix a value--

  • so do something like birth date.

  • Birth date-- maybe specify not an int.

  • But let's actually use the date field.

  • We could store time if we really care what time they

  • were born on a certain day.

  • But here, I can say date is going to be a little better because, now I

  • know in Python, JavaScript, even C, I can do a little bit of math.

  • And if I know they were born on such and such a day and month and year,

  • well, I'll just subtract that from the current day, month, and year

  • and figure out how many days or years old they are-- so a better design

  • decision there perhaps.

  • But we do have to standardize the format.

  • We can't just allow people from the US and Europe and Asia

  • to all kind of choose their own formats.

  • SQL standardizes this-- year, year, year, year dash

  • month, month dash day, day.

  • And that's the value of having these data types again.

  • All right.

  • So how about sports-- the last one?

  • AUDIENCE: Varchar.

  • DAVID J. MALAN: Varchar, all right.

  • What's the longest number of words in the sport?

  • AUDIENCE: I didn't say might want to do, so I could get up there,

  • but 255 probably makes the most sense.

  • DAVID J. MALAN: Maybe unless they're very athletic.

  • Yeah.

  • Here too I don't know.

  • But just for the sake of opening up possibilities,

  • when you think the human might be a little expository

  • and actually write a paragraph of all the sports they're

  • involved in or whatnot or even bigger than a paragraph, text is even bigger.

  • Sports, this probably isn't compelling.

  • And I'll change it back to varchar.

  • But if someone is typing in their college essay

  • into the Common Application, or if you're

  • asking people to paste their resumes, or the like, you might want to use text.

  • Because I have no idea how many words someone's going to have.

  • Text allows you to store even more data.

  • But it stores it a little differently.

  • It tends to store it not in the column, but using pointers.

  • If you recall from a few weeks back, it uses the equivalent

  • of that to store it over there, which takes a little more time to get to.

  • So again, there's just a trade-off here.

  • So we could do varchar 255--

  • makes me a little nervous.

  • So I'm going to go with another common value.

  • 1024, it's a power of 2, but there's no one right answer here.

  • But these are the non-obvious design decisions we have to make.

  • If I didn't make any mistakes here, I'm going

  • to go ahead and click Create, and whoo--

  • table has been created.

  • You can even see now all of the data that's been created there.

  • And voila, if I go back to froshims, and I go back to the registrants table,

  • not only can I browse it-- there's nothing in there yet.

  • I can look at the structure and actually see all of those same values

  • and edit some of them like renaming.

  • But you can't completely mutilate it.

  • You might have to start over if you make too many changes.

  • All right.

  • Any questions then about this?

  • Yeah?

  • AUDIENCE: Why do you use 1024 instead of 1023?

  • DAVID J. MALAN: Oh, why do I use 1024 instead of 1023.

  • Typically, when you choose a ma-- oh, convention.

  • I can't justify this.

  • 255 was the max because I think one of the bites was reserved for some value,

  • historically.

  • But that's not really the case.

  • That bound has been lifted, and no good reason.

  • AUDIENCE: You could have used 255.

  • DAVID J. MALAN: Nowadays, yes.

  • Years ago, 255 was an actual limit.

  • And so it got adopted.

  • Now, I don't know.

  • I just pick powers of 2 often.

  • And then at my next go-to would be 2048, 4096, and so forth, just because.

  • Yeah?

  • AUDIENCE: What's the difference between varchar and char?

  • DAVID J. MALAN: Varchar--

  • What's the difference between varchar and char?

  • Char uses a fixed number of bytes no matter how many of them you are using,

  • the advantage of which is your columns, conceptually,

  • are perfectly straight on both the left edge and the right edge, which

  • means you have random access because every cell is some fixed

  • number of bytes from the rest.

  • Varchar user a ragged array, as it's called,

  • where one side, the right-hand side is shorter or longer in different cells.

  • So there's only a maximum length on each of those cells.

  • But searching it can be slower as a result

  • because you can't just jump to cell to cell.

  • You have to follow the lengths of those things.

  • That's the trade-off.

  • Yeah?

  • AUDIENCE: If you [INAUDIBLE] education, how do you add it?

  • DAVID J. MALAN: Oh, if I wanted to add an education field now and modify

  • the table--

  • if you realize too late, oh, darn, like, I need to actually add something

  • to this, in the GUI tool, we can add 1 fields to the end of the table,

  • literally.

  • So let's do that.

  • Let me go ahead and click Go.

  • I'll be prompted with a similar form, but smaller.

  • I can go ahead and type in something like education.

  • Let me propose this is varchar, maybe 255,

  • though we could have that debate too.

  • I'm going to go ahead and say add fields.

  • And now notice that the table has been altered successfully.

  • It actually, for whatever reason, it's not showing me

  • the code for that particular command.

  • But there is literally an ALTER command in SQL

  • that would allow you to change it.

  • And if I go back to the structure now, you'll

  • see that I have another column called education shown ironically

  • here as a row.

  • Yeah?

  • AUDIENCE: Does the order of the columns matter?

  • DAVID J. MALAN: Good question.

  • Does the order of the columns matter?

  • Fundamentally, no.

  • By convention, you would typically put the ID first.

  • And then I, personally, by design, put the most important fields

  • next like name feels like the right choice,

  • maybe email feels like the right choice, though, I clearly thought

  • of it a little too late this time.

  • It's not easy in SQLite to reorder things, but in other databases you can.

  • So there, it's more of a human convention.

  • Yeah?

  • AUDIENCE: Is it convention to have one single primary key,

  • or can you have multiple?

  • DAVID J. MALAN: Good question.

  • Is it a convention to have one single primary key, or can you have multiple?

  • By definition, you can only have one.

  • But that primary key can span multiple columns.

  • So we haven't seen a use case for this yet.

  • But there are scenarios in which you would want to say,

  • I want to guarantee that these two columns together are unique,

  • but not each individual one unique.

  • But we won't encounter that just yet.

  • Other questions, yeah?

  • AUDIENCE: What if you had added education

  • after you had started the database, and that was a not null field?

  • DAVID J. MALAN: Really good question.

  • What if you had added education after you already had real data in there,

  • but you specified not null, which is problematic.

  • Because what is the educational backgrounds of the previous people?

  • Typically, what the database would do is either reject it,

  • or it would just put the "empty string," quote unquote.

  • So it's not technically null, but there's nothing actually there.

  • It's just a string of length 0.

  • Really good question.

  • All right.

  • So what can we now do that's a little more powerful about this?

  • Well, let me go ahead and quickly insert some data here.

  • I'm going to keep most of it blank.

  • But you know what?

  • I'm not even going to bother with ID.

  • Brian you're back on the team.

  • Let's go ahead and insert Brian.

  • Let's go ahead now into registrants again.

  • Let's go ahead and add Veronica again.

  • So I'm just inserting a few rows manually.

  • And again, notice it's executing all of this for me

  • without me having to bother typing it out.

  • But I absolutely could.

  • In fact, just for good measure, let's do one manually.

  • If I click the SQL tab, notice that I get a default suggestion here.

  • That is the syntax with which you can select everything.

  • Or I can just type INSERT into registrants.

  • But now, if I only want to insert a name,

  • I don't have to do all of the columns.

  • I can just say go ahead and insert here, Erin, for instance,

  • semicolon, zoom out and click Go.

  • That seemed to work.

  • If I go back to browse now, Erin is in there as well.

  • But you'll see the difference.

  • The query that's being generated automatically by the GUI

  • was lazily just inserting quote unquote, the so-called empty string of length 0.

  • I, by omitting even mention of those columns,

  • was deliberately inserting null.

  • So frankly, my database is getting a little messy here.

  • So you generally don't use phpLiteAdmin or a GUI to insert data.

  • You might use it to conveniently create your tables

  • and get your application ready.

  • But then you're going to write code ultimately.

  • And that's the direction we're going.

  • And I'm going to go ahead and insert one more person.

  • Oh, I forgot I'm not on the team at all because we started over.

  • So let me put myself back on the team, David.

  • And let me go ahead and click INSERT, go back to registrants,

  • and now you'll see there are four of us.

  • My ID changed because they've been inserted in different orders.

  • But notice all of the auto incrementing has been happening magically for me.

  • And that's useful because I don't have to even think about it.

  • And who cares what my ID is.

  • I just need to have, in many cases, in a database, a unique ID.

  • So now let's actually write a little bit of code, right?

  • Thus far we haven't done anything useful.

  • We've shown you this black and white window in which you

  • can select in certain update data.

  • But that doesn't really solve any problems we know about yet.

  • We have this graphical web-based interface

  • via which you can create tables and add data, but who cares?

  • We're trying to solve actual problems.

  • And the problems of late have been to build

  • software that would solve any number of human problems

  • like serving users and showing the results

  • or finding similarities in documents.

  • So suppose the problem at hand now is to actually build

  • something like the froshims website and let students register and then see

  • who is registered.

  • Well, back in my day, I fairly lazily, for lack of technical know-how,

  • just emailed the registrations to the proctor or the RA who was

  • managing the intramural sports program.

  • But I-- they later started putting it in CSV files.

  • Suppose now, version 3, 20 years later, I want to store in an actual database.

  • How can I actually do that and then see the results?

  • Well, let me go into the IDE again and open up,

  • for instance, a New File that I'll go ahead and call lecture.py.

  • And suppose I just want to write a simple Python program via which

  • to select data from a database.

  • So it turns out I can do a few things here.

  • First of all, let me go ahead and do, let's say, from CS50,

  • I previously have done things like import get_string and get_int

  • and so forth.

  • It turns out that the CS50 library for Python also supports SQL.

  • And it's going to give us a function called

  • EXECUTE that will let you execute any SQL command, but in Python code.

  • So instead of pulling up SQLite3 via my own hands

  • or going to a graphical user interface phpLiteAdmin,

  • I can write code that talks directly to froshims.db,

  • and eliminate all of those tools altogether, and just now write code.

  • So how do I do this?

  • I'm going to declare a variable called db for Database.

  • So I could call it anything I want.

  • And I'm going to go ahead and call this SQL function.

  • And I'm going to pass in a somewhat funky looking string as an argument,

  • but it's a standard convention, to say what

  • database technology do you want to use?

  • Then you do colon, slash, slash, slash-- so it's three slashes, not

  • the usual two in a URL.

  • And I'm going to specify froshims.db.

  • This now will give me a Python variable called

  • database that is kind of like a portal, if you will, into that database

  • file that I can send SELECTs, and INSERTs, and DELETEs, and UPDATEs to.

  • How do I do this?

  • Well, if at the end of the day, I want to execute

  • the equivalent of SELECT star from registrants, how do I do that?

  • Well, I'm just in a text editor, right?

  • This is CS50 IDE.

  • I'm just typing text.

  • Moreover, I'm typing text in a Python file, and this is not Python.

  • And indeed, the IDE has this little red x saying, mm-mm, can't do this.

  • But I could pass SQL code as an input to a Python function

  • and let that function talk to the database.

  • And indeed, that's what we're going to get here from CS50's library.

  • I'm going to go ahead and do this.

  • You know what?

  • Access the database and EXECUTE the following SQL code,

  • quote unquote, "that" close parentheses.

  • Now, what is select return by convention?

  • What should it return?

  • Well, in SQLite3, we just saw a pretty text-based table

  • with lines and slashes that looked like a table, but was just text.

  • phpLiteAdmin, we actually saw HTML tables when I browsed the database.

  • And I proposed verbally, a bit ago that, you know what?

  • If I were to get back all of this data in code, what data type

  • would I like it to me as?

  • Rows.

  • I want rows from a table.

  • Show me all the students who've registered.

  • What data structure in Python seems apt?

  • AUDIENCE: List.

  • DAVID J. MALAN: Yeah, just a list, right?

  • A list that's ordered from first row to last row.

  • So we'll call that a list or an array, back in the day of C. So you know what?

  • I'm going to assume that's correct.

  • And if I read the documentation, I would see that it's correct.

  • CS50's EXECUTE function, if you select, returns to you a list of rows.

  • It might have 0 rows if there are no matches.

  • But it might have 1,000 rows if there are lots of matches.

  • I'm going to store those results, wherever they are, in my rows array.

  • Now, suppose I want to print out who has registered in my database

  • from whatever froshims website exists.

  • I'm assuming students have registered on the web.

  • Now I'm just the proctor or the RA who's actually now

  • trying to manipulate the data and do something with it.

  • So what can I do?

  • Well, for row in rows, what do I want to do?

  • Let me go ahead and just print out that so-and-so registered.

  • So so-and-so registered.

  • Well, how do I plug in so-and-so?

  • Well, there are a few ways to do this.

  • And let's see.

  • First of all, I could use my placeholder syntax for print.

  • And then, I want to print out the row.

  • But what do I want from that row?

  • What columns are in any row in this database?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: ID and name and dorm and phone and sports.

  • Well, it turns out, those are going to be handed to you as Python dictionaries

  • or dict structures.

  • So I can just say row quote unquote, 'name' here.

  • And I'll use single quotes just to make more clear what's going on here.

  • And then I need to make one fix.

  • How do I--

  • AUDIENCE: F.

  • DAVID J. MALAN: --F for Format string.

  • So it looks a little cryptic.

  • But this is just Python stuff now.

  • The only thing that's new is SQL.

  • But if we stipulate that SQL, when using this execute function

  • is just going to hand you all a list of rows, each of which

  • is a dictionary so that you can get at this column or this column--

  • ID, or name, or dorm--

  • this would seem to be now a nice convergence of this week--

  • now, with the past couple of weeks.

  • So let me go ahead and save this.

  • Let me go ahead and View my Console, so I have a Terminal window.

  • And let me go ahead and run Python of lecture.py.

  • And in just a moment, if I cross my fingers,

  • I should hopefully see who has registered.

  • Amazing.

  • I've seen who's registered.

  • Now there's one line of output that I didn't expect, which is just this one.

  • This is the library just being pedagogically helpful.

  • It's showing me every command that I sent to the database.

  • But you'll see that so-and-so has registered.

  • So this is kind of interesting.

  • It's kind of a stupid program, right?

  • Because most proctors aren't going to be hacking

  • froshims by using a terminal window and running Python scripts.

  • They're probably going to want to do this by a web page

  • and actually see who is registered.

  • But if we have the ability in Python code to do this, like,

  • iteration, what could I do instead of just printing to the screen?

  • What could I print out per last week and per the past problems set?

  • I could print out HTML, right?

  • Like, each of the students who register, kind of

  • feels like an opportunity for an unordered list

  • or an ordered list or a table or whatever.

  • You can now generate HTML.

  • So let me do this.

  • Let me actually go into an example I've made in advance.

  • What if I went ahead and opened up layout.html.

  • Here is a simple layout for a web application using Flask.

  • For those unfamiliar, this is mostly HTML

  • plus a technology called Jinja, which is a web-based technology for generating

  • websites dynamically.

  • The body of this page is clearly what's of interest.

  • And you know what?

  • I bet I could do some logic right in there.

  • So let me go ahead and do this.

  • Let me go ahead and Create, let's say, a New File.

  • Let's call this application.py.

  • I'm going to go ahead and, just for time's sake,

  • do a little bit of copy-paste to save myself some keystrokes.

  • So here's a very simple web app.

  • And this is going to be my to-do.

  • So if I go in here to templates, let me open up index.html--

  • and let me go head into here.

  • So long story short--

  • here's where we're going with this.

  • What if I instead generate an unordered list using code from last week,

  • but I use my for loop here inside of my web app

  • instead of actually just with a simple lecture.py file.

  • Well, recall that I could do something like this.

  • I can have a Jinja loop.

  • So I could say something like for row in rows.

  • And then, down here, I can preemptively say something

  • like andfor, which is our weird syntax from last week.

  • And then, in here, I can just do a list item.

  • And then, if I want to show who registered, what do I type here?

  • Something in between these curly braces if each row represents a registrant?

  • AUDIENCE: Row.

  • DAVID J. MALAN: Row name registered.

  • I can just do something like this.

  • So same idea, I'm just wrapping it with a little bit of HTML.

  • Now let me go to my application.py file because I'm

  • going to have to fill in some blanks.

  • And let me see, how can I do this?

  • Well, ultimately, I want to return the result of rendering

  • a template called index.html.

  • For families unfamiliar, this is just a line of code

  • that says go show that file to the user.

  • But I don't want to just show them the file as-is.

  • But let's at least get this set up.

  • I'm worried that it might not work yet because I need to get the actual data.

  • So how can I get all of the rows for my registrants?

  • Well, I can do rows gets db.execute.

  • And I can go ahead and select star from registrants and store that in there.

  • This file is called froshims.db that I created earlier.

  • And everything else is just Flask stuff from last week.

  • Nothing else is new.

  • The only thing that's new is this line here,

  • this line here, and now this line here where

  • I'm using SQL inside of a Python call by passing

  • it is an argument to a function called EXECUTE.

  • How do I pass the rows to index.html?

  • AUDIENCE: [INAUDIBLE]

  • DAVID J. MALAN: Yeah, like rows equals rows is the convention we've adopted.

  • You call it anything you want, x equals y,

  • but this is a little more straightforward.

  • So this is saying, hey, database, get me all of the rows from my registrants,

  • and then render the template index.html, and pass in these rows.

  • And now, if I hold my breath and run flask run, no syntax errors.

  • If I go ahead and visit this here and open--

  • dammit-- the tab, I see an internal server error.

  • So teachable moment, families.

  • Let's go back into that browser window here and see what happened.

  • OK.

  • Template syntax error-- so pretty stupid mistake.

  • It looks like I expected a square bracket instead of a curly brace.

  • That's fixable.

  • Let me go into index.html.

  • And oh, I didn't finish my thought.

  • So that's some of the frustrations of programming for those

  • who are seeing this for the first time.

  • Let me save that.

  • Let me go back to the browser here, and we'll just reload.

  • And oh my god, voila, now I have a web page

  • via which you can see who has registered.

  • But you know what?

  • We can make this more powerful.

  • Recall that we've been playing with HTTP for some time.

  • And if this is the URL I'm accessing, recall

  • that we played around with reimplementing search functionality.

  • Well, what if I want to support search such that I can just visit q

  • equals and then search for people named, say, Brian

  • and see how many Brians are registered.

  • Could we add support for something like this?

  • Well, maybe.

  • Let me go back into the IDE, into application.py.

  • And let me go ahead and say something like this.

  • q equals request.args get q to see if anything is actually there.

  • And then let me go ahead and do this.

  • SELECT star FROM registrants WHERE--

  • let me see-- q where what?

  • NAME equals q.

  • But I need a placeholder.

  • So maybe I should do this.

  • And as soon as I do this, I need a what?

  • F for a format string.

  • So I could just create, on the fly, a SQL command

  • that plugs in the value of q between those curly

  • braces to express the logic of select all

  • of the registrants whose names equal Brian or Veronica

  • or whoever's name I typed in.

  • Let me go back to the browser here.

  • Let me go over and do something like this now.

  • Question mark q equals Brian-- cross my fingers as before.

  • Dammit.

  • OK.

  • And what did I do wrong here?

  • What did I do wrong here?

  • This is subtle.

  • And we're seeing it for the first time.

  • It thinks there's a column called Brian.

  • But why would it think that?

  • Well, what I've effectively done is sent in this.

  • Brian is not a keyword in SQL.

  • And because it's an actual string that I'm comparing against,

  • what I really need to be doing is this.

  • Otherwise, SQLite is going to think it's like the name of a column or something

  • I pre-created so we have to fix this.

  • But that's OK.

  • I can put the quotes there.

  • But I should probably put the q there in quotes.

  • Let's save this, go back to the browser, reload.

  • And there we go.

  • Now we have functionality for Brian.

  • And so with this basic building block, what have we done?

  • Well, in SQL, we have several commands at our disposal--

  • creating a table, which frankly gets tedious by typing it out.

  • I myself tend to use and recommend phpLiteAdmin just to create your table

  • and get it going.

  • But then you can certainly manually, with SQLite3 or phpLiteAdmin INSERT,

  • or UPDATE, or DELETE, or SELECT information

  • once it's actually in the database.

  • And that's pretty powerful.

  • But once you do that, you can now use that same new syntax, that new language

  • SQL, passing it in as an input with a "string" to our EXECUTE function,

  • and now start pulling any data you want from your database.

  • Last week, with CSV files, if you wanted to do this,

  • you'd have to open the CSV file, use a for loop to iterate over it,

  • look over every column and row for your data, then pass it in.

  • And that's fine.

  • That's correct.

  • That's not bad.

  • But it's tedious.

  • And you're reinventing the wheel again and again.

  • And there's no filtration built in as there is to SQL itself.

  • So you now have a more sophisticated tool

  • in your toolkit so to speak with which to solve that same kind of problem.

  • Any questions then on this technique?

  • All right.

  • Well, let's look at a bigger database and see where we can go with this?

  • So if you go on the course's website, you'll

  • see a larger database that's actually available in multiple formats, SQLite,

  • which we'll see in a moment, but also Google Spreadsheets.

  • Because frankly, it's a lot more pleasant to look

  • at your rows and columns in a GUI than it is, necessarily,

  • with the file itself.

  • So this happens to be a free and open source sample database.

  • Like, some guy, years ago, took his actual iTunes database--

  • all the music he'd ever bought, he wrote a program

  • to like analyze Apple's file format in iTunes

  • and extract all of the data that seemed to be stored about him,

  • I think was the story, and just made it publicly available as a sample

  • database for students and teachers to just use to manipulate data.

  • But what's interesting is that this database

  • demonstrates some other principles that we really haven't touched on.

  • For instance, if I were to store, again and again,

  • all of these students who are registering for froshims,

  • what do you start to see in certain fields?

  • Well, I was a little lazy, and I didn't bother typing in everyone's dorm.

  • But suppose that hundreds of students have registered for froshims.

  • A lot of them are going to be from Matthews, some from Pennypacker,

  • some from Candaday, some from Weld, and bunches of other buildings on campus.

  • It starts to get a little ridiculous when

  • you see Matthews, Matthews, Matthews, Matthews,

  • Matthews-- like, 100 or more times.

  • If there are 1,600 freshmen, there are a lot of kids in Matthews.

  • That's a lot of bytes to store M-A-T-T-H-E-W--

  • I don't know.

  • It's not important.

  • Doesn't matter how it's spelled.

  • That's a lot of bytes to actually store in your database again and again

  • and again.

  • It feels like there should be an opportunity

  • to factor out the commonalities.

  • And what humans do with databases is, once they recognize a recurring

  • pattern of data, same darn strings again and again and again, you know what?

  • Rather than use-- now it matters--

  • M-A-T-T-H-E-W-S-- which is 8 bytes.

  • Or P-E-N-N-Y-P-A-C-K-E-R, which is 11, then we have a lot of bytes being used

  • again and again and again to store all of these dorms.

  • You know what?

  • What's better than 11 bytes or 8 bytes?

  • Let's just use an int, or let's even use a small int--

  • 2 bytes or 4 bytes to represent dorms.

  • So instead of storing Matthews, let's just store the number 10.

  • And instead of Penny Packer, lets just store the number 11, thereby,

  • using some bytes, but fewer and, therefore,

  • saving bytes in the long run.

  • And so with this database demonstrates is exactly that principle.

  • Certainly, when it comes to music, where artists have multiple albums

  • and artists have multiple songs, it's probably

  • a little silly in a musical database to store the name of the album

  • again and again and again and again for all 10 or 12

  • or 20 tracks or songs on that particular album.

  • So what this person did was this.

  • Notice here, we have a whole bunch of sheets.

  • Or in database-speak, these would be tables.

  • And notice that these tables have columns.

  • And notice that these columns are album ID,

  • in the album table, album ID and title.

  • But notice what he did very cleverly with this field, artist ID.

  • Artists or singers have lots of songs to their name, eventually.

  • And so he's assigned each of them unique value,

  • or Apple did, in iTunes underneath the hood.

  • So how do I know what this artist's name is?

  • How would you figure this out?

  • It's not that interesting to us humans do know, ooh, artist ID number 2.

  • This is just-- what's that?

  • AUDIENCE: You need another table with artists.

  • DAVID J. MALAN: Yeah.

  • We need another table with artists, which is right over here.

  • So let me go ahead and look there.

  • So if I want to see-- let's see, "Let there be rock," artist number 1.

  • Let's go to the artists table.

  • And turns out, AC/DC, the band is who created that.

  • Now we've added a step here, which maybe is costing us a little bit of time.

  • But it's going to save a space in the long run if I'm not storing long

  • artist's names-- although, AC/DC isn't terribly long--

  • again and again and again.

  • Now, which is better?

  • Well, it's a trade-off.

  • Are you more comfortable wasting space and storing everything together?

  • Or do you prefer to save space and just spend a little more time

  • joining the data back together?

  • But it's going to be really annoying if, now,

  • if I want to make a website that shows me the names of the songs

  • that I have in a database and the artists for them,

  • let alone the albums, and more of that, the titles of the tracks, and so forth.

  • It feels like that's three queries, right?

  • Like SELECT the album, SELECT the artist, SELECT the titles--

  • but no.

  • With SQL, you can collapse that altogether.

  • Because notice, in this table here, artist,

  • there is a column called Artist ID that's numbers.

  • And notice, if you kind of picture this, it's

  • like finger tips here-- let's propose metaphorically--

  • represent the artist ID.

  • If I go into album now, notice that we have album ID and title,

  • but we also have artist ID.

  • And so if you imagine these two tables sharing this common column, what if we

  • kind of stitch them together like this, lining up one

  • on the left, the other on the right, thereby reconstructing

  • all of the information and duplicating it as

  • needed so that I get back just the album and the title and the artist.

  • Well, how can express that?

  • Well, let me go ahead into CS50 IDE where I have a copy of this file.

  • Let me close all of my tabs from earlier go into this file called lecture.db.

  • And in lecture.db, in phpLiteAdmin, we'll see all of those same tables.

  • And I literally just imported it into a SQLite.

  • You'll see all of these same tables.

  • We can browse album just as before.

  • And we just see a different format for the same data.

  • It's the same data from the Google Spreadsheet,

  • which is just more user-friendly.

  • And let me go ahead and do this.

  • I could, of course, SELECT star from album

  • Where our artist ID equals 1 to get back all of AC/DC's albums.

  • And indeed, here, I have two.

  • They have For those about to rock, We salute you, and Let there be rock.

  • They have two.

  • But notice, the rows I got back contain only what information?

  • Album ID title, and artist ID.

  • I just know, as a human, that oh, these are AC/DC's albums.

  • But what if I want to know, well, OK, I see that artist ID is 1.

  • So all right, well, let me open another tab here.

  • And now let me SELECT star from artist WHERE artist ID equals 1.

  • And so if I want to learn something about that artist-- let me go ahead

  • and Zoom Out, click Go, and OK-- now I get AC/DC.

  • Well, this is great.

  • Now I have to results, two sets of rows.

  • This is stupid.

  • Now I'm just creating work for myself by having two return values.

  • I could call db EXECUTE twice.

  • But there's a better way.

  • It turns out, SQL allows you to join tables just using SQL itself.

  • So I'm going to go ahead and do this.

  • I'm going to go ahead and SELECT star FROM album,

  • but also FROM artist WHERE Album.Artistid--

  • let me scroll to the right--

  • equals Artist.Artistid.

  • So notice I'm saying select everything from two tables,

  • but only do so where the album tables, artist ID

  • column has the same value as the artist tables artist ID column.

  • That's kind of the stitching, metaphorically, of my fingers

  • together, looking for that common column.

  • If I go ahead and click Go, wow, look at what I've just constructed.

  • It's a lot of information, but I have album ID and title,

  • I have artists ID still, but I have the name of that artist altogether.

  • So if you now let your mind wander back to the Python code,

  • oh, I could now get a whole bunch of rows containing

  • everything I care about all at once.

  • I don't need two select queries.

  • I can join these tables in this way.

  • And I use join very deliberately.

  • It turns out that there's another way to express this same thing.

  • Instead of using that comma syntax I did, you might see as well this,

  • Select star From Artist JOIN Album ON Artist.Artistid equals--

  • let me scroll over--

  • Album.Artistid.

  • This is going to have the exact same effect,

  • but you might just find that it reads a little more intuitively to you.

  • Select everything from the result of joining these two tables.

  • How do you want to join them?

  • Well, join them on this equaling that--

  • just another way of expressing the same idea.

  • And if I click Go, I get back the same information.

  • So ultimately, with JOINs do we have the ability to reassemble data.

  • So on the one hand, it's just good practice to normalize your database.

  • Identify columns that have lots and lots and lots of redundancy, and only

  • store that information once.

  • For instance, CS50 Finance, if you're supporting

  • many different users, every time Malan or Brian or Veronica buys a stock,

  • feels like it would be a little silly to store Malan

  • or Brian or Veronica along with Netflix, the symbol, and the number of shares

  • one of us bought.

  • Because Malan, Malan, Malan, Malan is going

  • to appear all throughout the database.

  • And what if I change my username or my name or someone gets married

  • and, therefore, it changes?

  • Like, why do you create that messiness for yourself?

  • Instead, give Brian and Veronica and me and everyone else a unique ID.

  • And when they buy something, just store their user ID or customer ID

  • or however you want to think about it, just like with album ID and artist ID.

  • And so normalizing a database is all about finding those commonalities

  • and moving the data into its own table.

  • And if you care about rejoining it, just use

  • SQL to reconstruct that view of the data, so to speak.

  • So what else can we do here as well?

  • It turns out that there is in SQL, not just primary keys,

  • but there are unique constraints in some databases where you can specify,

  • this isn't my primary key, but I want it to be unique.

  • You can specify that something should be indexed.

  • So it turns out that, if you just know there's a field in your database

  • that you want to be able to search on very efficiently,

  • you can index it in advance.

  • And you'll see or be able to do this if you'd like for final projects

  • or even for the next problem set if you'd like.

  • But what this enables are queries like this.

  • If I want to go ahead and search for, for instance--

  • what would be a good example?

  • Rock.

  • I'm interested in rock.

  • So if I want to go into My SQL tab here.

  • I could say something like this.

  • SELECT star FROM Album WHERE Name not equals,

  • but where name is LIKE and then I'm going to say 'Rock.'

  • But if I want any number of characters to come before that word,

  • I can use a percent sign.

  • And if any number of characters after, I can use a percent sign.

  • These are like wildcards.

  • In most languages, you would use star.

  • In SQL, you use percent signs.

  • But it means the same thing.

  • And if I go ahead and say go, now I get back--

  • oh, I get the got wrong lecture, album, oh, title I think is what I wanted.

  • Let me try that again, sorry--

  • WHERE Title LIKE 'Rock'--

  • let me go ahead and click Go.

  • And voila, here are all of the albums in the database that

  • have the word rock in them.

  • Now, as an aside, this table has a lot of more albums in it.

  • And frankly, it's small enough though.

  • It has hundreds of rows, maybe a few thousand rows.

  • None of us humans are really going to notice how slow linear search is.

  • But if you start having thousands of rows, tens of thousands

  • of rows, millions of rows, not having an index

  • means that searching for something like rock is going to start at the top

  • and search every darn field all the way to the bottom, big O of n.

  • If you instead tell the database, I know I'm

  • going to be searching on this column a lot, please index it for me,

  • here comes the secret sauce.

  • SQLite, Oracle, Microsoft Access, and so forth, they

  • will, using their own intellectual property,

  • build up some fancy data structures-- trees, or hash tables,

  • or whatever in memory, store the data for you invisibly in that format

  • so that, when you do ask for a question like, show me all the albums like rock,

  • they can answer you in much faster time than linear.

  • And that too is what you get with SQL that you don't get with CSVs.

  • CSVs are, by nature, only linear.

  • So we can do better.

  • But you, the programmer, have to help the database

  • and actually give it those hints, not just the types,

  • but also hints like this.

  • And as an aside, there's also the notion of foreign keys

  • where, if you really want to lock things down, you can specify that,

  • if you ever see in album ID in another table,

  • if it's a primary key in the album table,

  • by definition, in the other table, it's going to be called a foreign key.

  • Because it doesn't really belong there, but it's

  • referencing a column elsewhere.

  • So there's a lot more technology and vocabulary.

  • And you're welcome to dive in deeper.

  • And odds are, many of you will for final projects,

  • by nature of wanting certain features, among them, even

  • the ones we've seen like auto incrementing and not null.

  • As an aside too, SQL even has functions.

  • And for data scientists and statisticians

  • it's super useful to be able to just do math and summaries of data right

  • within SQL without ever writing Python code or R or anything else.

  • Built into a SQLite and other databases are

  • functions like this for average, counting things, getting

  • the min, max, sum, and so forth--

  • all of that you get for free with a lot of databases.

  • All it takes in the context of Python is a line like this.

  • But, but, but, but, but there are some problems.

  • And let's end by taking a look at two fundamental problems and threats that

  • are too often underappreciated.

  • And in fact, we have to fix a very serious vulnerability that I introduced

  • into my very own code earlier.

  • But first, the so-called race condition.

  • In survey-- or rather, let's see--

  • suppose that we think back at the very start of the semester, most of you

  • signed up for a GitHub account for the very first time.

  • And you went to github.com/signup.

  • For those unfamiliar, GitHub is a website

  • where you can save and store programming code that you've written

  • and want to collaborate with others on.

  • And you chose a username.

  • And let me go ahead and try choosing a username like, say, jharvard

  • for John Harvard.

  • Notice that the website immediately said the user name is taken.

  • All right, that's useful.

  • And you can probably guess how this is done-- maybe a little JavaScript,

  • using AJAX, talking to the server, getting the response,

  • changing the HTML or the CSS or whatever.

  • Might take some time to wire all that together.

  • But that's probably what's going on.

  • So let me try a really long random username that is not taken.

  • Hey, it's available.

  • But probably is not a good thing that I'm streaming this on the internet.

  • Because if I wait long enough, I bet someone could, for playful reasons,

  • just sign up for this, let alone anyone in this room.

  • But you've just told me it's available.

  • So good.

  • I'm really excited.

  • I've got my username.

  • Let me go ahead and type in my email address,

  • malan@harvard.edu, my password, 12345-- take a few moments there.

  • Verify my account and so forth.

  • And I click Submit.

  • Suppose that I'm told, momentarily, sorry, that username has been taken.

  • Could that happen?

  • Yeah, if any of you were trying to mess with me right now,

  • you would have signed up for that username and beaten me to the punch

  • so that when I hit Join, I get an error.

  • That's the definition of a race condition where two people or two users

  • or two computers or two threads--

  • if we really roll back to our discussion of threads in Scratch--

  • are trying to do the same thing at roughly the same time.

  • And if those two things, threads or humans,

  • check the state of a variable, which is a fancy way of saying

  • is the username available, they both get back answers.

  • But then some number of split seconds later,

  • then they make a decision based on that information, there is a window of time,

  • either split seconds or even seconds or minutes,

  • where the state of that variable could, of course, change.

  • So if you two, literally, right now on your laptop,

  • typed that very long username, all of us would probably be told, green light,

  • it's available.

  • But only one of us is actually going to get it.

  • And that's because of a race condition.

  • Literally, all of us might be racing to sign up for that value.

  • And it's when state can change in between things happening.

  • This is a bad thing because it makes your data

  • vulnerable to changes by someone you don't necessarily intend.

  • Or if the database isn't smart, you might

  • be able to do especially bad things.

  • ATMs are a canonical example of this.

  • If you had a malicious adversary trying to log into two bank accounts at once

  • or two physical machines at once, either with two cards or two accounts and two

  • laptops, you could imagine both of them trying to deduct, like,

  • $100 from the same account instantly.

  • Because imagine a poorly-implemented bank website.

  • It checks the account balance of the user logged in.

  • Do you have $100?

  • If the answer is yes, maybe both websites are going to say yes,

  • you may deduct $100.

  • You hit enter and voila, you deduct $100.

  • The user gets it somehow because it's transferred to some other account.

  • But the bank thinks it only did that once, deducts $100,

  • but you've just walked away with $200 because you made a decision based

  • on the same answer in two different threads

  • or two different programs or two different computers.

  • So long story short, this can happen even in the real world.

  • An example I was taught by my advisor years ago was this.

  • Suppose you and your roommates have a little dorm fridge.

  • And you're in the habit, of course, of drinking a lot of milk.

  • And so the fridge has run out of milk.

  • And you come home, the first roommate after classes.

  • And you realize, oh, I really need a drink of milk.

  • And so you check the fridge.

  • There's nothing there.

  • So you close the fridge, and you walk into the square, go to CVS,

  • and get in line to buy some milk.

  • Meanwhile, your roommate comes home.

  • Also, they really need a drink of milk.

  • And so they check the state of the variable.

  • Argh, no milk.

  • Close the fridge, and then walk to like Tommy's Convenience or some other place

  • nearby and get in line for some milk.

  • You of course, then both get home eventually.

  • And what happens now?

  • Dammit, now you have twice as much milk.

  • And milk goes bad quickly.

  • So now this is a problem, a very bad problem.

  • You have twice as much milk as you could possibly drink.

  • But what's the origin of that problem fundamentally?

  • AUDIENCE: You're out of something.

  • DAVID J. MALAN: You're out of something, but--

  • AUDIENCE: You need it.

  • DAVID J. MALAN: --you need it.

  • But why did I end up with two?

  • AUDIENCE: There's no flag.

  • DAVID J. MALAN: There's no flag, right?

  • There's no indication.

  • There's no sharing of state.

  • You both inspected the value of the variable,

  • made a decision independently on it.

  • But the state of that variable changed on one of you.

  • Because when one of you came home, the later person, damn, like,

  • the milk has already been refilled.

  • So how do you solve this?

  • In the real world, how could you avoid this problem?

  • You just, one, never do errands for your roommate.

  • AUDIENCE: The magnet you put on the refrigerator says get this.

  • DAVID J. MALAN: Mag-- yes.

  • A shopping list, right-- gone for milk--

  • Arrested Development.

  • Always leave a note, right?

  • You could convey that information.

  • You could more dramatically lock the refrigerator, right?

  • Padlock the thing, and so your roommate can't

  • inspect the state of the refrigerator while you are gone, therefore,

  • not making us vulnerable to this.

  • And I use the word lock deliberately because,

  • in databases, that's how they solve this.

  • There is a feature in databases called locks.

  • Or fancier versions of this are called transactions,

  • whereby, you can guarantee something called atomicity,

  • where atomicity means you can do multiple things back to back to back

  • without getting interrupted.

  • So in the case of a bank, it is possible, with SQL, using slightly

  • fancier syntax that we won't dive into today to solve this problem by saying,

  • you know what?

  • Begin the following transaction.

  • Check the state of the bank account, deduct this amount of money,

  • and now commit the results.

  • And while I'm doing that, lock everyone else out.

  • Don't let any other customer or any other user

  • do exactly that information that touches the same data until I am done.

  • Long story short-- you pay a price, perhaps.

  • You're literally preventing your roommate from accessing the fridge,

  • and that's annoying.

  • Or you're preventing other customers from doing transactions.

  • So hopefully the computer is fast at this, and your fast at shopping.

  • But you've at least ensured that you have atomicity.

  • No operation can get inserted into your sequence of operations

  • as by your roommate or some other computer or thread.

  • So that's a problem with databases that we're only going to skirt over.

  • And GitHub might solve this, how?

  • Well, by just not caring, potentially.

  • I don't know what's going to happen if multiple of us try.

  • I'm guessing they will just give n minus 1 of us an error message saying, sorry,

  • that username is no longer available.

  • Think about this.

  • If you've ever bought airline tickets, this

  • is a solved problem in that industry.

  • That would be really annoying.

  • If you just spent an hour of stressful price-hunting

  • for a good airplane ticket, you start checking out

  • after adding it to your shopping cart.

  • And five minutes later, after your name and email address and credit card

  • number, the ticket is gone.

  • So what do airlines do?

  • They often give you a five-minute window.

  • And some of the fancier websites show you the clock saying,

  • we guarantee this for the next five minutes.

  • Hotels might do this too where they locked the refrigerator for you

  • by somehow altering the database to say, mm-mm.

  • No one else can buy this ticket or this room for the next five minutes,

  • much like the note or the padlock.

  • So those kinds of things are all around us.

  • But let's look at one final example that's the worst threat of all is this.

  • Previously, I allowed myself to search by name.

  • So q equals Brian or q equals David or Veronica or the like.

  • And what did I do with that information?

  • Well, if we go back into the IDE and actually look

  • at that file in application.py, I simply formatted it using an F string

  • inside of this SQL string.

  • But what if my users were a little bit malicious?

  • And suppose that someone doesn't want to just search for Brian.

  • But you know what?

  • Suppose they do something like, my query is DELETE FROM registrants WHERE--

  • sorry Brian-- NAME equals Brian--

  • something like this.

  • Now, this is not valid at the moment, because this string,

  • while I'm certainly allowed to type it in,

  • is going to get plugged into my code, but in the wrong place logically.

  • Like, I'm going to look for someone's name called "DELETE FROM registrants

  • WHERE name equals Brian," which is just nonsensical.

  • It will return 0 results.

  • But what if I do something like this where I say,

  • Brian or DELETE from registrants where I finish

  • the thought that the programmer had and then start my own new thought.

  • Or another way of doing this is to use special syntax semicolon, something

  • like this.

  • Long story short, I could contrive a human malicious input that

  • finishes the programmer's thought and returns zero rows, but by the way,

  • also sneaks one additional rogue query into the database.

  • This is what's known as a SQL injection attack.

  • And if you naively and very, very, very badly and incorrectly write code like I

  • did-- don't ever do this--

  • you will be vulnerable to exactly this attack

  • because you are blindly plugging in the user's input to a string

  • that you are then passing to a database.

  • This is a fundamental flaw in lots of applications, lots of languages

  • where you have to distrust your users.

  • It doesn't matter if it's for just students on campus

  • or it's just for you and your friends.

  • Never ever, ever trust users' input because either someone's

  • going to mistype something and something is going to go awry,

  • or you're going to have a bad apple trying

  • to hack into your website or your application

  • by trying these kinds of commands.

  • And you have to always write code defensively.

  • So how to do this?

  • There are a bunch of ways.

  • But it turns out that, what's dangerous about something

  • like I just typed in is that it's the semicolon, for instance,

  • and that's the quote marks over "elsewhere."

  • So the safest thing to do is, no matter what the user types in, escape things.

  • You can use special syntax.

  • We saw this in C-- generally, putting a backslash in front of something means,

  • don't let it have its default behavior.

  • Instead, treat it specially.

  • So you could use special code in Python that

  • just says remove any bad characters, or replace things.

  • Frankly, you've probably been to a website where you've been told,

  • sorry, you can't use that character in your password.

  • Or sorry, you can't use that in your username.

  • That's just dumb.

  • Like, that is the lazy approach to this.

  • There is no reason to prevent users from typing

  • any characters into their keyboard for their password and maybe even

  • their username.

  • That's kind of a lazy way of defending against this by saying,

  • mm-mm, I don't trust any percent sign, any semicolons,

  • any dashes, any apostrophes.

  • Rather, just escape things.

  • But it's silly for all of us in this room

  • to write our own code for scaping users' input or scrubbing it, as it's called,

  • or sanitizing it, as it's called-- same things.

  • Why don't we just use a library?

  • Now, there are many libraries out there.

  • The one that we're using at the moment is CS50's.

  • And the EXECUTE function does this for us.

  • Instead of using F strings, which you should not use like this.

  • You should instead do this.

  • If you want to plug in a placeholder value to a SQL query,

  • you literally use a standard convention, that we have adopted too,

  • where you just put in a variable's name, but with a colon in front of it.

  • And it can be anything.

  • It can be q.

  • It can be x.

  • It doesn't matter.

  • But you want to just plug in some value there.

  • So I'm going to call it name, by convention.

  • Then you close your quote and finish your thought.

  • And then you go ahead and pass in the actual value, name equals q.

  • And now you have constructed, dynamically,

  • a SQL string with a place holder that is not

  • Python's own curly brace placeholder.

  • This is a special SQL convention where you say plug in value here.

  • What value?

  • We'll plug in this names value, q, whatever the human has typed in.

  • And what are execute function will do for you

  • is all of the fancy backslashing and all of the escaping

  • and will protect you from the user's data.

  • And this is how truly simple it is.

  • It doesn't have to be CS50's library.

  • This is ever so common in all languages, but too few people know about it

  • and use it.

  • And so half the time you read about some database getting hacked

  • or your data getting stolen, it is because

  • of a stupid oversight like that.

  • So just use libraries and escape users' input.

  • We can see this now more concretely.

  • All of the undergrads in the room have surely

  • logged into, either Yale's website or Harvard's website,

  • which looks a little something like this here.

  • You're prompted for your login name and your password,

  • or your Harvard key or the like.

  • Well, how does this take effect in real terms?

  • If I were to type in my email address--

  • but then weird syntax like this-- let's look at an example.

  • Quote "or" quote unquote "1" equals quote "1."

  • Notice it's not balanced.

  • It's missing a quote over here, missing a quote over here.

  • Because the presumption is that maybe Harvard is vulnerable to this.

  • I don't think they are.

  • But suppose that the code running Harvard key

  • and Harvard's login page looks a little something like this.

  • This is bad.

  • This is dangerous because they're just using f strings or format

  • strings, which are just going to blindly plug anything in there.

  • And so if you let the human type in something cryptic like that,

  • notice what has happened logically.

  • Where username equals me at example your email provider.com and password

  • equals quote unquote, so nothing, or 1 equals 1.

  • And why 1 equals 1?

  • If I go back, notice that there's a quote here and a quote here.

  • And the reason that I didn't finish my second quote here or my second quote

  • here is because I'm assuming, as a bad guy,

  • I think Harvard is just going to blindly plug my input

  • into a single quotes of their own.

  • Therefore, I can finish their thought nonsensically.

  • But notice, logically, what happens.

  • Select all users from the database where the user name is me at example email

  • provider and the password is nothing.

  • Or 1 equals 1.

  • Well, when does 1 equal 1?

  • Like, always.

  • So this will always return users from the database,

  • and presumably, therefore, let me log in as one of those users--

  • so incredibly simple to defend against this.

  • Just use placeholder syntax and distrust and sanitize users' input.

  • The syntax in SQL and the CS50 library is quite simply with that colon.

  • But in other libraries, it might be quite the same.

  • So now you are all, families and students alike,

  • inaugurated into the small class of folks

  • in the world who understand particularly geeky humor.

  • You might notice this meme that's gone around the internet for many years

  • now where someone either maliciously or humorously

  • decided to paint this over their license platelets.

  • Let's enhance.

  • Why would someone do this?

  • AUDIENCE: Scanners.

  • DAVID J. MALAN: Scanners, yeah.

  • Tollbooths are going away, at least in the US.

  • And they instead have cameras or readers that are scanning the front of your car

  • and trying to optically do OCR, Optical Character Recognition,

  • on your license plate.

  • And the presumption here is, maybe in some municipality,

  • there's some badly written code where they just blindly plug

  • your license plate into their code.

  • And hopefully you finish the thought where ZU 0666--

  • whatever that is, it's part of the license plate--

  • but "semicolon drop database table dot dot dot."

  • And we didn't even look at that because DROP is pretty extreme.

  • It literally deletes a database itself.

  • But this is a nice way of getting off the hook from a total price.

  • And most canonical perhaps, XKCD is a very popular cartoon strip.

  • It's particularly geek-oriented.

  • And you'll perhaps understand this joke now as well among CS circles.

  • [LAUGHING]

  • I can hear the laughter making its way through.

  • So from here on out, if you take nothing else away,

  • remember little Bobby Tables with pset.

  • Our final, will you actually implement CS50 Finance

  • and coalesce all these ideas.

  • Thank you so much to all of our families for joining.

  • And we will see you next time.

  • [APPLAUSE]

[MUSIC PLAYING]

字幕與單字

單字即點即查 點擊單字可以查詢單字解釋

B1 中級

CS50 2018--閱讀8--SQL (CS50 2018 - Lecture 8 - SQL)

  • 3 0
    林宜悉 發佈於 2021 年 01 月 14 日
影片單字