|
| https://realpython.com/ |
| Start Here | https://realpython.com/start-here/ |
|
Learn Python
| https://realpython.com/lessons/duckdb-joining-data/ |
| Python Tutorials →In-depth articles and video courses | https://realpython.com/search?kind=article&kind=course&order=newest |
| Learning Paths →Guided study plans for accelerated learning | https://realpython.com/learning-paths/ |
| Quizzes & Exercises →Check your learning progress | https://realpython.com/quizzes/ |
| Browse Topics →Focus on a specific area or skill level | https://realpython.com/tutorials/all/ |
| Community Chat →Learn with other Pythonistas | https://realpython.com/community/ |
| Office Hours →Live Q&A calls with Python experts | https://realpython.com/office-hours/ |
| Podcast →Hear what’s new in the world of Python | https://realpython.com/podcasts/rpp/ |
| Books →Round out your knowledge and learn offline | https://realpython.com/products/books/ |
| Reference →Concise definitions for common Python terms | https://realpython.com/ref/ |
| Code Mentor →BetaPersonalized code assistance & learning tools | https://realpython.com/mentor/ |
| Unlock All Content → | https://realpython.com/account/join/ |
|
More
| https://realpython.com/lessons/duckdb-joining-data/ |
| Learner Stories | https://realpython.com/learner-stories/ |
| Python Newsletter | https://realpython.com/newsletter/ |
| Python Job Board | https://www.pythonjobshq.com |
| Meet the Team | https://realpython.com/team/ |
| Become a Contributor | https://realpython.com/jobs/ |
| Search | https://realpython.com/search |
| https://realpython.com/search |
| Join | https://realpython.com/account/join/ |
| Sign‑In | https://realpython.com/account/login/?next=%2Flessons%2Fduckdb-joining-data%2F |
| Unlock This Lesson | https://realpython.com/account/join/?utm_source=rp_lesson&utm_content=starting-duckdb-python |
| Unlock This Lesson | https://realpython.com/account/join/?utm_source=rp_lesson&utm_content=starting-duckdb-python |
| https://realpython.com/courses/starting-duckdb-python/#team |
| Starting With DuckDB and Python | https://realpython.com/courses/starting-duckdb-python/ |
| Christopher Trudeau | https://realpython.com/courses/starting-duckdb-python/#team |
| Recommended Tutorial | https://realpython.com/python-duckdb/ |
| Course Slides (.pdf) | https://realpython.com/courses/starting-duckdb-python/downloads/duckdb-slides/ |
| Sample Code (.zip) | https://realpython.com/courses/starting-duckdb-python/downloads/duckdb-code/ |
| Ask a Question | https://realpython.com/lessons/duckdb-joining-data/#discussion |
| https://realpython.com/feedback/survey/course/starting-duckdb-python/liked/?from=lesson-title |
| https://realpython.com/feedback/survey/course/starting-duckdb-python/disliked/?from=lesson-title |
| Transcript | https://realpython.com/lessons/duckdb-joining-data/#transcript |
| Discussion | https://realpython.com/lessons/duckdb-joining-data/#discussion |
| 00:00 | https://realpython.com/lessons/duckdb-joining-data/#t=0.535 |
| In the previous lesson, I showed you how | https://realpython.com/lessons/duckdb-joining-data/#t=0.535 |
| to programmatically access the data in a relation object. | https://realpython.com/lessons/duckdb-joining-data/#t=2.195 |
| In this lesson, I’ll be querying data across multiple tables | https://realpython.com/lessons/duckdb-joining-data/#t=5.215 |
| with an SQL join. | https://realpython.com/lessons/duckdb-joining-data/#t=8.235 |
| 00:11 | https://realpython.com/lessons/duckdb-joining-data/#t=11.095 |
| A SELECT statement can build a result set | https://realpython.com/lessons/duckdb-joining-data/#t=11.095 |
| by querying across multiple tables. | https://realpython.com/lessons/duckdb-joining-data/#t=13.635 |
| This is known as a JOIN. | https://realpython.com/lessons/duckdb-joining-data/#t=16.045 |
| When you add a JOIN to a SELECT statement, you need | https://realpython.com/lessons/duckdb-joining-data/#t=18.085 |
| to specify which tables are participating in the join, | https://realpython.com/lessons/duckdb-joining-data/#t=20.855 |
| and what condition | https://realpython.com/lessons/duckdb-joining-data/#t=24.115 |
| or conditions to use to relate the rows between the tables. | https://realpython.com/lessons/duckdb-joining-data/#t=25.275 |
| 00:29 | https://realpython.com/lessons/duckdb-joining-data/#t=29.905 |
| This mechanism is often used to express one | https://realpython.com/lessons/duckdb-joining-data/#t=29.905 |
| -to-many relationships in your data. | https://realpython.com/lessons/duckdb-joining-data/#t=32.675 |
| For example, a book can have multiple authors. | https://realpython.com/lessons/duckdb-joining-data/#t=35.305 |
| If you have a book table with an author column, | https://realpython.com/lessons/duckdb-joining-data/#t=38.625 |
| you wouldn’t be able to express this. | https://realpython.com/lessons/duckdb-joining-data/#t=40.945 |
| 00:42 | https://realpython.com/lessons/duckdb-joining-data/#t=42.735 |
| You’d be stuck with however many author columns you had. | https://realpython.com/lessons/duckdb-joining-data/#t=42.735 |
| You could have three author columns, | https://realpython.com/lessons/duckdb-joining-data/#t=46.065 |
| but what if the book has four authors? | https://realpython.com/lessons/duckdb-joining-data/#t=47.665 |
| Also, what if you want | https://realpython.com/lessons/duckdb-joining-data/#t=50.395 |
| to store more information about the author. Instead, | https://realpython.com/lessons/duckdb-joining-data/#t=51.645 |
| the structure you use in this case is a table for books | https://realpython.com/lessons/duckdb-joining-data/#t=54.745 |
| with each book having a unique ID, | https://realpython.com/lessons/duckdb-joining-data/#t=58.315 |
| and a table for authors, who also get their own ID. | https://realpython.com/lessons/duckdb-joining-data/#t=60.545 |
| 01:04 | https://realpython.com/lessons/duckdb-joining-data/#t=64.585 |
| By having separate tables, you can have all sorts | https://realpython.com/lessons/duckdb-joining-data/#t=64.585 |
| of information that are specific to each thing. | https://realpython.com/lessons/duckdb-joining-data/#t=66.805 |
| The ISBN number could go with the book, | https://realpython.com/lessons/duckdb-joining-data/#t=69.745 |
| while the date of birth could go with the author. | https://realpython.com/lessons/duckdb-joining-data/#t=72.115 |
| 01:15 | https://realpython.com/lessons/duckdb-joining-data/#t=75.375 |
| To express the relationship between a book and its authors, | https://realpython.com/lessons/duckdb-joining-data/#t=75.375 |
| you would then need a third table. | https://realpython.com/lessons/duckdb-joining-data/#t=78.375 |
| This table would contain a column for a book’s ID | https://realpython.com/lessons/duckdb-joining-data/#t=80.785 |
| and a column for an author’s ID. | https://realpython.com/lessons/duckdb-joining-data/#t=83.495 |
| 01:26 | https://realpython.com/lessons/duckdb-joining-data/#t=86.075 |
| A book with multiple authors would be expressed | https://realpython.com/lessons/duckdb-joining-data/#t=86.075 |
| by multiple rows in this relationship table, one | https://realpython.com/lessons/duckdb-joining-data/#t=88.215 |
| for each book-author pair. | https://realpython.com/lessons/duckdb-joining-data/#t=91.155 |
| With this kind of table structure in place, | https://realpython.com/lessons/duckdb-joining-data/#t=93.945 |
| you would use a join operation | https://realpython.com/lessons/duckdb-joining-data/#t=96.095 |
| to query which authors are associated | https://realpython.com/lessons/duckdb-joining-data/#t=97.755 |
| with any given book or books. | https://realpython.com/lessons/duckdb-joining-data/#t=100.225 |
| 01:44 | https://realpython.com/lessons/duckdb-joining-data/#t=104.695 |
| Although the three-table structure | https://realpython.com/lessons/duckdb-joining-data/#t=104.695 |
| that I just mentioned is common, it’s a little complex, | https://realpython.com/lessons/duckdb-joining-data/#t=106.055 |
| so I’m going to use a slightly simpler example. | https://realpython.com/lessons/duckdb-joining-data/#t=108.715 |
| On screen here is a simplified version | https://realpython.com/lessons/duckdb-joining-data/#t=111.395 |
| of our presidents data, along with a new table | https://realpython.com/lessons/duckdb-joining-data/#t=113.875 |
| that contains the political parties information. | https://realpython.com/lessons/duckdb-joining-data/#t=116.765 |
| 02:00 | https://realpython.com/lessons/duckdb-joining-data/#t=120.205 |
| You may recall that our president table had a column | https://realpython.com/lessons/duckdb-joining-data/#t=120.205 |
| called party_id. | https://realpython.com/lessons/duckdb-joining-data/#t=123.025 |
| The party table then has a column which uses | https://realpython.com/lessons/duckdb-joining-data/#t=125.045 |
| that same identifier. To query the president | https://realpython.com/lessons/duckdb-joining-data/#t=127.745 |
| and their party name, you need a join. | https://realpython.com/lessons/duckdb-joining-data/#t=130.965 |
| 02:17 | https://realpython.com/lessons/duckdb-joining-data/#t=137.465 |
| The SELECT portion is similar to what you’ve seen before. | https://realpython.com/lessons/duckdb-joining-data/#t=137.465 |
| Just note that the columns in the SELECT can be from any | https://realpython.com/lessons/duckdb-joining-data/#t=140.795 |
| of the tables participating in the join. | https://realpython.com/lessons/duckdb-joining-data/#t=143.965 |
| 02:28 | https://realpython.com/lessons/duckdb-joining-data/#t=148.035 |
| After the JOIN keyword, | https://realpython.com/lessons/duckdb-joining-data/#t=148.035 |
| you provide the other tables participating. | https://realpython.com/lessons/duckdb-joining-data/#t=150.085 |
| In this case, it’s the parties table. | https://realpython.com/lessons/duckdb-joining-data/#t=152.445 |
| The ON keyword dictates how to relate the data | https://realpython.com/lessons/duckdb-joining-data/#t=154.765 |
| between the two tables. | https://realpython.com/lessons/duckdb-joining-data/#t=159.115 |
| 02:41 | https://realpython.com/lessons/duckdb-joining-data/#t=161.135 |
| In our case, the party_id is common between them, | https://realpython.com/lessons/duckdb-joining-data/#t=161.135 |
| so when the party_id on presidents matches the party_id on | https://realpython.com/lessons/duckdb-joining-data/#t=164.215 |
| the party’s table, the data gets joined. | https://realpython.com/lessons/duckdb-joining-data/#t=168.015 |
| 02:51 | https://realpython.com/lessons/duckdb-joining-data/#t=171.275 |
| The resulting data is each president with the name | https://realpython.com/lessons/duckdb-joining-data/#t=171.275 |
| of their party. Joins can get | https://realpython.com/lessons/duckdb-joining-data/#t=173.775 |
| much more complicated than this, | https://realpython.com/lessons/duckdb-joining-data/#t=176.295 |
| having more than two tables as well as different rules | https://realpython.com/lessons/duckdb-joining-data/#t=177.455 |
| for how to match data | https://realpython.com/lessons/duckdb-joining-data/#t=180.025 |
| on the left to data on the right, | https://realpython.com/lessons/duckdb-joining-data/#t=181.105 |
| this is really just a taste, | https://realpython.com/lessons/duckdb-joining-data/#t=183.115 |
| a tiny little breadcrumb tossed in a pond. | https://realpython.com/lessons/duckdb-joining-data/#t=185.365 |
| 03:08 | https://realpython.com/lessons/duckdb-joining-data/#t=188.735 |
| Let’s go see this in practice. Same import, same data, | https://realpython.com/lessons/duckdb-joining-data/#t=188.735 |
| 03:18 | https://realpython.com/lessons/duckdb-joining-data/#t=198.305 |
| and a quick query to remind you what’s in there. | https://realpython.com/lessons/duckdb-joining-data/#t=198.305 |
| You may recall from a previous lesson, | https://realpython.com/lessons/duckdb-joining-data/#t=201.065 |
| I used the limit method to restrict | https://realpython.com/lessons/duckdb-joining-data/#t=203.205 |
| how many rows got shown in the result. | https://realpython.com/lessons/duckdb-joining-data/#t=205.105 |
| 03:27 | https://realpython.com/lessons/duckdb-joining-data/#t=207.425 |
| The reason it’s called LIMIT rather than HEAD, is | https://realpython.com/lessons/duckdb-joining-data/#t=207.425 |
| because LIMIT is an SQL keyword. | https://realpython.com/lessons/duckdb-joining-data/#t=210.245 |
| I’ve used it in my query here | https://realpython.com/lessons/duckdb-joining-data/#t=212.675 |
| to return just the first two results. | https://realpython.com/lessons/duckdb-joining-data/#t=214.185 |
| 03:36 | https://realpython.com/lessons/duckdb-joining-data/#t=216.735 |
| Alright, that’s our presidents data. | https://realpython.com/lessons/duckdb-joining-data/#t=216.735 |
| Now let’s go get the party info. | https://realpython.com/lessons/duckdb-joining-data/#t=218.845 |
| 03:45 | https://realpython.com/lessons/duckdb-joining-data/#t=225.555 |
| Parquet and CSV are | https://realpython.com/lessons/duckdb-joining-data/#t=225.555 |
| so 10 minutes ago. This time the data’s in JSON. Note, | https://realpython.com/lessons/duckdb-joining-data/#t=227.305 |
| I’ve chained the to_table() call here on the end. | https://realpython.com/lessons/duckdb-joining-data/#t=231.075 |
| 03:59 | https://realpython.com/lessons/duckdb-joining-data/#t=239.195 |
| So far, so familiar. Okay, how about a quick sanity check? | https://realpython.com/lessons/duckdb-joining-data/#t=239.195 |
| How do you know what’s in your database? | https://realpython.com/lessons/duckdb-joining-data/#t=243.635 |
| Well, the database itself contains metadata about the | https://realpython.com/lessons/duckdb-joining-data/#t=245.645 |
| database, which you can query. | https://realpython.com/lessons/duckdb-joining-data/#t=248.775 |
| 04:15 | https://realpython.com/lessons/duckdb-joining-data/#t=255.435 |
| The special duckdb_tables table tells us there are two | https://realpython.com/lessons/duckdb-joining-data/#t=255.435 |
| tables in the database. | https://realpython.com/lessons/duckdb-joining-data/#t=259.755 |
| Okay, let’s construct our join. | https://realpython.com/lessons/duckdb-joining-data/#t=262.005 |
| 04:37 | https://realpython.com/lessons/duckdb-joining-data/#t=277.925 |
| So far, this is just like the example I showed you. | https://realpython.com/lessons/duckdb-joining-data/#t=277.925 |
| Let’s add a little orange glaze to our duck. | https://realpython.com/lessons/duckdb-joining-data/#t=280.355 |
| 04:45 | https://realpython.com/lessons/duckdb-joining-data/#t=285.995 |
| Rather than seeing everyone, I’ve restricted the results | https://realpython.com/lessons/duckdb-joining-data/#t=285.995 |
| to just the Whig party. | https://realpython.com/lessons/duckdb-joining-data/#t=289.395 |
| This could also have been done | https://realpython.com/lessons/duckdb-joining-data/#t=291.355 |
| with the party_id on either table if you knew the | https://realpython.com/lessons/duckdb-joining-data/#t=292.685 |
| ID for the Whigs. | https://realpython.com/lessons/duckdb-joining-data/#t=296.305 |
| 05:00 | https://realpython.com/lessons/duckdb-joining-data/#t=300.365 |
| The ORDER BY clause specifies the sorting of the results. | https://realpython.com/lessons/duckdb-joining-data/#t=300.365 |
| It takes an argument as | https://realpython.com/lessons/duckdb-joining-data/#t=304.245 |
| to which column in the results to perform the sorting upon. | https://realpython.com/lessons/duckdb-joining-data/#t=305.505 |
| 05:07 | https://realpython.com/lessons/duckdb-joining-data/#t=307.785 |
| The DESC keyword, pronounced descending, | https://realpython.com/lessons/duckdb-joining-data/#t=307.785 |
| means descending, specifying the sort order being | https://realpython.com/lessons/duckdb-joining-data/#t=312.105 |
| that direction around. And there you go. | https://realpython.com/lessons/duckdb-joining-data/#t=315.215 |
| There were four presidents from the Whig party. | https://realpython.com/lessons/duckdb-joining-data/#t=319.535 |
| 05:22 | https://realpython.com/lessons/duckdb-joining-data/#t=322.515 |
| How funny is that? One of them’s named Millard. | https://realpython.com/lessons/duckdb-joining-data/#t=322.515 |
| I swear to you, I didn’t plan that. You may recall | https://realpython.com/lessons/duckdb-joining-data/#t=325.375 |
| I said it was good practice | https://realpython.com/lessons/duckdb-joining-data/#t=329.305 |
| to close your connection when you’re done with it. | https://realpython.com/lessons/duckdb-joining-data/#t=330.425 |
| 05:32 | https://realpython.com/lessons/duckdb-joining-data/#t=332.635 |
| This is me doing that. To come full circle, | https://realpython.com/lessons/duckdb-joining-data/#t=332.635 |
| let’s see the same idea using in-memory operations. | https://realpython.com/lessons/duckdb-joining-data/#t=335.495 |
| 05:45 | https://realpython.com/lessons/duckdb-joining-data/#t=345.085 |
| Note, I’m not using a connection here. | https://realpython.com/lessons/duckdb-joining-data/#t=345.085 |
| The same read methods are available directly on the module. | https://realpython.com/lessons/duckdb-joining-data/#t=347.275 |
| 05:55 | https://realpython.com/lessons/duckdb-joining-data/#t=355.705 |
| I’ve got both presidents and parties as relation objects. | https://realpython.com/lessons/duckdb-joining-data/#t=355.705 |
| Remember, these aren’t tables. The connection’s closed. | https://realpython.com/lessons/duckdb-joining-data/#t=359.925 |
| Python no longer knows about those tables at all. | https://realpython.com/lessons/duckdb-joining-data/#t=362.945 |
| 06:06 | https://realpython.com/lessons/duckdb-joining-data/#t=366.405 |
| Queries can be performed on relation objects | https://realpython.com/lessons/duckdb-joining-data/#t=366.405 |
| as if they were tables | https://realpython.com/lessons/duckdb-joining-data/#t=368.305 |
| by using the sql() function directly on the DuckDB module. | https://realpython.com/lessons/duckdb-joining-data/#t=369.425 |
| 06:27 | https://realpython.com/lessons/duckdb-joining-data/#t=387.705 |
| Same query, same results, | https://realpython.com/lessons/duckdb-joining-data/#t=387.705 |
| but this time it was done on the memory objects | https://realpython.com/lessons/duckdb-joining-data/#t=390.735 |
| instead. I’ve been fast | https://realpython.com/lessons/duckdb-joining-data/#t=393.235 |
| and loose with the names here, using presidents | https://realpython.com/lessons/duckdb-joining-data/#t=395.255 |
| to mean a table earlier and a relation now. | https://realpython.com/lessons/duckdb-joining-data/#t=397.695 |
| 06:41 | https://realpython.com/lessons/duckdb-joining-data/#t=401.075 |
| You can almost think of them as the same things | https://realpython.com/lessons/duckdb-joining-data/#t=401.075 |
| as you can perform queries on either, | https://realpython.com/lessons/duckdb-joining-data/#t=403.395 |
| but make sure you don’t confuse them. | https://realpython.com/lessons/duckdb-joining-data/#t=405.195 |
| The relation only lives as long as this REPL session, | https://realpython.com/lessons/duckdb-joining-data/#t=406.875 |
| whereas the table can be accessed again by connecting | https://realpython.com/lessons/duckdb-joining-data/#t=409.805 |
| to the database once more. | https://realpython.com/lessons/duckdb-joining-data/#t=412.535 |
| 06:55 | https://realpython.com/lessons/duckdb-joining-data/#t=415.385 |
| Let’s do this one more time in a third way, this time | https://realpython.com/lessons/duckdb-joining-data/#t=415.385 |
| through method calls. | https://realpython.com/lessons/duckdb-joining-data/#t=418.655 |
| 07:05 | https://realpython.com/lessons/duckdb-joining-data/#t=425.515 |
| There’s a little bit of housekeeping necessary | https://realpython.com/lessons/duckdb-joining-data/#t=425.515 |
| before using the API. You need to give DuckDB a name | https://realpython.com/lessons/duckdb-joining-data/#t=427.365 |
| to associate with your relation object for use | https://realpython.com/lessons/duckdb-joining-data/#t=431.185 |
| inside the API calls. | https://realpython.com/lessons/duckdb-joining-data/#t=434.105 |
| 07:20 | https://realpython.com/lessons/duckdb-joining-data/#t=440.415 |
| You can think of this like | https://realpython.com/lessons/duckdb-joining-data/#t=440.415 |
| registering the object with a name. | https://realpython.com/lessons/duckdb-joining-data/#t=441.715 |
| This name doesn’t have to be the same as the name | https://realpython.com/lessons/duckdb-joining-data/#t=443.425 |
| of the variable you’re using to store the relation object, | https://realpython.com/lessons/duckdb-joining-data/#t=445.475 |
| but typically that’s what you do. | https://realpython.com/lessons/duckdb-joining-data/#t=448.215 |
| 07:30 | https://realpython.com/lessons/duckdb-joining-data/#t=450.515 |
| Now, let me construct the same query as before, | https://realpython.com/lessons/duckdb-joining-data/#t=450.515 |
| but this time using chained method calls. | https://realpython.com/lessons/duckdb-joining-data/#t=452.635 |
| The reason for the aliases will be clearer in a second. | https://realpython.com/lessons/duckdb-joining-data/#t=455.785 |
| 07:39 | https://realpython.com/lessons/duckdb-joining-data/#t=459.825 |
| Starting with the president’s relation object, | https://realpython.com/lessons/duckdb-joining-data/#t=459.825 |
| 07:48 | https://realpython.com/lessons/duckdb-joining-data/#t=468.045 |
| and chaining a join() method. | https://realpython.com/lessons/duckdb-joining-data/#t=468.045 |
| This takes the party’s relationship object as an argument | https://realpython.com/lessons/duckdb-joining-data/#t=470.055 |
| and a condition for the joining. | https://realpython.com/lessons/duckdb-joining-data/#t=473.365 |
| The condition is a string. Inside the string, | https://realpython.com/lessons/duckdb-joining-data/#t=475.885 |
| you need to reference the objects, hence the alias. | https://realpython.com/lessons/duckdb-joining-data/#t=478.785 |
| 08:02 | https://realpython.com/lessons/duckdb-joining-data/#t=482.855 |
| DuckDB parses the condition like it does | https://realpython.com/lessons/duckdb-joining-data/#t=482.855 |
| inside an SQL statement, | https://realpython.com/lessons/duckdb-joining-data/#t=485.085 |
| and the alias is what tells it | https://realpython.com/lessons/duckdb-joining-data/#t=486.805 |
| to associate those names in the condition | https://realpython.com/lessons/duckdb-joining-data/#t=488.345 |
| with the relation objects. | https://realpython.com/lessons/duckdb-joining-data/#t=490.615 |
| 08:13 | https://realpython.com/lessons/duckdb-joining-data/#t=493.205 |
| This is kind of messy. | https://realpython.com/lessons/duckdb-joining-data/#t=493.205 |
| If you’re used to ORMs like SQLAlchemy or Django, | https://realpython.com/lessons/duckdb-joining-data/#t=494.875 |
| this feels kind of fragile. | https://realpython.com/lessons/duckdb-joining-data/#t=498.205 |
| Both those ORMs have ways of writing this kind of expression | https://realpython.com/lessons/duckdb-joining-data/#t=500.565 |
| with objects instead. | https://realpython.com/lessons/duckdb-joining-data/#t=503.375 |
| 08:24 | https://realpython.com/lessons/duckdb-joining-data/#t=504.835 |
| But hey, it works. With the tables | https://realpython.com/lessons/duckdb-joining-data/#t=504.835 |
| joined, the select() method specifies the names of the columns | https://realpython.com/lessons/duckdb-joining-data/#t=508.675 |
| for our result, and then the filter() call | https://realpython.com/lessons/duckdb-joining-data/#t=511.715 |
| enacts the WHERE clause. | https://realpython.com/lessons/duckdb-joining-data/#t=515.545 |
| 08:37 | https://realpython.com/lessons/duckdb-joining-data/#t=517.955 |
| Finally, a call to order() | https://realpython.com/lessons/duckdb-joining-data/#t=517.955 |
| to sort the results, and there you go. | https://realpython.com/lessons/duckdb-joining-data/#t=519.625 |
| Third way, same result. | https://realpython.com/lessons/duckdb-joining-data/#t=523.225 |
| The API method’s a little more verbose than writing SQL | https://realpython.com/lessons/duckdb-joining-data/#t=525.405 |
| queries directly, but from your IDE’s perspective, | https://realpython.com/lessons/duckdb-joining-data/#t=528.305 |
| SQL is just a string. | https://realpython.com/lessons/duckdb-joining-data/#t=531.005 |
| 08:52 | https://realpython.com/lessons/duckdb-joining-data/#t=532.515 |
| Using the API like this gives you type hinting | https://realpython.com/lessons/duckdb-joining-data/#t=532.515 |
| and compiler enforcement, making bugs a little less | https://realpython.com/lessons/duckdb-joining-data/#t=535.11 |
| likely. When done right, | https://realpython.com/lessons/duckdb-joining-data/#t=537.845 |
| it also helps deal with SQL injection. | https://realpython.com/lessons/duckdb-joining-data/#t=539.785 |
| 09:02 | https://realpython.com/lessons/duckdb-joining-data/#t=542.245 |
| I won’t go into that here. | https://realpython.com/lessons/duckdb-joining-data/#t=542.245 |
| The short version is if a user is passing you strings | https://realpython.com/lessons/duckdb-joining-data/#t=543.905 |
| that you’re basing your query upon, they could include stuff | https://realpython.com/lessons/duckdb-joining-data/#t=546.805 |
| that mangles your SQL. | https://realpython.com/lessons/duckdb-joining-data/#t=549.565 |
| 09:10 | https://realpython.com/lessons/duckdb-joining-data/#t=550.905 |
| And when I say mangle, | https://realpython.com/lessons/duckdb-joining-data/#t=550.905 |
| I mean vicious things like deleting data or tables. | https://realpython.com/lessons/duckdb-joining-data/#t=552.205 |
| For a little more information on this, Google OWASP, | https://realpython.com/lessons/duckdb-joining-data/#t=555.225 |
| that’s O-W-A-S-P SQL injection attacks | https://realpython.com/lessons/duckdb-joining-data/#t=558.025 |
| for a little bit of homework. | https://realpython.com/lessons/duckdb-joining-data/#t=561.785 |
| 09:25 | https://realpython.com/lessons/duckdb-joining-data/#t=565.495 |
| Why did the mallard want to be an accountant? | https://realpython.com/lessons/duckdb-joining-data/#t=565.495 |
| Because he loved deductions. Tip your waitress. | https://realpython.com/lessons/duckdb-joining-data/#t=567.745 |
| I’ll be here all week. Next up, how | https://realpython.com/lessons/duckdb-joining-data/#t=571.795 |
| to incorporate Python functions into your DuckDB queries. | https://realpython.com/lessons/duckdb-joining-data/#t=574.435 |
| Become a Member | https://realpython.com/account/join/ |
| https://realpython.com/lessons/accessing-data-relation-objects/ |
| Overview | https://realpython.com/courses/starting-duckdb-python/ |
| https://realpython.com/lessons/python-functions-inside-duckdb-queries/ |
|
Starting With DuckDB and Python (Overview) 02:39
| https://realpython.com/videos/starting-duckdb-python-overview/ |
|
Reviewing SQL 07:53
| https://realpython.com/videos/duckdb-reviewing-sql/ |
|
An Introduction to DuckDB 07:13
| https://realpython.com/videos/introduction-duckdb/ |
|
Using DuckDB With Databases 05:03
| https://realpython.com/videos/duckdb-databases/ |
|
Ingesting CSV Files 04:43
| https://realpython.com/lessons/ingesting-csv-files/ |
|
Accessing Data in Relation Objects 03:28
| https://realpython.com/lessons/accessing-data-relation-objects/ |
|
Joining Data 09:39
| https://realpython.com/lessons/duckdb-joining-data/ |
|
Using Python Functions Inside DuckDB Queries 05:25
| https://realpython.com/lessons/python-functions-inside-duckdb-queries/ |
|
Starting With DuckDB and Python (Quiz) 06:30
| https://realpython.com/lessons/starting-duckdb-python-quiz/ |
|
Starting With DuckDB and Python (Summary) 02:33
| https://realpython.com/lessons/starting-duckdb-python-summary/ |
| Privacy Policy | https://realpython.com/privacy-policy/ |
Viewport: width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover