From 0ebb71e09ad299676206f64fe348a88ca159b3a0 Mon Sep 17 00:00:00 2001 From: Academy CI Date: Sun, 16 Aug 2026 18:18:11 +0000 Subject: [PATCH] Sync content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed content: - Deleted: course/guide/sched‎uled-events - Updated: course/module-0/intro-community - Updated: course/module-0/intro-intro - Updated: course/module-0/intro-structure-of-course - Updated: course/module-1/basic-database-concepts - Updated: course/module-1/database-types - Updated: course/module-1/document-oriented-databases - Updated: course/module-1/intro-sql - Updated: course/module-1/key-value-databases - Updated: course/module-1/relation-databases - Updated: course/module-1/structure-of-relation-databases - Updated: course/module-2/aggregate-functions - Updated: course/module-2/basic-syntax-sql-query - Updated: course/module-2/conditional-where-operator - Updated: course/module-2/distinct-operator - Updated: course/module-2/groupping - Updated: course/module-2/is-null-between-in-operators - Updated: course/module-2/literals - Updated: course/module-2/operator-having - Updated: course/module-2/operator-like - Updated: course/module-2/operator-regexp - Updated: course/module-2/sorting - Updated: course/module-2/using-functions - Updated: course/module-3/case-expression - Updated: course/module-3/combining-queries - Updated: course/module-3/correlated-subqueries - Updated: course/module-3/if-function - Updated: course/module-3/inner-join - Updated: course/module-3/limit - Updated: course/module-3/multi-table-request-join - Updated: course/module-3/nested-sql-queries - Updated: course/module-3/operator-with - Updated: course/module-3/outer-join - Updated: course/module-3/subquery-with-one-column-one-row - Updated: course/module-3/subquery-with-one-column-several-row - Updated: course/module-3/subquery-with-several-column - Updated: course/module-4/operator-delete - Updated: course/module-4/operator-insert - Updated: course/module-4/operator-update - Updated: course/module-5/creating-transactions - Updated: course/module-5/locking - Updated: course/module-5/operators-if-case-while-in-stored-procedures - Updated: course/module-5/partitions - Added: course/module-5/scheduled-events - Added: course/module-5/sorting-in-windows-functions - Deleted: course/module-5/sorting-in-windows-functions - Updated: course/module-5/stored-functions - Updated: course/module-5/stored-procedures-and-functions - Updated: course/module-5/stored-procedures - Updated: course/module-5/transactions - Updated: course/module-5/type-conversion-functions - Updated: course/module-5/types-of-windows-functions - Updated: course/module-5/windows-functions-frames - Updated: course/module-5/windows-functions - Updated: course/module-5/work-with-datatypes - Updated: course/module-5/work-with-datetime-data-type - Updated: course/module-5/work-with-number-data-type - Updated: course/module-6/constraints - Updated: course/module-6/create-database - Updated: course/module-6/create-table - Updated: course/module-6/datetime-data-type - Updated: course/module-6/indexes - Updated: course/module-6/number-data-type - Updated: course/module-6/string-data-type - Updated: course/module-6/table-data-type - Updated: course/module-6/view - Updated: interviewQuestions/1 - Updated: interviewQuestions/10 - Updated: interviewQuestions/11 - Updated: interviewQuestions/12 - Updated: interviewQuestions/13 - Updated: interviewQuestions/14 - Updated: interviewQuestions/15 - Updated: interviewQuestions/16 - Updated: interviewQuestions/17 - Updated: interviewQuestions/18 - Updated: interviewQuestions/19 - Updated: interviewQuestions/2 - Updated: interviewQuestions/20 - Updated: interviewQuestions/21 - Updated: interviewQuestions/22 - Updated: interviewQuestions/23 - Updated: interviewQuestions/24 - Updated: interviewQuestions/25 - Updated: interviewQuestions/26 - Updated: interviewQuestions/27 - Updated: interviewQuestions/28 - Updated: interviewQuestions/29 - Updated: interviewQuestions/3 - Updated: interviewQuestions/30 - Updated: interviewQuestions/31 - Updated: interviewQuestions/32 - Updated: interviewQuestions/33 - Updated: interviewQuestions/34 - Updated: interviewQuestions/35 - Updated: interviewQuestions/36 - Updated: interviewQuestions/37 - Updated: interviewQuestions/38 - Updated: interviewQuestions/39 - Updated: interviewQuestions/4 - Updated: interviewQuestions/40 - Updated: interviewQuestions/5 - Updated: interviewQuestions/6 - Updated: interviewQuestions/7 - Updated: interviewQuestions/8 - Updated: interviewQuestions/9 --- .../sched\342\200\216uled-events/article.md" | 362 -------------- course/module-0/intro-community/article.md | 32 +- course/module-0/intro-intro/article.md | 24 +- .../intro-structure-of-course/article.md | 22 +- .../basic-database-concepts/article.md | 49 +- course/module-1/database-types/article.md | 12 +- .../document-oriented-databases/article.md | 4 +- course/module-1/intro-sql/article.md | 50 +- .../module-1/key-value-databases/article.md | 4 +- course/module-1/relation-databases/article.md | 4 +- .../article.md | 38 +- .../module-2/aggregate-functions/article.md | 92 ++-- .../basic-syntax-sql-query/article.md | 50 +- .../conditional-where-operator/article.md | 255 +++++----- course/module-2/distinct-operator/article.md | 10 +- course/module-2/groupping/article.md | 120 +++-- .../is-null-between-in-operators/article.md | 4 +- course/module-2/literals/article.md | 86 ++-- course/module-2/operator-having/article.md | 24 +- course/module-2/operator-like/article.md | 55 ++- course/module-2/operator-regexp/article.md | 213 ++++---- course/module-2/sorting/article.md | 40 +- course/module-2/using-functions/article.md | 160 +++++-- course/module-3/case-expression/article.md | 135 ++++-- course/module-3/combining-queries/article.md | 20 +- .../module-3/correlated-subqueries/article.md | 10 +- course/module-3/if-function/article.md | 332 ++++++++++++- course/module-3/inner-join/article.md | 8 +- course/module-3/limit/article.md | 44 +- .../multi-table-request-join/article.md | 17 +- course/module-3/nested-sql-queries/article.md | 4 +- course/module-3/operator-with/article.md | 54 ++- course/module-3/outer-join/article.md | 368 +++++++------- .../article.md | 24 +- .../article.md | 38 +- .../subquery-with-several-column/article.md | 10 +- course/module-4/operator-delete/article.md | 46 +- course/module-4/operator-insert/article.md | 129 ++++- course/module-4/operator-update/article.md | 30 +- .../module-5/creating-transactions/article.md | 20 +- course/module-5/locking/article.md | 30 +- .../article.md | 85 ++-- course/module-5/partitions/article.md | 179 ++++++- course/module-5/scheduled-events/article.md | 407 ++++++++++++++++ .../{article.mdx => article.md} | 14 +- course/module-5/stored-functions/article.md | 138 +++--- .../article.md | 41 +- course/module-5/stored-procedures/article.md | 101 ++-- course/module-5/transactions/article.md | 4 +- .../type-conversion-functions/article.md | 74 +-- .../types-of-windows-functions/article.md | 182 ++++++- .../windows-functions-frames/article.md | 54 ++- course/module-5/windows-functions/article.md | 204 +++++++- .../module-5/work-with-datatypes/article.md | 4 +- .../work-with-datetime-data-type/article.md | 164 +++---- .../work-with-number-data-type/article.md | 130 +++-- course/module-6/constraints/article.md | 44 +- course/module-6/create-database/article.md | 45 +- course/module-6/create-table/article.md | 453 ++++++++++-------- course/module-6/datetime-data-type/article.md | 56 ++- course/module-6/indexes/article.md | 74 +-- course/module-6/number-data-type/article.md | 67 ++- course/module-6/string-data-type/article.md | 12 +- course/module-6/table-data-type/article.md | 4 +- course/module-6/view/article.md | 86 +++- interviewQuestions/1/en.mdx | 16 +- interviewQuestions/10/en.mdx | 26 +- interviewQuestions/11/en.mdx | 22 +- interviewQuestions/12/en.mdx | 16 +- interviewQuestions/13/en.mdx | 12 +- interviewQuestions/14/en.mdx | 8 +- interviewQuestions/15/en.mdx | 14 +- interviewQuestions/16/en.mdx | 14 +- interviewQuestions/17/en.mdx | 22 +- interviewQuestions/18/en.mdx | 26 +- interviewQuestions/19/en.mdx | 20 +- interviewQuestions/2/en.mdx | 17 +- interviewQuestions/20/en.mdx | 28 +- interviewQuestions/21/en.mdx | 18 +- interviewQuestions/22/en.mdx | 22 +- interviewQuestions/23/en.mdx | 36 +- interviewQuestions/24/en.mdx | 6 +- interviewQuestions/25/en.mdx | 22 +- interviewQuestions/26/en.mdx | 24 +- interviewQuestions/27/en.mdx | 10 +- interviewQuestions/28/en.mdx | 30 +- interviewQuestions/29/en.mdx | 12 +- interviewQuestions/3/en.mdx | 16 +- interviewQuestions/30/en.mdx | 8 +- interviewQuestions/31/en.mdx | 12 +- interviewQuestions/32/en.mdx | 6 +- interviewQuestions/33/en.mdx | 12 +- interviewQuestions/34/en.mdx | 34 +- interviewQuestions/35/en.mdx | 49 +- interviewQuestions/36/en.mdx | 32 +- interviewQuestions/37/en.mdx | 22 +- interviewQuestions/38/en.mdx | 16 +- interviewQuestions/39/en.mdx | 12 +- interviewQuestions/4/en.mdx | 114 +---- interviewQuestions/40/en.mdx | 32 +- interviewQuestions/5/en.mdx | 24 +- interviewQuestions/6/en.mdx | 10 +- interviewQuestions/7/en.mdx | 4 +- interviewQuestions/8/en.mdx | 16 +- interviewQuestions/9/en.mdx | 12 +- 105 files changed, 3891 insertions(+), 2612 deletions(-) delete mode 100644 "course/guide/sched\342\200\216uled-events/article.md" create mode 100644 course/module-5/scheduled-events/article.md rename course/module-5/sorting-in-windows-functions/{article.mdx => article.md} (87%) diff --git "a/course/guide/sched\342\200\216uled-events/article.md" "b/course/guide/sched\342\200\216uled-events/article.md" deleted file mode 100644 index f23bbe4..0000000 --- "a/course/guide/sched\342\200\216uled-events/article.md" +++ /dev/null @@ -1,362 +0,0 @@ ---- -meta: - title: 'SQL Event Scheduler: MySQL EVENT & PostgreSQL pg_cron Guide' - description: 'Complete guide to creating automated tasks in MySQL and PostgreSQL. Learn to use EVENT scheduler and pg_cron for data cleanup, statistics updates, and report generation on schedule. Code examples and practical tips included.' ---- - - - -# Scheduled Events - -In real-world applications, there's often a need to automatically execute certain actions on a schedule: cleaning up old records, updating statistics, generating reports. SQL provides a mechanism called **scheduled events** for these tasks. - -> **Event** is a task the database runs for you on a schedule. You set it up — it runs automatically. - - - -Events in MySQL are similar to a task scheduler in an operating system: you create a task once, and the database executes it automatically on schedule. - - - - - -In PostgreSQL, automatic task execution is handled by the **pg_cron** extension. This extension allows you to schedule SQL commands using cron syntax (like in Unix systems). - - - -## When it is useful - -Scheduled events help automate the following tasks: - -- **Data cleanup**: removing outdated log records or temporary data -- **Statistics updates**: recalculating aggregated data for analytics -- **Report generation**: automatically creating periodic reports -- **Backups**: creating copies of important data - -## Enabling the scheduler - - - -Before creating events, make sure the event scheduler is enabled: - -```sql -SHOW VARIABLES LIKE 'event_scheduler'; -``` - -If the scheduler is disabled, enable it: - -```sql -SET GLOBAL event_scheduler = ON; -``` - - - - - -To use scheduled tasks in PostgreSQL, you need to install the pg_cron extension: - -```sql -CREATE EXTENSION IF NOT EXISTS pg_cron; -``` - -> **Important:** The pg_cron extension may require superuser privileges and additional PostgreSQL configuration. In cloud services (AWS RDS, Azure), it may already be pre-installed. - - - -## Creating a One-Time Event - -Let's start with the simplest case — an event that executes once at a specific time: - - - -```sql-executable -CREATE EVENT cleanup_old_logs -ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY -DO - DELETE FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY; -``` - -This event will delete log records older than 30 days, 24 hours after the event is created. - -**Breaking down the syntax:** - -- `CREATE EVENT cleanup_old_logs` — create an event named `cleanup_old_logs` -- `ON SCHEDULE AT` — specify when the event should execute -- `CURRENT_TIMESTAMP + INTERVAL 1 DAY` — execution time (in 1 day) -- `DO` — the code to execute (any SQL statement) - - - - - -```sql -SELECT cron.schedule( - 'cleanup_old_logs', - '0 3 * * *', - 'DELETE FROM logs WHERE created_at < NOW() - INTERVAL ''30 days''' -); -``` - -This event will run every day at 3:00 AM and delete log records older than 30 days. - -**Breaking down the syntax:** - -- `cron.schedule()` — function to create a scheduled task -- `'cleanup_old_logs'` — task name -- `'0 3 * * *'` — schedule in cron format (minute hour day month day_of_week) -- Last parameter — SQL command to execute - -**Cron schedule format:** - -![Format cron scheduler](https://sql-academy.org/static/guidePage/scheduled-events/cron_schedule_en.png 'Format cron scheduler') - - - -## Creating a Recurring Event - -More often, events need to run periodically — every day, hour, or minute: - - - -```sql-executable -CREATE EVENT update_statistics -ON SCHEDULE EVERY 1 HOUR -DO -BEGIN - UPDATE product_stats SET - total_sales = (SELECT SUM(amount) FROM orders WHERE product_id = product_stats.product_id), - last_updated = NOW(); -END; -``` - -This event will update sales statistics every hour. - -**Breaking down the syntax:** - -- `ON SCHEDULE EVERY 1 HOUR` — execute every hour -- `BEGIN ... END` — block of multiple SQL statements - -**Interval options:** - -- `EVERY 1 MINUTE` — every minute -- `EVERY 1 HOUR` — every hour -- `EVERY 1 DAY` — every day -- `EVERY 1 WEEK` — every week -- `EVERY 1 MONTH` — every month -- `EVERY 30 SECOND` — every 30 seconds - - - - - -```sql -SELECT cron.schedule( - 'update_statistics_hourly', - '0 * * * *', - $$ - UPDATE product_stats SET - total_sales = (SELECT SUM(amount) FROM orders WHERE product_id = product_stats.product_id), - last_updated = NOW() - $$ -); -``` - -This event will update sales statistics every hour (at the start of each hour). - -**Schedule examples:** - -- `'*/5 * * * *'` — every 5 minutes -- `'0 * * * *'` — every hour (at the start of the hour) -- `'0 0 * * *'` — every day at midnight -- `'0 0 * * 0'` — every Sunday at midnight -- `'0 9 1 * *'` — first day of each month at 9:00 AM - - - -## Event with Limited Duration - -Sometimes you need an event to work only during a specific period: - - - -```sql-executable -CREATE EVENT seasonal_discount -ON SCHEDULE EVERY 1 DAY -STARTS '2025-12-01 00:00:00' -ENDS '2025-12-31 23:59:59' -DO - UPDATE products SET price = price * 0.9 WHERE category = 'seasonal'; -``` - -This event will apply a 10% discount to seasonal products every day during December 2025. - -**New elements:** - -- `STARTS` — start of the event's active period -- `ENDS` — end of the event's active period - -After the specified date, the event will automatically stop executing. - - - - - -Pg_cron doesn't have built-in support for automatic task termination, but you can include date checking in the command itself: - -```sql -SELECT cron.schedule( - 'seasonal_discount', - '0 0 * * *', - $$ - UPDATE products - SET price = price * 0.9 - WHERE category = 'seasonal' - AND CURRENT_DATE BETWEEN '2025-12-01' AND '2025-12-31' - $$ -); -``` - -Alternatively, you can create a task to remove the event at the end of the period: - -```sql --- Create a task to remove the event -SELECT cron.schedule( - 'remove_seasonal_discount', - '0 0 1 1 *', -- January 1st at midnight - $$SELECT cron.unschedule('seasonal_discount')$$ -); -``` - - - -## Viewing Existing Events - - - -To see all created events: - -```sql -SHOW EVENTS; -``` - -To view events in a specific database: - -```sql -SHOW EVENTS FROM your_database_name; -``` - - - - - -To see all scheduled tasks: - -```sql -SELECT * FROM cron.job; -``` - -This will return a table with all tasks, including their schedule and commands. - -To view task execution history: - -```sql -SELECT * FROM cron.job_run_details -ORDER BY start_time DESC -LIMIT 10; -``` - - - -## Managing Events - - - -**Temporarily disable an event:** - -```sql -ALTER EVENT cleanup_old_logs DISABLE; -``` - -**Enable an event:** - -```sql -ALTER EVENT cleanup_old_logs ENABLE; -``` - -**Change event schedule:** - -```sql -ALTER EVENT cleanup_old_logs -ON SCHEDULE EVERY 2 HOUR; -``` - -**Delete an event:** - -```sql -DROP EVENT IF EXISTS cleanup_old_logs; -``` - - - - - -**Remove a scheduled task:** - -```sql -SELECT cron.unschedule('cleanup_old_logs'); -``` - -Or by job ID: - -```sql -SELECT cron.unschedule(42); -- where 42 is the jobid from cron.job table -``` - -**Modify a task:** - -In pg_cron, you can't modify an existing task directly. You need to remove the old one and create a new one: - -```sql --- Remove the old one -SELECT cron.unschedule('cleanup_old_logs'); - --- Create a new one with updated schedule -SELECT cron.schedule( - 'cleanup_old_logs', - '0 */2 * * *', -- Every 2 hours - 'DELETE FROM logs WHERE created_at < NOW() - INTERVAL ''30 days''' -); -``` - - - -## Important Considerations When Working with Events - - - -1. **Access privileges**: Creating events requires the `EVENT` privilege. - -2. **Time zone**: Events execute according to the database server's time zone. - -3. **Performance**: Avoid creating events with very short intervals (every minute), as this can impact performance. - - - - - -1. **Access privileges**: Using pg_cron typically requires superuser privileges or special configuration. - -2. **Time zone**: Pg_cron tasks execute according to PostgreSQL's time zone (check with `SHOW timezone;`). - -3. **Performance**: Pg_cron checks the schedule every second, so the minimum precision is 1 minute. - -4. **Logging**: All task executions are saved in the `cron.job_run_details` table, which is useful for debugging. - - - -## Self-Check - -What is the minimum interval you can use for recurring events? - - -Scheduled events are a powerful tool for automating routine database tasks. They help maintain data cleanliness, update statistics, and perform maintenance operations without developer intervention! 🚀 diff --git a/course/module-0/intro-community/article.md b/course/module-0/intro-community/article.md index 9cf01f8..4bf0166 100644 --- a/course/module-0/intro-community/article.md +++ b/course/module-0/intro-community/article.md @@ -1,31 +1,21 @@ --- meta: - title: 'SQL Academy Community' - description: 'Information about our SQL community and the purposes for which it is organized, as well as available ways to contact the administration of this service.' + title: "Contact SQL Academy" + description: "How to reach the SQL Academy team and where to find more SQL learning content." --- -# Community +# Contact -We understand that communication is a very important part of the educational process, so we offer to join our community, where -you can get help and support from other students or suggest yourself in case of questions from other members of the community. +For any question about the platform, suggestions on course content, or issues with a premium account, write to us at +**[feedback@sql-academy.org](mailto:feedback@sql-academy.org)**. -Communication is organized through: +We read every message and reply within one to two working days. -- **chat on Telegram** -- **VK community** +## More SQL content -On the community page, we post information on the latest and most important updates. +Bite-sized SQL tips, query patterns and behind-the-scenes posts in English are on Instagram: +**@sqlacademyorg_eng**. -There are **Telegram** chat for communication between participants. +## Ready to start -## Problem solving - -For questions that arise during the operation of the service, comments and recommendations on the content of the course, or if there are problems with paying for a premium account, you can use -the following communication methods: - -- Write a letter to - **[feedback@sql-academy.org](mailto:feedback@sql-academy.org)** -- Write a message to the community - ** VK community** - -We are glad to see you in our community 😍 +That's it for the intro — the next chapter dives straight into SQL. Good luck, and have fun! diff --git a/course/module-0/intro-intro/article.md b/course/module-0/intro-intro/article.md index 0f17893..c43180e 100644 --- a/course/module-0/intro-intro/article.md +++ b/course/module-0/intro-intro/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Introduction to the SQL course' - description: 'Information about our free online SQL course, support for working on various devices and the option of purchasing a premium account' + title: "Introduction to the SQL course" + description: "Information about our free online SQL course, support for working on various devices and the option of purchasing a premium account" --- # About the course @@ -14,7 +14,7 @@ To achieve this goal, the course is equipped with a large number of exercises th to think much when making queries to databases. During the course, we strongly recommend that you cultivate a "growth mindset": if you encounter any difficulties trying -to understand a new topic or doing exercises, try to transform the frustrating experience into a productive one. +to understand a new topic or doing exercises, try to transform the frustrating experience into a productive one.\ And the most important thing in this course is **have fun!** ## Take the course publicly @@ -25,26 +25,26 @@ You can use the hashtag `#sql-academy` if you want. ## Device support -This course is designed to pass from a computer and laptop - the most optimal devices for writing SQL queries. The course can also be taken from a tablet or from a phone, +This course is designed to be taken on a computer or laptop — the best devices for writing SQL queries. The course can also be taken on a tablet or phone, but some functionality may not be available or work incorrectly. Please treat this with understanding. ## How our site is organized -![How our site is organized](https://sql-academy.org/static/guidePage/intro-intro/connections.webp 'How our site is organized') +![How our site is organized](https://sql-academy.org/static/guidePage/intro-intro/connections.webp "How our site is organized") There are four main sections on our resource, each of which will be useful in different ways: -- ** Course ** - is your step-by-step assistant when learning SQL. It presents consistent, structured materials, as well as related exercises to consolidate knowledge. -- **Advanced courses** - are separate practice-oriented programs for those who already know the basics and want to go deeper into applied topics, such as SQL query optimization or data analysis. -- **Trainer ** the simulator is a tool to test your knowledge. The tasks in it are ranked by difficulty, so you can choose the ones that are suitable for your current level. - Also, solving tasks from the simulator is necessary to obtain a certificate confirming knowledge in the field of SQL. -- **Sandbox ** - is a space for free acquaintance with the structure of our databases. +- ** Course ** - is your step-by-step assistant when learning SQL. It presents consistent, structured materials, as well as related exercises to consolidate knowledge. +- **Advanced courses** - are separate practice-oriented programs for those who already know the basics and want to go deeper into applied topics, such as SQL query optimization or data analysis. +- **Trainer ** the simulator is a tool to test your knowledge. The tasks in it are ranked by difficulty, so you can choose the ones that are suitable for your current level. + Also, solving tasks from the simulator is necessary to obtain a certificate confirming knowledge in the field of SQL. +- **Sandbox ** - is a space for free acquaintance with the structure of our databases. In addition, the header includes a global search that helps you find materials across all parts of the platform: courses, tasks, and functions from the handbook. ## Premium account -The basic course, trainer, and sandbox are available for free. A Premium account is an optional upgrade for learners who want to go deeper and use all the platform’s features. +The basic course, trainer, and sandbox are available for free. A Premium account is an optional upgrade for learners who want to go deeper and use all the platform’s features. With a Premium account, you get: @@ -61,7 +61,7 @@ Purchasing Premium also supports the development of SQL Academy and helps us cre The trainer certificate confirms that you have not only studied the theory but can also solve practical SQL tasks independently. You can add it to your résumé or portfolio, and anyone can verify its authenticity using the public link. -The certificate becomes available after you independently solve 50 tasks in the **Trainer**. Tasks for which you viewed a ready-made solution do not count. +The certificate becomes available after you independently solve 40 tasks in the **Trainer**. Tasks for which you viewed a ready-made solution do not count. You can track the number of independently solved tasks using the progress bar in the trainer. diff --git a/course/module-0/intro-structure-of-course/article.md b/course/module-0/intro-structure-of-course/article.md index 84b13df..28f02c2 100644 --- a/course/module-0/intro-structure-of-course/article.md +++ b/course/module-0/intro-structure-of-course/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Course structure' - description: 'Detailed information about this SQL course' + title: "Course structure" + description: "Detailed information about this SQL course" --- # Course structure @@ -28,13 +28,13 @@ SELECT 'Hi, I am code playground 😊' AS hello; If it has an active blue button, then this code can be executed. When you click on the request execution button, the code will open in a new tab in the sandbox. -![Description of the block with executable code](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_codeplayground_description.png 'Description of the block with executable code') +![Description of the block with executable code](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_codeplayground_description.png "Description of the block with executable code") ### Self-testing tasks It is strongly recommended not to skip the tasks at the end of each article, they look like this: -![Description of self-test tasks](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_exercises_description.png 'Description of self-test tasks') +![Description of self-test tasks](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_exercises_description.png "Description of self-test tasks") It is recommended to solve problems while logged in, so all your solutions will be saved. @@ -44,16 +44,16 @@ We have a smart assistant powered by artificial intelligence that will gladly he **How to interact with the assistant:** -- **Select text** on the page — an "Explain" button will appear for additional explanations of the selected text fragment +- **Select text** on the page — an "Explain" button will appear for additional explanations of the selected text fragment - ![Clarify button when selecting text](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_ai_explain.png 'Clarify button when selecting text') + ![«Explain» button when text is selected](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_ai_explain.png "«Explain» button when text is selected") -- **Quick actions** in the assistant window, for example "Ask a question" to check yourself on the current topic +- **Quick actions** in the assistant window, for example "Ask a question" to check yourself on the current topic - ![AI assistant window with quick actions](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_ai_window.png 'AI assistant window with quick actions') + ![AI assistant window with quick actions](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_ai_window.png "AI assistant window with quick actions") -- **Error explanations** — if you get an error while executing an SQL query in exercises, the assistant will help you understand the reason and suggest how to fix your query +- **Error explanations** — if you get an error while executing an SQL query in exercises, the assistant will help you understand the reason and suggest how to fix your query - ![AI assistant explains SQL query error](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_ai_explain_error.png 'AI assistant explains SQL query error') + ![AI assistant explaining SQL query error](https://sql-academy.org/static/guidePage/intro-structure-of-course/en_ai_explain_error.png "AI assistant explaining SQL query error") -The assistant works for **registered users**. Each user gets a few free requests, and [premium users](https://sql-academy.org/premium) get unlimited requests! 😊 +The assistant works for **registered users**. Each user gets a few free requests, and premium users get unlimited requests! 😊 diff --git a/course/module-1/basic-database-concepts/article.md b/course/module-1/basic-database-concepts/article.md index 998e908..da02155 100644 --- a/course/module-1/basic-database-concepts/article.md +++ b/course/module-1/basic-database-concepts/article.md @@ -1,43 +1,50 @@ --- meta: - title: 'Databases and DBMS' - description: 'Definition of database and database management system. How databases work. Rating and popularity of relational databases. Features of relational databases. SQL query language.' + title: "Databases and DBMS" + description: "Definition of database and database management system. How databases work. Rating and popularity of relational databases. Features of relational databases. SQL query language." --- # Databases and DBMS Before we start learning SQL, let's get acquainted with the basic concepts -about databases. This will help us to understand the scope of SQL and its environment. -execution. +of databases. This will help us understand the scope of SQL and the environment it operates in. > A database is a set of data stored in a structured way In fact, this is just a repository of some information, nothing more. Databases themselves would be of no interest if there were no database management systems. -> database management system is a set of language and software tools that performs -> access to data, allows them to be created, modified and deleted, provides -> data security, etc. +> A database management system is a set of software tools that provides +> access to data, allows it to be created, modified and deleted, ensures +> data security, and so on. -In simpler terms, a DBMS is a system that allows -create databases and manipulate information from them. +In simpler terms, a DBMS is a system that lets you +create databases and manipulate the information in them. The simplest scheme for working with a database: -![Database operation scheme](https://sql-academy.org/static/guidePage/basic-database-concepts/en_schema_of_db_work.png 'title') +![Database operation scheme](https://sql-academy.org/static/guidePage/basic-database-concepts/en_schema_of_db_work.png "title") ## DBMS rating -At the moment, the rating of database management systems based on db-engines is as follows: +At the moment, the rating of database management systems is as follows: -- `Oracle` - relational DBMS -- `MySQL` - relational DBMS -- `Microsoft SQL Server` - relational DBMS -- `PostgreSQL` - relational DBMS -- `MongoDB` - document-oriented databases -- `Redis` - key-value databases -- `Snowflake` - cloud relational DBMS -- `Elasticsearch` - search engine -- `IBM Db2` - relational DBMS -- `SQLite` - relational DBMS +- `Oracle` - relational DBMS +- `MySQL` - relational DBMS +- `Microsoft SQL Server` - relational DBMS +- `PostgreSQL` - relational DBMS +- `MongoDB` - document-oriented databases +- `Redis` - key-value databases +- `Snowflake` - cloud relational DBMS +- `Elasticsearch` - search engine +- `IBM Db2` - relational DBMS +- `SQLite` - relational DBMS It can be noted that 7 of the 10 most popular DBMS are relational. You made the right choice to study them 😉. + +Let's check how we learned the topic, choose the correct statement: + +1. The DBMS does not interact with the database in any way. — Database management systems (DBMS) allow you to manage, modify and delete databases. So the DBMS interacts with the database, the diagram above shows the scheme of their work. + +2. **Correct answer:** The DBMS manages the data stored in the database — A database is just a collection of data. You really need a database management system to manage them. + +3. To interact with all DBMS, you can use the SQL language — DBMS are different and not all of them use the SQL query language. SQL is the standard for relational DBMS. diff --git a/course/module-1/database-types/article.md b/course/module-1/database-types/article.md index 3d114ac..65af031 100644 --- a/course/module-1/database-types/article.md +++ b/course/module-1/database-types/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Types of databases' - description: 'Types and classifications of databases, the most popular type of database management systems' + title: "Types of databases" + description: "Types and classifications of databases, the most popular type of database management systems" --- # Types of databases @@ -17,6 +17,8 @@ Of course, we will pay special attention to relational databases in the future. There are quite a lot of database classifications, but let's focus on the most popular ones: -- Relational databases -- Key-value databases -- Document-oriented databases +| Database type | Description | +| ----------------- | ---------------------------------------- | +| Relational | Data in linked tables — rows and columns | +| Key-value | Fast access to a value by its key | +| Document-oriented | Flexible documents in JSON format | diff --git a/course/module-1/document-oriented-databases/article.md b/course/module-1/document-oriented-databases/article.md index 34792d9..827d991 100644 --- a/course/module-1/document-oriented-databases/article.md +++ b/course/module-1/document-oriented-databases/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Document-oriented databases' - description: 'Definition of document-oriented databases, examples of data storage, features, and a rating of popular document-oriented DBMS.' + title: "Document-oriented databases" + description: "Definition of document-oriented databases, examples of data storage, features, and a rating of popular document-oriented DBMS." --- # Document-oriented databases diff --git a/course/module-1/intro-sql/article.md b/course/module-1/intro-sql/article.md index bd248e3..516e7c2 100644 --- a/course/module-1/intro-sql/article.md +++ b/course/module-1/intro-sql/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Introduction to SQL" - description: "Defining the SQL language. Dialects (extensions) of SQL. Differences between T-SQL, PL/SQL, PL/pgSQL." + title: "Introduction to SQL" + description: "Defining the SQL language. Dialects (extensions) of SQL. Differences between T-SQL, PL/SQL, PL/pgSQL." --- # Introduction to SQL @@ -12,41 +12,53 @@ Communication with relational DBMS happens in SQL. It is used to perform all the **Data** -- `SELECT` — extract data from a database -- `INSERT` — insert records into a database -- `UPDATE` — update records in a database -- `DELETE` — delete records from a database +- `SELECT` — Extract data from a database +- `INSERT` — Insert records into a database +- `UPDATE` — Update records in a database +- `DELETE` — Delete records from a database **Structure** -- `CREATE DATABASE` — create new databases -- `CREATE TABLE` — create new tables in a database +- `CREATE DATABASE` — Create new databases +- `CREATE TABLE` — Create new tables in a database **Logic and access** -- `CREATE PROCEDURE` — create stored procedures -- `CREATE VIEW` — create views -- `GRANT` — set permissions for tables, procedures, and views +- `CREATE PROCEDURE` — Create stored procedures +- `CREATE VIEW` — Create views +- `GRANT` — Set permissions for tables, procedures, and views ## SQL dialects (SQL extensions) SQL is a universal language for all relational database management systems, but many DBMS make changes to the language they use, thus deviating from the standard. Such languages are called dialects or extensions of the language. -Here are some of them: +Here are some of them. As an example, let's see how each of these DBMS selects the first 3 rows. -- T-SQL - Microsoft SQL Server dialect -- PL/SQL - Oracle Database dialect -- PL/pgSQL - PostgreSQL dialect +| Dialect | DBMS | Example | +| -------- | -------------------- | ------------------- | +| T-SQL | Microsoft SQL Server | `SELECT TOP 3 name` | +| PL/SQL | Oracle Database | `WHERE ROWNUM <= 3` | +| MySQL | MySQL | `name LIMIT 3` | +| PL/pgSQL | PostgreSQL | `name LIMIT 3` | ### Which dialect to learn? If you know that you need to learn SQL, you should learn standard SQL. However, if you already know which specific database you will be working with, it is probably best to learn its SQL dialect and just know that different databases may use slightly different syntax. In our course, we offer you a choice between MySQL DBMS and PostgreSQL DBMS, as the 2 most popular solutions. -You can pick a DBMS and switch it at any time in one of the following ways: +Try picking one right now — every example and exercise in the course will adapt to your choice: -- in the gear icon menu in the site header -- in the code editor interface +**MySQL** - ![SQL code editor interface](https://sql-academy.org/static/guidePage/intro-sql/en_changing_dbms.png "SQL code editor interface") +- The web classic: easy to start, running everywhere +- The most widespread open-source DBMS in the world +- Powers WordPress, YouTube and Booking.com + +**PostgreSQL** + +- Power and precision: the startup favourite +- Rich syntax and strict adherence to the SQL standard +- Chosen by Instagram, Spotify and Reddit + +You can switch the DBMS at any time — right here, in the gear icon menu in the site header or in the code editor. diff --git a/course/module-1/key-value-databases/article.md b/course/module-1/key-value-databases/article.md index 7d3dda9..7522378 100644 --- a/course/module-1/key-value-databases/article.md +++ b/course/module-1/key-value-databases/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Key-value databases' - description: 'Key-value databases are a type of database that store data as a collection of key-value pairs, where the key serves as a unique identifier. Learn about their advantages, disadvantages, and a ranking of popular key-value databases.' + title: "Key-value databases" + description: "Key-value databases are a type of database that store data as a collection of key-value pairs, where the key serves as a unique identifier. Learn about their advantages, disadvantages, and a ranking of popular key-value databases." --- # Key-value databases diff --git a/course/module-1/relation-databases/article.md b/course/module-1/relation-databases/article.md index 86c6b6f..9ecf1af 100644 --- a/course/module-1/relation-databases/article.md +++ b/course/module-1/relation-databases/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Relational databases' - description: 'The concept of relational databases, their features and principles of operation. Ranking relational databases by popularity.' + title: "Relational databases" + description: "The concept of relational databases, their features and principles of operation. Ranking relational databases by popularity." --- # Relational databases diff --git a/course/module-1/structure-of-relation-databases/article.md b/course/module-1/structure-of-relation-databases/article.md index fdf592a..6d37951 100644 --- a/course/module-1/structure-of-relation-databases/article.md +++ b/course/module-1/structure-of-relation-databases/article.md @@ -1,12 +1,12 @@ --- meta: - title: 'Structure of Relational Databases' - description: 'Structure of tables in relational databases, concepts of records and attributes. Definition of primary and foreign keys.' + title: "Structure of a Relational Database: Tables, Records and Keys" + description: "How a relational database is organized inside: tables, records and attributes, primary and foreign keys, column data types — explained with examples and exercises." --- # Structure of Relational Databases -We have briefly introduced ourselves to relational databases in the previous article. But +We have briefly introduced ourselves to relational databases in the previous article. But a superficial understanding is not enough for us, is it? Let's go beyond the surface and delve deeper into the structure and terminology of relational databases. @@ -17,7 +17,7 @@ In relational databases, information is stored in tables linked to each other. T - rows, which are called "records" - columns, which are called "fields" or "attributes" -![Table Structure](https://sql-academy.org/static/guidePage/structure-of-relation-databases/en_structure_db.png 'Table Structure') +![Table Structure](https://sql-academy.org/static/guidePage/structure-of-relation-databases/en_structure_db.png "Table Structure") In each table, each column has a predetermined data type. For example, these types can be: @@ -28,22 +28,22 @@ In each table, each column has a predetermined data type. For example, these typ And each row in the table must have the corresponding type for each column. The DBMS will not allow an attempt to add an arbitrary string to a field with the `DATETIME` type. -To find out attribute data types, you can execute an SQL command and specify the table name. +To find out attribute data types, you can execute an SQL command and specify the table name: -For MySQL, you can execute the `DESCRIBE` SQL command: +**MySQL** ```sql DESCRIBE FamilyMembers ``` -| Field | Type | Null | Key | -| ----------- | ----------- | ---- | --- | -| member_id | int | NO | PRI | -| status | varchar(50) | NO | | -| member_name | varchar(50) | NO | | -| birthday | datetime | NO | | +| Field | Type | Null | Key | Default | Extra | +| ----------- | ----------- | ---- | --- | ------- | ----- | +| member_id | int | NO | PRI | | | +| status | varchar(50) | NO | | | | +| member_name | varchar(50) | NO | | | | +| birthday | datetime | NO | | | | -For PostgreSQL, you can use an SQL query to the information schema: +**PostgreSQL** ```sql SELECT column_name, data_type, is_nullable @@ -61,6 +61,8 @@ WHERE table_name = 'familymembers' Alternatively, you can look at the ERD diagram of the database schema: +Family database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/structure-of-relation-databases). + ## Primary Key Any database management system has a built-in system of data integrity and consistency. This system works on a set of rules defined in the database schema. @@ -83,10 +85,18 @@ The table with the foreign key is called the child table, and the table with the The foreign key rule guarantees that when creating records in the child table, the value of the field that is the foreign key exists in the parent table. -![Examples of foreign keys](https://sql-academy.org/static/guidePage/structure-of-relation-databases/en_keys.png 'Examples of foreign keys') +![Examples of foreign keys](https://sql-academy.org/static/guidePage/structure-of-relation-databases/en_keys.png "Examples of foreign keys") The presence of a foreign key is the same optional requirement as in the case of a primary key. If the foreign key is not defined, the database management system will still work, but it will not verify that, for example, when creating a record in the `Purchase` table, the `buyer_id` and `good_id` fields contain values that are defined in the corresponding tables in the `id` field. + +Which of the following statements is **false** regarding keys in relational databases? + +1. There can only be one primary key in each table — There can only be one primary key in each table, which uniquely identifies a record in the table. The primary key can consist of multiple fields in the table, but there is only one primary key. + +2. A table can contain multiple foreign keys or no foreign keys at all — Defining a foreign key constraint is optional, so a table may not have any foreign keys. At the same time, if a table has multiple fields that reference the identifiers of other tables, we can define multiple foreign keys. + +3. **Correct answer:** The purpose of primary key rules and foreign key rules is the same — The purposes of primary key rules and foreign key rules are different. The primary key ensures the uniqueness of each record within a single table, while the foreign key is used to maintain referential integrity. diff --git a/course/module-2/aggregate-functions/article.md b/course/module-2/aggregate-functions/article.md index 4f0545c..eda7c2b 100644 --- a/course/module-2/aggregate-functions/article.md +++ b/course/module-2/aggregate-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Aggregate Functions' - description: 'Aggregate functions in SQL queries, syntax, and examples' + title: "Aggregate Functions" + description: "Aggregate functions in SQL queries, syntax, and examples" --- # Aggregate Functions @@ -25,6 +25,12 @@ SELECT home_type, AVG(price) as avg_price FROM Rooms GROUP BY home_type ``` +| home_type | avg_price | +| --------------- | --------- | +| Private room | 89.4286 | +| Entire home/apt | 148.6667 | +| Shared room | 40 | + ## Description of aggregate functions | Function | Description | @@ -35,50 +41,50 @@ GROUP BY home_type | `MIN(table_field)` | Returns the minimum value | | `MAX(table_field)` | Returns the maximum value | -> Aggregate functions apply to values that are not `NULL`. The exception is the `COUNT(*)` function.. +> Aggregate functions apply to values that are not `NULL`. The exception is the `COUNT(*)` function. ## Examples - +Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/aggregate-functions). - Find the number of each type of home and sort the resulting list in descending order: - ```sql - SELECT home_type, COUNT(*) as amount FROM Rooms - GROUP BY home_type - ORDER BY amount DESC - ``` - - | home_type | amount | - | --------------- | ------ | - | Private room | 28 | - | Entire home/apt | 21 | - | Shared room | 1 | - -- For each room, find the latest end date of reservations(the `end_date` field) - - ```sql - SELECT room_id, MAX(end_date) AS last_end_date FROM Reservations - GROUP BY room_id - ``` - - | room_id | last_end_date | - | ------- | -------------------- | - | 1 | 2019-02-04T12:00:00Z | - | 2 | 2020-03-23T09:00:00Z | - | 13 | 2020-04-21T10:00:00Z | - | 16 | 2019-06-24T10:00:00Z | - | 21 | 2020-02-29T10:00:00Z | - | 19 | 2020-05-02T10:00:00Z | - | 8 | 2020-01-21T12:00:00Z | - | 7 | 2019-09-17T10:00:00Z | - | 5 | 2020-05-15T10:00:00Z | - | 50 | 2019-11-25T11:00:00Z | - | 49 | 2020-06-11T10:00:00Z | - | 48 | 2019-11-10T10:00:00Z | - | 32 | 2020-01-18T13:00:00Z | - | 17 | 2019-11-05T09:00:00Z | - | 25 | 2020-04-22T09:00:00Z | - | 14 | 2020-02-12T10:00:00Z | - | 39 | 2019-12-09T10:00:00Z | - | 38 | 2020-03-23T10:00:00Z | + ```sql + SELECT home_type, COUNT(*) as amount FROM Rooms + GROUP BY home_type + ORDER BY amount DESC + ``` + + | home_type | amount | + | --------------- | ------ | + | Private room | 28 | + | Entire home/apt | 21 | + | Shared room | 1 | + +- For each room, find the latest end date of reservations (the `end_date` field) + + ```sql + SELECT room_id, MAX(end_date) AS last_end_date FROM Reservations + GROUP BY room_id + ``` + + | room_id | last_end_date | + | ------- | ------------------------ | + | 1 | 2019-02-04T12:00:00.000Z | + | 2 | 2020-03-23T09:00:00.000Z | + | 13 | 2020-04-21T10:00:00.000Z | + | 16 | 2019-06-24T10:00:00.000Z | + | 21 | 2020-02-29T10:00:00.000Z | + | 19 | 2020-05-02T10:00:00.000Z | + | 8 | 2020-01-21T12:00:00.000Z | + | 7 | 2019-09-17T10:00:00.000Z | + | 5 | 2020-05-15T10:00:00.000Z | + | 50 | 2019-11-25T11:00:00.000Z | + | 49 | 2020-06-11T10:00:00.000Z | + | 48 | 2019-11-10T10:00:00.000Z | + | 32 | 2020-01-18T13:00:00.000Z | + | 17 | 2019-11-05T09:00:00.000Z | + | 25 | 2020-04-22T09:00:00.000Z | + | 14 | 2020-02-12T10:00:00.000Z | + | 39 | 2019-12-09T10:00:00.000Z | + | 38 | 2020-03-23T10:00:00.000Z | diff --git a/course/module-2/basic-syntax-sql-query/article.md b/course/module-2/basic-syntax-sql-query/article.md index f5baddf..100442f 100644 --- a/course/module-2/basic-syntax-sql-query/article.md +++ b/course/module-2/basic-syntax-sql-query/article.md @@ -1,13 +1,13 @@ --- meta: - title: 'Basic SQL query syntax' - description: 'An example of simple SQL queries to a database. Using aliases in SQL queries.' + title: "Basic SQL query syntax" + description: "An example of simple SQL queries to a database. Using aliases in SQL queries." --- # Basic SQL query syntax One of the main functions of SQL is to get data samples from the DBMS. -To do this, SQL uses the `SELECT` operator. Let's look at a few simple queries with his participation. +To do this, SQL uses the `SELECT` operator. Let's look at a few simple queries that use it. ## Output of arbitrary values @@ -15,7 +15,7 @@ To begin with, it is important to understand that using the `SELECT` operator, y but also arbitrary rows, numbers, dates, etc. For example, this way you can output an arbitrary string: ```sql -SELECT "Hello world" +SELECT 'Hello world' ``` ## Output of all data from the table @@ -23,19 +23,21 @@ SELECT "Hello world" The `*` symbol is used to output all fields from a specific table. Let's take a look at the database schema and output the data from one of the tables. +Family database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/basic-syntax-sql-query). + ```sql SELECT * FROM FamilyMembers ``` -| member_id | status | member_name | birthday | -| --------- | --------- | ------------------ | --------------------- | -| 1 | father | Headley Quincey | 1960-05-13T00:00:00Z | -| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00Z | -| 3 | son | Andie Quincey | 1983-06-05T00:00:00Z | -| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00Z | -| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00Z | -| 6 | father | Ernest Forrest | 1961-09-11T00:00:00Z | -| 7 | mother | Constance Forrest | 1968-09-06T00:00:00Z | +| member_id | status | member_name | birthday | +| --------- | -------- | ----------------- | ------------------------ | +| 1 | father | Headley Quincey | 1960-05-13T00:00:00.000Z | +| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00.000Z | +| 3 | son | Andie Quincey | 1983-06-05T00:00:00.000Z | +| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00.000Z | +| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00.000Z | +| 6 | father | Ernest Forrest | 1961-09-11T00:00:00.000Z | +| 7 | mother | Constance Forrest | 1968-09-06T00:00:00.000Z | ## Output of data from certain columns of the table @@ -46,15 +48,15 @@ this can be done by listing the column names separated by commas: SELECT member_id, member_name FROM FamilyMembers ``` -| member_id | member_name | -| --------- | ------------------ | -| 1 | Headley Quincey | -| 2 | Flavia Quincey | -| 3 | Andie Quincey | -| 4 | Lela Quincey | -| 5 | Annie Quincey | -| 6 | Ernest Forrest | -| 7 | Constance Forrest | +| member_id | member_name | +| --------- | ----------------- | +| 1 | Headley Quincey | +| 2 | Flavia Quincey | +| 3 | Andie Quincey | +| 4 | Lela Quincey | +| 5 | Annie Quincey | +| 6 | Ernest Forrest | +| 7 | Constance Forrest | ## Aliases @@ -90,5 +92,5 @@ SELECT member_id, member_name Name FROM FamilyMembers This is our first lesson of the practical module. Before that, there were only theoretical ones aimed at filling potential gaps in the theory of relational databases. After each practical lesson, we offer a group of tasks for self-testing work in order to immediately practise the information received. -If you missed the module "Introduction", namely the article "Course structure", which described the principle of operation and interface of the block -"Tasks for self-testing", then we recommend to return to it. +If you missed the module "Introduction", namely the article "Course structure", which described the principle of operation and interface of the block +"Tasks for self-testing", then we recommend to return to it. diff --git a/course/module-2/conditional-where-operator/article.md b/course/module-2/conditional-where-operator/article.md index 6be2c2a..e82b14e 100644 --- a/course/module-2/conditional-where-operator/article.md +++ b/course/module-2/conditional-where-operator/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Conditional operator WHERE" - description: "Conditional operator WHERE in an SQL query. Logical and comparison operators. SELECT FROM WHERE examples" + title: "Conditional operator WHERE" + description: "Conditional operator WHERE in an SQL query. Logical and comparison operators. SELECT FROM WHERE examples" --- # Conditional operator WHERE @@ -20,40 +20,37 @@ WHERE row_limit_conditions For example, a query using the `WHERE` operator may look like this: - +**MySQL** -```sql-executable-Schedule +```sql SELECT * FROM Student WHERE first_name = "Grigorij" AND YEAR(birthday) > 2000; ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql SELECT * FROM Student WHERE first_name = 'Grigorij' AND EXTRACT(YEAR FROM birthday) > 2000; ``` - +| id | first_name | middle_name | last_name | birthday | address | +| --- | ---------- | ----------- | --------- | ------------------------ | ------------------------------- | +| 33 | Grigorij | Gennadevich | Kapustin | 2001-12-13T00:00:00.000Z | ul. Pervomajskaya, d. 45, kv. 6 | +| 65 | Grigorij | Kirillovich | Kolobov | 2003-07-17T00:00:00.000Z | ul. CHernova, d. 9, kv. 34 | This code snippet uses two conditions: - +**MySQL** - `first_name = "Grigorij"` — the student's first name must be "Grigorij" - `YEAR(birthday) > 2000` — birth year greater than 2000 - - - +**PostgreSQL** - `first_name = 'Grigorij'` — the student's first name must be "Grigorij" - `EXTRACT(YEAR FROM birthday) > 2000` — birth year greater than 2000 - - Between them is the logical operator `AND`, which requires both conditions to be met simultaneously. As a result, we get only those students who meet both criteria. ## Comparison operators @@ -64,7 +61,7 @@ To compare values in SQL, special operators are used. They allow you to check wh - `false` (same as 0) - `NULL` (if the comparison result is undefined, for example, when comparing with NULL) - +**MySQL** | Operator | Sign | Description | | :-------------------- | :----------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | @@ -78,9 +75,7 @@ To compare values in SQL, special operators are used. They allow you to check wh > The result of comparing any value with `NULL` is `NULL`. The exception is the equivalence operator. - - - +**PostgreSQL** | Operator | Sign | Description | | :-------------------- | :----------- | -------------------------------------------------------------------------------------------- | @@ -93,13 +88,11 @@ To compare values in SQL, special operators are used. They allow you to check wh > The result of comparing any value with `NULL` is `NULL`. - - Try playing with these operators in the sandbox yourself and see what results they give: - +**MySQL** -```sql-executable +```sql SELECT 2 = 1, 'a' = 'a', @@ -112,22 +105,26 @@ SELECT 8 >= 10; ``` - +| 2 = 1 | 'a' = 'a' | 1 \<=> NULL | NULL \<=> NULL | 2 \<> 2 | 3 \< 4 | 10 \<= 10 | 7 > 1 | 8 >= 10 | +| ----- | --------- | ----------- | -------------- | ------- | ------ | --------- | ----- | ------- | +| 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | - +**PostgreSQL** -```sql-executable +```sql SELECT - 2 = 1, - 'a' = 'a', - 2 <> 2, - 3 < 4, - 10 <= 10, - 7 > 1, - 8 >= 10; + 2 = 1 AS "2 = 1", + 'a' = 'a' AS "'a' = 'a'", + 2 <> 2 AS "2 <> 2", + 3 < 4 AS "3 < 4", + 10 <= 10 AS "10 <= 10", + 7 > 1 AS "7 > 1", + 8 >= 10 AS "8 >= 10"; ``` - +| 2 = 1 | 'a' = 'a' | 2 \<> 2 | 3 \< 4 | 10 \<= 10 | 7 > 1 | 8 >= 10 | +| ----- | --------- | ------- | ------ | --------- | ----- | ------- | +| false | true | false | true | true | true | false | ## Logical operators @@ -135,121 +132,114 @@ Logical operators are your helpers when you need to combine several conditions i - `AND` — both conditions must be true. - Imagine you are looking for flights that simultaneously meet two requirements: for example, the aircraft must be of a certain model, and depart from a specific city. The `AND` operator helps combine these conditions. - - + Imagine you are looking for flights that simultaneously meet two requirements: for example, the aircraft must be of a certain model, and depart from a specific city. The `AND` operator helps combine these conditions. - ```sql-executable - SELECT * FROM Trip - WHERE plane = 'Boeing' AND town_from = 'London'; - ``` + **MySQL** - + ```sql + SELECT * FROM Trip + WHERE plane = 'Boeing' AND town_from = 'London'; + ``` - + **PostgreSQL** - ```sql-executable - SELECT * FROM Trip - WHERE plane = 'Boeing' AND town_from = 'London'; - ``` + ```sql + SELECT * FROM Trip + WHERE plane = 'Boeing' AND town_from = 'London'; + ``` - + | id | company | plane | town_from | town_to | time_out | time_in | + | ---- | ------- | ------ | --------- | --------- | ------------------------ | ------------------------ | + | 7771 | 5 | Boeing | London | Singapore | 1900-01-01T01:00:00.000Z | 1900-01-01T11:00:00.000Z | + | 7773 | 5 | Boeing | London | Singapore | 1900-01-01T03:00:00.000Z | 1900-01-01T13:00:00.000Z | + | 7775 | 5 | Boeing | London | Singapore | 1900-01-01T09:00:00.000Z | 1900-01-01T20:00:00.000Z | + | 7777 | 5 | Boeing | London | Singapore | 1900-01-01T18:00:00.000Z | 1900-01-02T06:00:00.000Z | + | 8881 | 5 | Boeing | London | Paris | 1900-01-01T03:00:00.000Z | 1900-01-01T04:00:00.000Z | - This query will select only those flights where the aircraft model is `Boeing` and the departure city is `London`. + This query will select only those flights where the aircraft model is `Boeing` and the departure city is `London`. - If at least one of the conditions is not met (for example, the aircraft is not `Boeing` or the departure is not from `London`), such a flight will not be included in the result. + If at least one of the conditions is not met (for example, the aircraft is not `Boeing` or the departure is not from `London`), such a flight will not be included in the result. - `OR` — it's enough for at least one condition to be met. - The `OR` operator works as "or". If at least one of the conditions is true — the row will be included in the result. This is convenient when you want to see all flights that meet at least one of your criteria. + The `OR` operator works as "or". If at least one of the conditions is true — the row will be included in the result. This is convenient when you want to see all flights that meet at least one of your criteria. - + **MySQL** - ```sql-executable - SELECT * FROM Trip - WHERE town_to = 'Paris' OR plane = 'Airbus'; - ``` + ```sql + SELECT * FROM Trip + WHERE town_to = 'Paris' OR plane = 'Airbus'; + ``` - + **PostgreSQL** - + ```sql + SELECT * FROM Trip + WHERE town_to = 'Paris' OR plane = 'Airbus'; + ``` - ```sql-executable - SELECT * FROM Trip - WHERE town_to = 'Paris' OR plane = 'Airbus'; - ``` + | id | company | plane | town_from | town_to | time_out | time_in | + | ---- | ------- | ------ | --------- | ------- | ------------------------ | ------------------------ | + | 1100 | 4 | Boeing | Rostov | Paris | 1900-01-01T14:30:00.000Z | 1900-01-01T17:50:00.000Z | + | 8881 | 5 | Boeing | London | Paris | 1900-01-01T03:00:00.000Z | 1900-01-01T04:00:00.000Z | - + As a result, you will get all flights that arrive in `Paris`, as well as all flights on an `Airbus` aircraft (even if they don't fly to `Paris`). - As a result, you will get all flights that arrive in `Paris`, as well as all flights on an `Airbus` aircraft (even if they don't fly to `Paris`). - - If a flight is both on an `Airbus` and to `Paris` — it will also be included in the result. + If a flight is both on an `Airbus` and to `Paris` — it will also be included in the result. - `NOT` — the condition becomes opposite. - The `NOT` operator inverts the condition: if it was true, it becomes false, and vice versa. This is convenient when you want to exclude certain values. - - - - ```sql-executable - SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; - ``` + The `NOT` operator inverts the condition: if it was true, it becomes false, and vice versa. This is convenient when you want to exclude certain values. - + **MySQL** - + ```sql + SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; + ``` - ```sql-executable - SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; - ``` + **PostgreSQL** - + ```sql + SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; + ``` - This query will select all flights that arrive **not** in `Moscow`. + This query will select all flights that arrive **not** in `Moscow`. - That is, if the arrival city is `Moscow`, such a flight will not be included in the result. Everything else — will be included. + That is, if the arrival city is `Moscow`, such a flight will not be included in the result. Everything else — will be included. - `XOR` — this is an operator that helps select rows where only one of two conditions is met, but not both at the same time. - Suppose you want to find flights that either depart from `Moscow` or arrive in `Paris`, but not both options at the same time. Let's look at all possible cases: - - | Departs
from Moscow | Arrives
in Paris | Included
in result | Explanation | - | :-----------------------: | :--------------------: | :----------------------: | -------------------------------------------- | - | Yes | No | ✅ Yes | Only the first condition is met | - | No | Yes | ✅ Yes | Only the second condition is met | - | Yes | Yes | ❌ No | Both conditions are met — XOR excludes these | - | No | No | ❌ No | Neither condition is met | - - + Suppose you want to find flights that either depart from `Moscow` or arrive in `Paris`, but not both options at the same time. Let's look at all possible cases: - ```sql-executable - SELECT * FROM trip - WHERE town_from = 'Moscow' XOR town_to = 'Paris'; - ``` + | Departs
from Moscow | Arrives
in Paris | Included
in result | Explanation | + | :-----------------------: | :--------------------: | :----------------------: | -------------------------------------------- | + | Yes | No | ✅ Yes | Only the first condition is met | + | No | Yes | ✅ Yes | Only the second condition is met | + | Yes | Yes | ❌ No | Both conditions are met — XOR excludes these | + | No | No | ❌ No | Neither condition is met | -
+ **MySQL** - + ```sql + SELECT * FROM trip + WHERE town_from = 'Moscow' XOR town_to = 'Paris'; + ``` - ```sql-executable - SELECT * FROM trip - WHERE (town_from = 'Moscow' AND town_to != 'Paris') - OR (town_from != 'Moscow' AND town_to = 'Paris'); - ``` + **PostgreSQL** - + ```sql + SELECT * FROM trip + WHERE (town_from = 'Moscow' AND town_to != 'Paris') + OR (town_from != 'Moscow' AND town_to = 'Paris'); + ``` - + **MySQL** - > Note: the XOR operator is not available in all databases. If it's not available, you can use a combination of AND and OR. + > Note: the XOR operator is not available in all databases. If it's not available, you can use a combination of AND and OR. - + **PostgreSQL** - - - > PostgreSQL does not have the XOR operator, so a combination of AND and OR is used to achieve the same result. - - + > PostgreSQL does not have the XOR operator, so a combination of AND and OR is used to achieve the same result. ## Priority of logical operators @@ -266,9 +256,9 @@ It might seem that conditions will be checked simply from left to right, but thi Let's look at such an example: - +**MySQL** -```sql-executable +```sql SELECT * FROM Trip WHERE town_to = 'Paris' @@ -276,11 +266,9 @@ WHERE town_to = 'Paris' AND NOT town_from = 'Moscow'; ``` - - - +**PostgreSQL** -```sql-executable +```sql SELECT * FROM Trip WHERE town_to = 'Paris' @@ -288,7 +276,20 @@ WHERE town_to = 'Paris' AND NOT town_from = 'Moscow'; ``` - +| id | company | plane | town_from | town_to | time_out | time_in | +| ---- | ------- | ------ | --------- | --------- | ------------------------ | ------------------------ | +| 1100 | 4 | Boeing | Rostov | Paris | 1900-01-01T14:30:00.000Z | 1900-01-01T17:50:00.000Z | +| 1101 | 4 | Boeing | Paris | Rostov | 1900-01-01T08:12:00.000Z | 1900-01-01T11:45:00.000Z | +| 7771 | 5 | Boeing | London | Singapore | 1900-01-01T01:00:00.000Z | 1900-01-01T11:00:00.000Z | +| 7772 | 5 | Boeing | Singapore | London | 1900-01-01T12:00:00.000Z | 1900-01-02T02:00:00.000Z | +| 7773 | 5 | Boeing | London | Singapore | 1900-01-01T03:00:00.000Z | 1900-01-01T13:00:00.000Z | +| 7774 | 5 | Boeing | Singapore | London | 1900-01-01T14:00:00.000Z | 1900-01-02T06:00:00.000Z | +| 7775 | 5 | Boeing | London | Singapore | 1900-01-01T09:00:00.000Z | 1900-01-01T20:00:00.000Z | +| 7776 | 5 | Boeing | Singapore | London | 1900-01-01T18:00:00.000Z | 1900-01-02T08:00:00.000Z | +| 7777 | 5 | Boeing | London | Singapore | 1900-01-01T18:00:00.000Z | 1900-01-02T06:00:00.000Z | +| 7778 | 5 | Boeing | Singapore | London | 1900-01-01T22:00:00.000Z | 1900-01-02T12:00:00.000Z | +| 8881 | 5 | Boeing | London | Paris | 1900-01-01T03:00:00.000Z | 1900-01-01T04:00:00.000Z | +| 8882 | 5 | Boeing | Paris | London | 1900-01-01T22:00:00.000Z | 1900-01-01T23:00:00.000Z | What happens here: @@ -305,9 +306,9 @@ As a result, you get the following selection: If you want to change the order of condition checking or make it clearer, use **parentheses**. Everything in parentheses is executed first. For example, if you manually place parentheses according to the priorities of logical operators, it immediately becomes clear how the query will be executed! - +**MySQL** -```sql-executable +```sql SELECT * FROM Trip WHERE ( @@ -319,11 +320,9 @@ WHERE ( ); ``` - +**PostgreSQL** - - -```sql-executable +```sql SELECT * FROM Trip WHERE ( @@ -335,6 +334,10 @@ WHERE ( ); ``` - - Now try it yourself: suppose you want to get a list of flights that depart from `Paris` or on a `Boeing` aircraft, and fly **not** to `Moscow`. This can be done by correctly placing parentheses in the original query from the example. How would you do it? + +1. town_from = 'Paris' OR (plane = 'Boeing' AND NOT town_to = 'Moscow'); — This option will select all flights from Paris, as well as Boeing flights that do not fly to Moscow. The parentheses are placed incorrectly: flights from Paris will be included in the selection even if they fly to Moscow. + +2. **Correct answer:** (town_from = 'Paris' OR plane = 'Boeing') AND NOT town_to = 'Moscow'; — This query will select flights that either depart from Paris or are on Boeing, and do not fly to Moscow. + +3. town_from = 'Paris' OR plane = 'Boeing' AND NOT town_to = 'Moscow'; — This option without parentheses will not work as expected: AND will be executed first, then OR. This will lead to an incorrect result diff --git a/course/module-2/distinct-operator/article.md b/course/module-2/distinct-operator/article.md index 2b6383f..ebabe38 100644 --- a/course/module-2/distinct-operator/article.md +++ b/course/module-2/distinct-operator/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Duplicate elimination, operator DISTINCT' - description: 'Examples of what the SQL DISTINCT operator is needed for, excluding repetitions in SQL for one or more columns.' + title: "Duplicate elimination, operator DISTINCT" + description: "Examples of what the SQL DISTINCT operator is needed for, excluding repetitions in SQL for one or more columns." --- # Duplicate elimination, DISTINCT @@ -10,6 +10,8 @@ In some situations, an SQL query for selecting data may return duplicate rows. For example, let's retrieve the `class` field from the `Student_in_class` table in the database, where information about the school schedule is stored. +Schedule database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/distinct-operator). + ```sql SELECT class FROM Student_in_class; ``` @@ -28,6 +30,7 @@ SELECT class FROM Student_in_class; | 9 | | 9 | | 9 | +| 9 | | 8 | | 8 | | 8 | @@ -49,6 +52,7 @@ SELECT class FROM Student_in_class; | 6 | | 6 | | 6 | +| 6 | | 5 | | 5 | | 5 | @@ -120,7 +124,7 @@ SELECT DISTINCT class FROM Student_in_class; ## DISTINCT for multiple column -When using the `DISTINCT` operator for two or more columns, records that have identical values in all fields will be removed. +When using the DISTINCT operator for two or more columns, records that have identical values in all fields will be removed. So for such a table: diff --git a/course/module-2/groupping/article.md b/course/module-2/groupping/article.md index 5a0b2bc..81e4fe7 100644 --- a/course/module-2/groupping/article.md +++ b/course/module-2/groupping/article.md @@ -1,17 +1,59 @@ --- meta: - title: "Grouping, GROUP BY operator" - description: "The structure of an SQL query with the group by operator, grouping by multiple fields, and examples." + title: "Grouping, GROUP BY operator" + description: "The structure of an SQL query with the group by operator, grouping by multiple fields, and examples." --- # Grouping, GROUP BY operator Let's run a query: -```sql-executable-Airbnb +```sql SELECT id, home_type, has_tv, price FROM Rooms; ``` +**MySQL** + +| id | home_type | has_tv | price | +| --- | --------------- | ------ | ----- | +| 1 | Private room | 1 | 149 | +| 2 | Entire home/apt | 0 | 225 | +| 3 | Private room | 1 | 150 | +| 4 | Entire home/apt | 1 | 89 | +| 5 | Entire home/apt | 0 | 80 | +| 6 | Entire home/apt | 0 | 200 | +| 7 | Private room | 0 | 60 | +| 8 | Private room | 1 | 79 | +| 9 | Private room | 1 | 79 | +| 10 | Entire home/apt | 1 | 150 | +| 11 | Entire home/apt | 1 | 135 | +| 12 | Private room | 0 | 85 | +| 13 | Private room | 0 | 89 | +| 14 | Private room | 0 | 85 | +| 15 | Entire home/apt | 1 | 120 | +| 40 | Shared room | 1 | 40 | + +**PostgreSQL** + +| id | home_type | has_tv | price | +| --- | --------------- | ------ | ----- | +| 1 | Private room | true | 149 | +| 2 | Entire home/apt | false | 225 | +| 3 | Private room | true | 150 | +| 4 | Entire home/apt | true | 89 | +| 5 | Entire home/apt | false | 80 | +| 6 | Entire home/apt | false | 200 | +| 7 | Private room | false | 60 | +| 8 | Private room | true | 79 | +| 9 | Private room | true | 79 | +| 10 | Entire home/apt | true | 150 | +| 11 | Entire home/apt | true | 135 | +| 12 | Private room | false | 85 | +| 13 | Private room | false | 89 | +| 14 | Private room | false | 85 | +| 15 | Entire home/apt | true | 120 | +| 40 | Shared room | true | 40 | + This gives us information about each rented room. But what if we want to get information not about each record separately, but about the groups they form? For example, such groups can be records divided by the type of housing: @@ -39,11 +81,17 @@ GROUP BY grouping_fields; To group records by the type of housing, we need to specify `home_type` after `GROUP BY`, i.e., the field by which grouping will occur. -```sql-executable-Airbnb +```sql SELECT home_type FROM Rooms GROUP BY home_type ``` +| home_type | +| --------------- | +| Private room | +| Entire home/apt | +| Shared room | + > It should be noted that for `GROUP BY`, all `NULL` values are treated as equal, > i.e., when grouping by a field that contains `NULL` values, all such rows will be included in one group. @@ -55,44 +103,62 @@ When using `GROUP BY`, we can only output: - literals, i.e., values that are explicitly fixed. - We can output them because they are fixed values that do not depend on anything. - For example, + We can output them because they are fixed values that do not depend on anything. + For example, + + ```sql + SELECT home_type, 'literal' FROM Rooms + GROUP BY home_type + ``` - ```sql-executable-Airbnb - SELECT home_type, 'literal' FROM Rooms - GROUP BY home_type - ``` + | home_type | literal | + | --------------- | ------- | + | Private room | literal | + | Entire home/apt | literal | + | Shared room | literal | - aggregate function results, i.e. computed values based on a set of values. - We will cover more detailed information about aggregate functions in the next lesson. But for example, let's consider the aggregate function `AVG`. - The `AVG` function takes as an argument the name of the field we want to calculate the average value for each group based on. + We will cover more detailed information about aggregate functions in the next lesson. But for example, let's consider the aggregate function `AVG`. + The `AVG` function takes as an argument the name of the field we want to calculate the average value for each group based on. - ```sql-executable-Airbnb - SELECT home_type, AVG(price) as avg_price FROM Rooms - GROUP BY home_type - ``` + ```sql + SELECT home_type, AVG(price) as avg_price FROM Rooms + GROUP BY home_type + ``` - This query first divides all records from the `Rooms` table into 3 groups based on the `home_type` field. - Then, for each group, it adds up all the values taken from the `price` field of each record included in the current group, and then divides the resulting sum - by the number of records in that group. + | home_type | avg_price | + | --------------- | --------- | + | Private room | 89.4286 | + | Entire home/apt | 148.6667 | + | Shared room | 40 | + + This query first divides all records from the `Rooms` table into 3 groups based on the `home_type` field. + Then, for each group, it adds up all the values taken from the `price` field of each record included in the current group, and then divides the resulting sum + by the number of records in that group. - grouping fields. - We can output them because within one group, the fields on which grouping was performed are the same. + We can output them because within one group, the fields on which grouping was performed are the same. ## Grouping by 2 or more fields - We have already looked at how records in a table are grouped by one field. For additional illustration, - it looks something like this when the grouping field is `home_type`: +We have already looked at how records in a table are grouped by one field. For additional illustration, +it looks something like this when the grouping field is `home_type`: - ![Grouping by 1 field](https://sql-academy.org/static/guidePage/groupping/groupping_by_1_field.png 'Grouping by 1 field') +![Grouping by 1 field](https://sql-academy.org/static/guidePage/groupping/groupping_by_1_field.png "Grouping by 1 field") - When grouping by 2 or more fields, the principle remains the same, - only the resulting groups are additionally divided into smaller groups depending on the second grouping field. +When grouping by 2 or more fields, the principle remains the same, +only the resulting groups are additionally divided into smaller groups depending on the second grouping field. - Example of grouping by `home_type` and `has_tv`: +Example of grouping by `home_type` and `has_tv`: - ![Grouping by 2 field](https://sql-academy.org/static/guidePage/groupping/groupping_by_2_field.png 'Grouping by 2 field') +![Grouping by 2 field](https://sql-academy.org/static/guidePage/groupping/groupping_by_2_field.png "Grouping by 2 field") Let's test ourselves? When using the `GROUP BY` operator, what can display in `SELECT` statement? + +1. **Correct answer:** Only literals, aggregate function results, and grouping fields — When grouping in SELECT, you can only display literals, aggregate function results, and fields that were used for grouping. + +2. The same fields that we could display for each record in the table — When grouping in SELECT, you can only display literals, aggregate function results, and fields that were used for grouping. + +3. Only literals and aggregate function results — In addition to literals and aggregate function results, you can also display the fields that were used for grouping diff --git a/course/module-2/is-null-between-in-operators/article.md b/course/module-2/is-null-between-in-operators/article.md index 4eca923..1623704 100644 --- a/course/module-2/is-null-between-in-operators/article.md +++ b/course/module-2/is-null-between-in-operators/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'IS NULL, BETWEEN, IN Operators' - description: 'Syntax and usage examples of SQL IS NULL, BETWEEN, IN operators' + title: "IS NULL, BETWEEN, IN Operators" + description: "Syntax and usage examples of SQL IS NULL, BETWEEN, IN operators" --- # IS NULL, BETWEEN, IN Operators diff --git a/course/module-2/literals/article.md b/course/module-2/literals/article.md index 6313a75..83a6515 100644 --- a/course/module-2/literals/article.md +++ b/course/module-2/literals/article.md @@ -1,14 +1,14 @@ --- meta: - title: "Literals in SQL" - description: 'Literal — an explicitly specified fixed value, for example, the number 12 or the string "SQL". In MySQL, there are the following types of literals: numeric, string, boolean, NULL, bit, hexadecimal, and date and time literal.' + title: "Literals in SQL" + description: 'Literal — an explicitly specified fixed value, for example, the number 12 or the string "SQL". In MySQL, there are the following types of literals: numeric, string, boolean, NULL, bit, hexadecimal, and date and time literal.' --- # Literals in SQL In the last lesson, a string was output, and if we speak in a more formal language, then the so-called string literal. -```sql-executable +```sql SELECT 'Hello world' ``` @@ -24,33 +24,55 @@ The main types of literals in SQL are: ## String literals - +**MySQL** A string is a sequence of characters enclosed in single (') or double (") quotation marks. For example, `'this is a string'` and `"this is a string"`. - - - +**PostgreSQL** A string is a sequence of characters enclosed in single quotation marks ('). For example, `'this is a string'`. In PostgreSQL, double quotes (") are used for identifiers (table names, column names), and cannot be used for string literals. - +**MySQL** + +Strings can contain special sequences of characters starting with `"\"` (escape character). +They are needed in order for the DBMS to give ordinary symbols (letters and other signs) a new special meaning. For example, the sequence `"\n"` +literally means "new line", and without the preceding slash it would be the usual letter `"n"`. + +**PostgreSQL** Strings can contain special sequences of characters starting with `"\"` (escape character). They are needed in order for the DBMS to give ordinary symbols (letters and other signs) a new special meaning. For example, the sequence `"\n"` literally means "new line", and without the preceding slash it would be the usual letter `"n"`. -- ```sql-Family-executable +To use escape sequences in PostgreSQL, you need to use E-strings (with the `E` prefix): `E'string \n with newline'`. + +- ```sql SELECT 'Line Another line' as String ``` -- ```sql-Family-executable - SELECT 'Line \n Another line' as String - ``` + | String | + | ----------------- | + | Line Another line | + +- **MySQL** + + ```sql + SELECT 'Line \n Another line' as String + ``` + + **PostgreSQL** + + ```sql + SELECT E'Line \n Another line' as String + ``` + + | String | + | ---------------------- | + | Line
Another line | ## Numeric literals @@ -65,7 +87,7 @@ literally means "new line", and without the preceding slash it would be the usua For numeric literals, SQL has all the arithmetic operators we are familiar with: - +**MySQL** | Operator | Description | Example | | :--------: | :--------------- | :-------------- | @@ -76,9 +98,7 @@ For numeric literals, SQL has all the arithmetic operators we are familiar with: | `/` | Division | `1 / 2 = 0.5` | | `DIV` | Integer division | `10 DIV 4 = 2` | - - - +**PostgreSQL** | Operator | Description | Example | | :------: | :--------------- | :-------------- | @@ -88,36 +108,34 @@ For numeric literals, SQL has all the arithmetic operators we are familiar with: | `-` | Subtraction | `50 - 51 = -1` | | `/` | Division | `1 / 2 = 0.5` | - - Using these operators, you can construct any arithmetic expression by applying the standard rules of arithmetic. For example: -```sql-Family-executable +```sql SELECT (5 * 2 - 6) / 2 AS Result; ``` +| Result | +| ------ | +| 2 | + ## Date and Time Literals Date and time values can be represented as strings or numbers. - +**MySQL** For example, if we want to specify a date in a query, we can do this using the string `"1970-12-30"`, `"19701230"`, or the number `19701230`. In both cases, these values will be interpreted as the date "December 30th, 1970". - - - +**PostgreSQL** For example, if we want to specify a date in a query, we can do this using the string `'1970-12-30'`. - - Here is an example of using a date literal: -```sql-Family-executable +```sql SELECT * FROM FamilyMembers WHERE birthday > '1970-12-30' ``` @@ -125,7 +143,7 @@ You don't need to pay attention to what this query specifically does, we'll look Above, we looked at how to specify a date, but in addition to a date, we can also specify a time or both together. - +**MySQL** | | Description | Format | | :------------ | :--------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -133,9 +151,7 @@ Above, we looked at how to specify a date, but in addition to a date, we can als | Time | Contains only time without a specific date | `hh:mm:ss`, `hh:mm`, `hh`, `ss`

The separator can also be omitted.

For example:
`12:11` = 12:11:00 | | Date and time | Date with the possibility of setting a specific time | `YYYY-MM-DD hh:mm:ss`, `YYYYMMDDhhmmss`

For example:
`'20200101183030'` = January 1st, 2020, 18:30:30 | -
- - +**PostgreSQL** | | Description | Format | | :------------ | :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------- | @@ -143,16 +159,14 @@ Above, we looked at how to specify a date, but in addition to a date, we can als | Time | Contains only time without a specific date | `hh:mm:ss`, `hh:mm`

For example:
`'12:11:00'`, `'12:11'` | | Date and time | Date with the possibility of setting a specific time | `YYYY-MM-DD hh:mm:ss`

For example:
`'2020-01-01 18:30:30'` = January 1st, 2020, 18:30:30 | -
- ## Logical literals A logical literal is a value of `TRUE` or `FALSE`, which indicates the truthfulness or falsehood of a statement. - - When interpreting a query, MySQL converts them into numbers: `TRUE` and `FALSE` become - `1` and `0`, respectively. - +**MySQL** + +When interpreting a query, MySQL converts them into numbers: `TRUE` and `FALSE` become +`1` and `0`, respectively. ## NULL diff --git a/course/module-2/operator-having/article.md b/course/module-2/operator-having/article.md index e246e6d..96662ef 100644 --- a/course/module-2/operator-having/article.md +++ b/course/module-2/operator-having/article.md @@ -1,13 +1,15 @@ --- meta: - title: 'Operator HAVING' - description: 'Using the HAVING statement in SQL' + title: "operator HAVING" + description: "Using the HAVING statement in SQL" --- -# Operator HAVING +# operator HAVING We have already looked at a query to obtain the average rental cost of residential properties depending on the type of housing: +Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/operator-having). + ```sql SELECT home_type, AVG(price) as avg_price FROM Rooms GROUP BY home_type @@ -32,6 +34,16 @@ WHERE avg_price > 50 In advance, to filter groups, we must use the `HAVING` operator: +**MySQL** + +```sql +SELECT home_type, AVG(price) as avg_price FROM Rooms +GROUP BY home_type +HAVING avg_price > 50 +``` + +**PostgreSQL** + ```sql SELECT home_type, AVG(price) as avg_price FROM Rooms GROUP BY home_type @@ -43,13 +55,17 @@ HAVING AVG(price) > 50 | Private room | 89.4286 | | Entire home/apt | 148.6667 | +**PostgreSQL** + +> In PostgreSQL, aliases declared in `SELECT` are not available in `HAVING` +
## Order of execution for SQL queries But why couldn't we use `WHERE`, and why do we need a separate operator for this purpose? It all has to do with the order of execution for SQL queries. -![SQL query execution order scheme](https://sql-academy.org/static/guidePage/operator-having/sql_query_order_en.png 'SQL query execution order scheme') +![SQL query execution order scheme](https://sql-academy.org/static/guidePage/operator-having/sql_query_order_en.png "SQL query execution order scheme") Our first query was incorrect because we tried to use the `avg_price` field for the formed groups before they were formed, as the execution of the `WHERE` operator precedes grouping. diff --git a/course/module-2/operator-like/article.md b/course/module-2/operator-like/article.md index 635b4cc..1d21886 100644 --- a/course/module-2/operator-like/article.md +++ b/course/module-2/operator-like/article.md @@ -1,7 +1,7 @@ --- meta: - title: "LIKE operator" - description: "SQL syntax of the LIKE and ILIKE operators to search for records by a patterned string" + title: "LIKE operator" + description: "SQL syntax of the LIKE and ILIKE operators to search for records by a patterned string" --- # LIKE operator @@ -10,10 +10,18 @@ The `LIKE` operator is used in conditional queries when we want to find out whet For example, we have a `Users` table that has an `email` field: -```sql-executable-Airbnb +```sql SELECT name, email FROM Users; ``` +| name | email | +| ----------------- | ---------------------- | +| Bruce Willis | barjam\@hotmail.com | +| George Clooney | tellis\@me.com | +| Kevin Costner | metzzo\@hotmail.com | +| Samuel L. Jackson | moonlapse\@outlook.com | +| Kurt Russell | gator\@live.com | + Suppose we want to find all users whose email is in the second-level domain "hotmail". That is, we need to select only those records that meet the following condition: @@ -28,57 +36,62 @@ For such non-trivial searches on string fields, we need the `LIKE` operator. ... WHERE table_field [NOT] LIKE string_pattern ``` -The pattern may include the following special characters: +The pattern may include two special characters — `%` and `_`. Here is what each of them means: -| Character | Description | -| :-------- | :---------------------------------------------------------------------------------------- | -| `%` | Any sequence of characters (the number of characters in the sequence can be zero or more) | -| `_` | Any single character | +| Character | Description | +| --------- | ---------------------------------------------------------------------- | +| `%` | Any sequence of characters: 0 characters, 1 character, Many characters | +| `_` | Exactly one character | So our query for finding users in the "hotmail" domain might look like this: -```sql-executable-Airbnb +```sql SELECT name, email FROM Users WHERE email LIKE '%@hotmail.%' ``` +| name | email | +| -------------------- | --------------------- | +| Bruce Willis | barjam\@hotmail.com | +| Kevin Costner | metzzo\@hotmail.com | +| Jennifer Lopez | barjam\@hotmail.com | +| Harrison Ford | kostas\@hotmail.com | +| Michael Douglas | timtroyr\@hotmail.com | +| Catherine Zeta-Jones | flakeg\@hotmail.com | + ## Examples - ```sql ... WHERE table_field LIKE 'text%' ``` - Matches any strings beginning with "text" + Matches any strings beginning with "text" - ```sql ... WHERE table_field LIKE '%text' ``` - Matches any strings ending with "text" + Matches any strings ending with "text" - ```sql ... WHERE table_field LIKE '_ext' ``` - Matches strings with a length of 4 characters, with the last 3 characters required to be "ext". For example, the words "text" and "next" + Matches strings with a length of 4 characters, with the last 3 characters required to be "ext". For example, the words "text" and "next" - ```sql ... WHERE table_field LIKE 'begin%end' ``` - Matches strings starting with "begin" and ending with "end" + Matches strings starting with "begin" and ending with "end" - +**MySQL** > By default, MySQL patterns are not case-sensitive - - - +**PostgreSQL** > In PostgreSQL, patterns are case-sensitive. For case-insensitive search, use the `ILIKE` operator - - ## Escaping special characters Sometimes you need to search for strings where `%` and `_` are part of the text itself rather than pattern elements. In such cases, these characters must be escaped. @@ -110,5 +123,7 @@ Here, `!` plays the same role as `\` in the previous example. ## Interactive Exercise -Now let's practice what we've learned! +Now let's practice what we've learned!\ In the exercise below, you need to match the email addresses to the LIKE patterns by dragging them into the matching areas. + +The interactive demonstration is available [in the SQL Academy lesson](https://sql-academy.org/en/guide/operator-like). diff --git a/course/module-2/operator-regexp/article.md b/course/module-2/operator-regexp/article.md index ff77617..fe0883a 100644 --- a/course/module-2/operator-regexp/article.md +++ b/course/module-2/operator-regexp/article.md @@ -1,27 +1,23 @@ --- meta: - title: "REGEXP and ~ Operators in SQL" - description: "Using regular expressions in SQL with REGEXP operator in MySQL and ~ operator in PostgreSQL" + title: "REGEXP and ~ Operators in SQL" + description: "Using regular expressions in SQL with REGEXP operator in MySQL and ~ operator in PostgreSQL" --- - +**MySQL** # REGEXP Operator for Regular Expressions The `REGEXP` operator (or its synonym `RLIKE`) in MySQL is used for searching and manipulating string data using regular expressions. - +**PostgreSQL** - - -# Regular Expression Operator ~ +# Regular Expression Operator \~ The `~` and `~*` operators in PostgreSQL are used for searching and manipulating string data using regular expressions. - - Regular expressions provide powerful capabilities for complex search patterns that are difficult to implement with the `LIKE` operator. @@ -36,7 +32,7 @@ It is important to remember that `LIKE` compares the whole string against its pa ## Regular expression syntax - +**MySQL** ```sql ... WHERE table_field REGEXP 'pattern'; @@ -44,9 +40,7 @@ It is important to remember that `LIKE` compares the whole string against its pa Where `pattern` is the regular expression that defines the search pattern. - - - +**PostgreSQL** ```sql ... WHERE table_field ~ 'pattern'; -- case-sensitive @@ -55,43 +49,37 @@ Where `pattern` is the regular expression that defines the search pattern. Where `pattern` is the regular expression that defines the search pattern. - - ## Important Considerations - +**MySQL** 1. **Case insensitive** - By default, regular expressions in MySQL are not case-sensitive. - For example, the expression `REGEXP 'abc'` will match the string `abc`, `Abc`, and `ABC`. + By default, regular expressions in MySQL are not case-sensitive.\ + For example, the expression `REGEXP 'abc'` will match the string `abc`, `Abc`, and `ABC`. 2. **Special characters** - Some characters have special meanings in regular expressions and require escaping (e.g., - `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). + Some characters have special meanings in regular expressions and require escaping (e.g., + `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). - To escape such characters, use a double backslash — `\\`. + To escape such characters, use a double backslash — `\\`. - - - +**PostgreSQL** 1. **Case sensitivity** - By default, regular expressions in PostgreSQL are case-sensitive. + By default, regular expressions in PostgreSQL are case-sensitive. - - The `~` operator — case-sensitive - - The `~*` operator — case-insensitive + - The `~` operator — case-sensitive + - The `~*` operator — case-insensitive 2. **Special characters** - Some characters have special meanings in regular expressions and require escaping (e.g., - `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). - - To escape such characters, use a single backslash — `\`. + Some characters have special meanings in regular expressions and require escaping (e.g., + `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). - + To escape such characters, use a single backslash — `\`. ## Special characters and constructs @@ -116,117 +104,132 @@ Where `pattern` is the regular expression that defines the search pattern. - **Get all users whose names start with "John":** - - - ```sql-executable-Airbnb - SELECT * FROM Users WHERE name REGEXP '^John' - ``` + **MySQL** - + ```sql + SELECT * FROM Users WHERE name REGEXP '^John' + ``` - + **PostgreSQL** - ```sql-executable-Airbnb - SELECT * FROM Users WHERE name ~ '^John' - ``` + ```sql + SELECT * FROM Users WHERE name ~ '^John' + ``` - + | id | name | email | email_verified_at | password | phone_number | + | --- | ------------- | ----------------- | ------------------------ | -------------------- | --------------- | + | 18 | John Travolta | wainwrig\@msn.com | 2016-11-19T12:30:43.000Z | fzjhl0v82o0amalr8649 | +1 202 555 0176 | + | 28 | Johnny Depp | cgarcia\@yahoo.ca | 2017-05-26T01:19:06.000Z | qpp6hbnae42cdhmxlk4j | +7 401 195 7363 | - This expression searches for strings starting with "John". The `^` symbol indicates the start of the string. + This expression searches for strings starting with "John". The `^` symbol indicates the start of the string. - **Display all school subjects whose names end with the letter "e" or "y":** - + **MySQL** - ```sql-executable-Schedule - SELECT * FROM Subject WHERE name REGEXP '[ey]$' - ``` + ```sql + SELECT * FROM Subject WHERE name REGEXP '[ey]$' + ``` - + **PostgreSQL** - + ```sql + SELECT * FROM Subject WHERE name ~ '[ey]$' + ``` - ```sql-executable-Schedule - SELECT * FROM Subject WHERE name ~ '[ey]$' - ``` + | id | name | + | --- | ---------------- | + | 2 | Russian language | + | 3 | Literature | + | 5 | Chemistry | + | 6 | Geography | + | 7 | History | + | 8 | Biology | + | 9 | English language | + | 11 | Physical Culture | + | 13 | Technology | - - - In this example, `[ey]` defines a list of possible values for the pattern `$`, which defines what the string should end with. + In this example, `[ey]` defines a list of possible values for the pattern `$`, which defines what the string should end with. - **Find all users whose email addresses end with "@outlook.com" or "@icloud.com":** - - - ```sql-executable-Airbnb - SELECT * FROM Users WHERE email REGEXP '@(outlook\\.com|icloud\\.com)$' - ``` + **MySQL** - + ```sql + SELECT * FROM Users WHERE email REGEXP '@(outlook\\.com|icloud\\.com)$' + ``` - + **PostgreSQL** - ```sql-executable-Airbnb - SELECT * FROM Users WHERE email ~ '@(outlook\.com|icloud\.com)$' - ``` + ```sql + SELECT * FROM Users WHERE email ~ '@(outlook\.com|icloud\.com)$' + ``` - + | id | name | email | email_verified_at | password | phone_number | + | --- | ----------------- | ---------------------- | ------------------------ | -------------------- | ----------------- | + | 7 | Samuel L. Jackson | moonlapse\@outlook.com | 2018-07-19T11:16:13.000Z | i6yvht95527z3idgqx9y | +1 202 555 0162 | + | 13 | Steve Martin | nelson\@outlook.com | 2016-07-29T04:25:00.000Z | w76yphg3kvzg77ilmxfs | +1 202 555 0138 | + | 29 | Pierce Brosnan | treeves\@icloud.com | 2019-03-08T01:56:00.000Z | lqiwecclne9rv8woo2go | +7 401 749 3620 | + | 30 | Sean Connery | jschauma\@icloud.com | 2016-05-21T00:45:17.000Z | lyh4jkdxkvtvulvqi5db | +7 401 511 6783 | + | 31 | Bruce Willis | kewley\@icloud.com | 2016-12-08T20:18:59.000Z | 0ofa2khvnptiackbssv0 | +375 154 771 3462 | - Here, `$` is used to indicate the end of the string and `|` is used to specify multiple options. + Here, `$` is used to indicate the end of the string and `|` is used to specify multiple options. - **Find all users whose phone numbers do not contain the digits "2" and "8":** - - - ```sql-executable-Airbnb - SELECT * FROM Users WHERE phone_number REGEXP '^[^28]*$' - ``` + **MySQL** - + ```sql + SELECT * FROM Users WHERE phone_number REGEXP '^[^28]*$' + ``` - + **PostgreSQL** - ```sql-executable-Airbnb - SELECT * FROM Users WHERE phone_number ~ '^[^28]*$' - ``` + ```sql + SELECT * FROM Users WHERE phone_number ~ '^[^28]*$' + ``` - + | id | name | email | email_verified_at | password | phone_number | + | --- | ----------- | --------------------- | ------------------------ | -------------------- | --------------- | + | 27 | Brad Pitt | kewley\@optonline.net | 2017-02-11T05:45:15.000Z | 829j2ygocn8btzae49kv | +7 401 741 3797 | + | 28 | Johnny Depp | cgarcia\@yahoo.ca | 2017-05-26T01:19:06.000Z | qpp6hbnae42cdhmxlk4j | +7 401 195 7363 | - In this example, the symbol `[^28]` represents any character except "2" and "8", and `*` means any number of such characters. - The `^` and `$` symbols indicate the start and end of the string respectively, ensuring that the entire string matches the pattern. + In this example, the symbol `[^28]` represents any character except "2" and "8", and `*` means any number of such characters. + The `^` and `$` symbols indicate the start and end of the string respectively, ensuring that the entire string matches the pattern. - **Find all users whose phone number starts with «+7»** - - - ```sql-executable-Airbnb - SELECT name, phone_number FROM Users WHERE phone_number REGEXP '^\\+7' - ``` - - - - + **MySQL** - ```sql-executable-Airbnb - SELECT name, phone_number FROM Users WHERE phone_number ~ '^\+7' - ``` + ```sql + SELECT name, phone_number FROM Users WHERE phone_number REGEXP '^\\+7' + ``` - + **PostgreSQL** - In this example, `^` denotes the beginning of a string. This means we are looking for strings that start with a specific pattern. + ```sql + SELECT name, phone_number FROM Users WHERE phone_number ~ '^\+7' + ``` - + | name | phone_number | + | -------------- | --------------- | + | Hideo Kojima | +7 401 452 0052 | + | ClINT Eastwood | +7 401 722 0912 | + | Brad Pitt | +7 401 741 3797 | + | Johnny Depp | +7 401 195 7363 | + | Pierce Brosnan | +7 401 749 3620 | + | Sean Connery | +7 401 511 6783 | - Since `+` is a special character in regular expressions, - it needs to be escaped with a double backslash (`\\`) so that it is treated as the literal `+` character. - As a result, `\\+` matches the `+` sign in the string. + In this example, `^` denotes the beginning of a string. This means we are looking for strings that start with a specific pattern. - + **MySQL** - + Since `+` is a special character in regular expressions, + it needs to be escaped with a double backslash (`\\`) so that it is treated as the literal `+` character. + As a result, `\\+` matches the `+` sign in the string. - Since `+` is a special character in regular expressions, - it needs to be escaped with a single backslash (`\`) so that it is treated as the literal `+` character. - As a result, `\+` matches the `+` sign in the string. + **PostgreSQL** - + Since `+` is a special character in regular expressions, + it needs to be escaped with a single backslash (`\`) so that it is treated as the literal `+` character. + As a result, `\+` matches the `+` sign in the string. diff --git a/course/module-2/sorting/article.md b/course/module-2/sorting/article.md index 21e1206..2f36cd4 100644 --- a/course/module-2/sorting/article.md +++ b/course/module-2/sorting/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Sorting, ORDER BY operator" - description: "SQL ORDER BY operator, sorting by multiple columns, examples of usage" + title: "Sorting, ORDER BY operator" + description: "SQL ORDER BY operator, sorting by multiple columns, examples of usage" --- # Sorting, ORDER BY operator @@ -23,15 +23,23 @@ Where `ASC` and `DESC` are sorting directions: - `ASC` - sorting in ascending order (by default) - `DESC` - sorting in descending order -For example, Let's display the names of airlines in alphabetical order from the `Company` table: +For example, let's display the names of airlines in alphabetical order from the `Company` table: -```sql-executable-Airo +```sql SELECT name FROM Company ORDER BY name; ``` +| name | +| ---------- | +| Aeroflot | +| air_France | +| British_AW | +| Dale_avia | +| Don_avia | + ## Sorting in ascending and descending order for main types - +**MySQL** | Data type | ASC | DESC | | :------------ | :-------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | @@ -41,9 +49,7 @@ SELECT name FROM Company ORDER BY name; | Boolean type | `False` comes before `True` | `True` comes before `False` | | NULL values | `NULL` values come first | `NULL` values come first | - - - +**PostgreSQL** | Data type | ASC | DESC | | :------------ | :-------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | @@ -53,8 +59,6 @@ SELECT name FROM Company ORDER BY name; | Boolean type | `false` comes before `true` | `true` comes before `false` | | NULL values | `NULL` values come last | `NULL` values come first | - - ## Sorting by multiple columns To sort results by two or more columns, they should be specified separated by commas. @@ -76,11 +80,25 @@ The number of columns that can be sorted is unlimited. Let's display flight information sorted by the departure city in ascending order and by the arrival city in descending order, from the `Trip` table: -```sql-executable-Airo +```sql SELECT DISTINCT town_from, town_to FROM Trip ORDER BY town_from, town_to DESC; ``` +| town_from | town_to | +| ----------- | ----------- | +| London | Singapore | +| London | Paris | +| Moscow | Rostov | +| Paris | Rostov | +| Rostov | Vladivostok | +| Rostov | Paris | +| Rostov | Moscow | +| Singapore | London | +| Vladivostok | Rostov | + In this example, the entries are sorted by the `town_from` field first. Then, it performs reverse sorting by the `town_to` field for groups of rows that have the same value in the `town_from` column. ## Demonstration of how sorting works + +The interactive demonstration is available [in the SQL Academy lesson](https://sql-academy.org/en/guide/sorting). diff --git a/course/module-2/using-functions/article.md b/course/module-2/using-functions/article.md index 1bf6379..079b066 100644 --- a/course/module-2/using-functions/article.md +++ b/course/module-2/using-functions/article.md @@ -1,17 +1,21 @@ --- meta: - title: 'Using functions' - description: 'Examples of scalar SQL functions and their applications on literals and field values from tables.' + title: "Using functions" + description: "Examples of scalar SQL functions and their applications on literals and field values from tables." --- # Using Functions When creating SQL queries, we can use built-in functions. For example, if we want to output a string in uppercase, we can use the `UPPER` function. -```sql-executable +```sql SELECT UPPER('Hello world') AS upper_string; ``` +| upper_string | +| ------------ | +| HELLO WORLD | + ## What is a built-in function? The built–in function is a piece of code implemented in the DBMS, with which you can perform transformations of string, numeric and other data in queries. @@ -22,103 +26,131 @@ For example, the function `NOW()` takes zero arguments and returns a literal in ## Examples of Functions -There are many functions, but the main ones can always be found using the search bar in the header or on the function reference page. +There are many functions, but the main ones can always be found using the search bar in the header or on the function reference page. Here are some examples: - +**MySQL** -- - **LOWER** - +- + **LOWER** + Returns a string in which all characters are written in lowercase - ```sql-executable + ```sql SELECT LOWER('SQL Academy') AS lower_string; ``` -- - **YEAR** - + | lower_string | + | ------------ | + | sql academy | + +- + **YEAR** + Returns the year for a given date. - ```sql-executable + ```sql SELECT YEAR('2022-06-16') AS year; ``` -- - **INSTR** - + | year | + | ---- | + | 2022 | + +- + **INSTR** + Searches for a substring in a string, returning the position of its first character. At the same time, the countdown starts with one, not zero, as in most programming languages. The function works by character-by-character comparison of the source string with the desired one. For example, in the string `sql-academy`, the substring `academy` appears starting from the fifth character. - ```sql-executable + ```sql SELECT INSTR('sql-academy', 'academy') AS idx; ``` -- - **LENGTH** - + | idx | + | --- | + | 5 | + +- + **LENGTH** + Returns the length of the specified string. - ```sql-executable + ```sql SELECT LENGTH('sql-academy') AS str_length; ``` - + | str_length | + | ---------- | + | 11 | - +**PostgreSQL** -- - **LOWER** - +- + **LOWER** + Returns a string in which all characters are written in lowercase - ```sql-executable + ```sql SELECT LOWER('SQL Academy') AS lower_string; ``` -- - **EXTRACT** - + | lower_string | + | ------------ | + | sql academy | + +- + **EXTRACT** + Extracts date parts (year, month, day, etc.) from a given date - ```sql-executable + ```sql SELECT EXTRACT(YEAR FROM DATE '2022-06-16') AS year; ``` -- - **POSITION** - + | year | + | ---- | + | 2022 | + +- + **POSITION** + Searches for a substring in a string, returning the position of its first character. At the same time, the countdown starts with one, not zero, as in most programming languages. The function works by character-by-character comparison of the source string with the desired one. For example, in the string `sql-academy`, the substring `academy` appears starting from the fifth character. - ```sql-executable + ```sql SELECT POSITION('academy' IN 'sql-academy') AS idx; ``` -- - **LENGTH** - + | idx | + | --- | + | 5 | + +- + **LENGTH** + Returns the length of the specified string. - ```sql-executable + ```sql SELECT LENGTH('sql-academy') AS str_length; ``` - + | str_length | + | ---------- | + | 11 | ## Applying functions over table field values @@ -127,33 +159,50 @@ Functions can be used not only on literals, but also on values taken from a tabl For example, let's go back to our database and look at the `FamilyMembers` table: it contains the name, status, and birthdate of people. +Family database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/using-functions). + We can modify each of these fields' values when outputting them. The following query calculates the length of the full name for each family member. -```sql-executable-Family-format +```sql SELECT member_name, LENGTH(member_name) AS fullname_length FROM FamilyMembers; ``` +| member_name | fullname_length | +| ----------------- | --------------- | +| Headley Quincey | 15 | +| Flavia Quincey | 14 | +| Andie Quincey | 13 | +| Lela Quincey | 12 | +| Annie Quincey | 13 | +| Ernest Forrest | 14 | +| Constance Forrest | 17 | +| Wednesday Addams | 16 | + ## Operations on the result of the function Since we know that each function must return any of the possible literals, its result can also be used in further calculations and transformations. For example, we want to get the first three letters in a string and convert them to uppercase. To do this, it will be enough for us to combine two functions: `LEFT` and `UPPER`, where the result of one function will be an argument for the second. -```sql-executable-format +```sql SELECT UPPER(LEFT('sql-academy', 3)) AS str; ``` +| str | +| --- | +| SQL | + Or we want to calculate the length of a person's last name by having a string in the format `first namelast name`. One of the possible ways to calculate the length of the last name can be using the functions `LENGTH` and position search, using the formula ` = - ( + )`: -- The value `` can be obtained using the `LENGTH` function +- The value `` can be obtained using the `LENGTH` function - +**MySQL** -- For ` + `, you need to calculate the position of the character where the name ends and add one, because the space has a length of "1". We can do this using only the `INSTR` function, focusing on the "space" character +- For ` + `, you need to calculate the position of the character where the name ends and add one, because the space has a length of "1". We can do this using only the `INSTR` function, focusing on the "space" character Since both functions return numeric literals, we can perform arithmetic operations on them. Let's subtract one from the other and get the length of the last name (lastname_length): -```sql-executable-Family-format +```sql SELECT member_name, LENGTH(member_name) AS full_length, @@ -162,15 +211,13 @@ SELECT FROM FamilyMembers; ``` - - - +**PostgreSQL** -- For ` + `, you need to calculate the position of the character where the name ends and add one, because the space has a length of "1". We can do this using only the `POSITION` function, focusing on the "space" character +- For ` + `, you need to calculate the position of the character where the name ends and add one, because the space has a length of "1". We can do this using only the `POSITION` function, focusing on the "space" character Since both functions return numeric literals, we can perform arithmetic operations on them. Let's subtract one from the other and get the length of the last name (lastname_length): -```sql-executable-Family-format +```sql SELECT member_name, LENGTH(member_name) AS full_length, @@ -179,4 +226,13 @@ SELECT FROM FamilyMembers; ``` - +| member_name | full_length | firstname_with_space_length | lastname_length | +| ----------------- | ----------- | --------------------------- | --------------- | +| Headley Quincey | 15 | 8 | 7 | +| Flavia Quincey | 14 | 7 | 7 | +| Andie Quincey | 13 | 6 | 7 | +| Lela Quincey | 12 | 5 | 7 | +| Annie Quincey | 13 | 6 | 7 | +| Ernest Forrest | 14 | 7 | 7 | +| Constance Forrest | 17 | 10 | 7 | +| Wednesday Addams | 16 | 10 | 6 | diff --git a/course/module-3/case-expression/article.md b/course/module-3/case-expression/article.md index 4b858a1..8518e70 100644 --- a/course/module-3/case-expression/article.md +++ b/course/module-3/case-expression/article.md @@ -1,13 +1,13 @@ --- meta: - title: "Conditional logic, CASE statement" - description: "Conditional logic in SQL using the CASE WHEN THEN END statement" + title: "Conditional logic, CASE statement" + description: "Conditional logic in SQL using the CASE WHEN THEN END statement" --- # Conditional logic, CASE statement -SQL, like many programming languages, allows you to write conditional logic so that behavior -query depended on the values ​​of certain columns or expressions. In this article, we will look at how this is implemented in SQL with +SQL, like many programming languages, lets you write conditional logic so that a query's +behavior depends on the values of certain columns or expressions. In this article, we'll look at how this is implemented in SQL using the `CASE` operator. ## Concept of conditional logic @@ -19,13 +19,13 @@ in the selection, it is necessary to display not the date of birth itself, but t if the student is 18 or not. This is an example of conditional logic, in which either one value or another should be displayed depending on the specific condition. - +Schedule database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/case-expression). The implementation of such a query using `CASE` might look like this: - +**MySQL** -```sql-executable-Schedule +```sql SELECT first_name, last_name, CASE WHEN TIMESTAMPDIFF(YEAR, birthday, NOW()) >= 18 THEN 'Adult' @@ -34,11 +34,9 @@ END AS status FROM Student ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql SELECT first_name, last_name, CASE WHEN EXTRACT(YEAR FROM AGE(NOW(), birthday)) >= 18 THEN 'Adult' @@ -47,7 +45,30 @@ END AS status FROM Student ``` - +| first_name | last_name | status | +| ---------- | ------------ | ------ | +| Nikolaj | Sokolov | Adult | +| Vyacheslav | Eliseev | Adult | +| Ivan | Efremov | Adult | +| Anatolij | ZHdanov | Minor | +| Georgij | Noskov | Adult | +| Artyom | Sergeev | Minor | +| Arina | Evseeva | Adult | +| Angelina | Voroncova | Adult | +| Ekaterina | Ustinova | Adult | +| Raisa | Lapina | Adult | +| Leonid | Ignatov | Minor | +| Snezhana | Seliverstova | Adult | +| Semyon | Biryukov | Adult | +| Georgij | Baranov | Adult | +| YUliya | Vishnyakova | Adult | +| Valentina | Bolshakova | Adult | +| Leonid | Kryukov | Adult | +| Vladislav | Cvetkov | Adult | +| Snezhana | Morozova | Adult | +| Lyubov | Borisova | Adult | +| Anfisa | Kalashnikova | Adult | +| Anna | Osipova | Adult | ## CASE search expression syntax @@ -70,9 +91,9 @@ Let's take the `CASE` operator to implement the stages of schooling. ![School education stages](https://sql-academy.org/static/guidePage/case-expression/en_school_education_stages.png "School education stages") - +**MySQL** -```sql-executable-Schedule +```sql SELECT name, CASE WHEN SUBSTRING(name, 1, INSTR(name, ' ')) IN (10, 11) THEN 'High School' @@ -82,11 +103,9 @@ END AS stage FROM Class ``` - +**PostgreSQL** - - -```sql-executable-Schedule +```sql SELECT name, CASE WHEN SUBSTRING(name, 1, POSITION(' ' IN name) - 1) IN ('10', '11') THEN 'High School' @@ -96,28 +115,41 @@ END AS stage FROM Class ``` - - - +| name | stage | +| ---- | ----------------- | +| 8 A | Middle school | +| 8 B | Middle school | +| 9 C | Middle school | +| 9 B | Middle school | +| 9 A | Middle school | +| 10 B | High School | +| 10 A | High School | +| 11 B | High School | +| 11 A | High School | +| 7 A | Middle school | +| 7 B | Middle school | +| 6 A | Middle school | +| 6 B | Middle school | +| 5 A | Middle school | +| 5 B | Middle school | +| 4 A | Elementary school | + +**MySQL** - First we extract the class number from its name - ```sql - SUBSTRING(name, 1, INSTR(name, ' ')) - ``` - - + ```sql + SUBSTRING(name, 1, INSTR(name, ' ')) + ``` - +**PostgreSQL** - First we extract the class number from its name - ```sql - SUBSTRING(name, 1, POSITION(' ' IN name) - 1) - ``` + ```sql + SUBSTRING(name, 1, POSITION(' ' IN name) - 1) + ``` - - -- Next, we check for occurrences of this class number in the list of classes related to "High School" and "Middle school". -- If the class number doesn't match 5-11, we output "Elementary school". +* Next, we check for occurrences of this class number in the list of classes related to "High School" and "Middle school". +* If the class number doesn't match 5-11, we output "Elementary school". ## Syntax of a simple CASE expression @@ -138,9 +170,9 @@ value, the value following `THEN` is returned. Using this syntax, we can rewrite our previous example: - +**MySQL** -```sql-executable-Schedule +```sql SELECT name, CASE SUBSTRING(name, 1, INSTR(name, ' ')) WHEN 11 THEN 'High School' @@ -155,11 +187,9 @@ END AS stage FROM Class ``` - +**PostgreSQL** - - -```sql-executable-Schedule +```sql SELECT name, CASE SUBSTRING(name, 1, POSITION(' ' IN name) - 1) WHEN '11' THEN 'High School' @@ -174,7 +204,24 @@ END AS stage FROM Class ``` - +| name | stage | +| ---- | ----------------- | +| 8 A | Middle school | +| 8 B | Middle school | +| 9 C | Middle school | +| 9 B | Middle school | +| 9 A | Middle school | +| 10 B | High School | +| 10 A | High School | +| 11 B | High School | +| 11 A | High School | +| 7 A | Middle school | +| 7 B | Middle school | +| 6 A | Middle school | +| 6 B | Middle school | +| 5 A | Middle school | +| 5 B | Middle school | +| 4 A | Elementary school | ### Test yourself @@ -187,3 +234,9 @@ CASE 2 ELSE 'Many' END ``` + +1. Zero — The CASE statement cannot return "Zero" because the values ​​"2" and "0" are not equal + +2. One — The CASE statement cannot return "One" because the values ​​"2" and "1" are not equal + +3. **Correct answer:** Many — That's right, the CASE statement will indeed return "Many", because none of the values ​​passed to WHEN matched "2" diff --git a/course/module-3/combining-queries/article.md b/course/module-3/combining-queries/article.md index a361fe9..6a9f275 100644 --- a/course/module-3/combining-queries/article.md +++ b/course/module-3/combining-queries/article.md @@ -1,10 +1,10 @@ --- meta: - title: 'Combining requests, Union operator' - description: 'An example of using sql operator union to combine selections' + title: "Combining queries, UNION operator" + description: "An example of using the SQL UNION operator to combine query results" --- -# Combining requests, Union operator +# Combining queries, UNION operator The results of executing SQL queries can be combined. There is a `UNION` operator for this. @@ -18,8 +18,8 @@ SELECT table_fields FROM list_of_tables ... ; `UNION` removes repetitions in the resulting table by default. There is an optional `ALL` parameter for repeat display. -- Do not confuse query join operations with table join operations. To do this, use the `JOIN` operator. -- Do not confuse query merge operations with subqueries. Subqueries are executed for linked tables. +- Do not confuse query join operations with table join operations. To do this, use the `JOIN` operator. +- Do not confuse query merge operations with subqueries. Subqueries are executed for linked tables. Table joining with the `UNION` operator is performed for tables that are not related in any way, but with a similar structure. @@ -31,12 +31,12 @@ In order for `UNION` to function correctly, it is essential that the resulting t There are two other operators whose behavior is very similar to `UNION`: -- `INTERSECT` - Combines two SELECT queries, but returns only the first SELECT records that have matches in the second SELECT element. -- `EXCEPT` - Combines two SELECT queries, but returns only the first SELECT records, which do not match in the second SELECT element. +- `INTERSECT` + Combines two SELECT queries, but returns only the first SELECT records that have matches in the second SELECT element. +- `EXCEPT` + Combines two SELECT queries, but returns only the first SELECT records, which do not match in the second SELECT element. -## Examples of using +## Usage examples For example, it is necessary to display the name of all goods and the names of all family members (very conditional task). Since the data types are the same, we can do this. diff --git a/course/module-3/correlated-subqueries/article.md b/course/module-3/correlated-subqueries/article.md index 2a0f6af..4cab9ce 100644 --- a/course/module-3/correlated-subqueries/article.md +++ b/course/module-3/correlated-subqueries/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Correlated subqueries' - description: 'Correlated and uncorrelated subqueries in SQL, their syntax' + title: "Correlated subqueries" + description: "Correlated and uncorrelated subqueries in SQL, their syntax" --- # Correlated subqueries @@ -30,9 +30,9 @@ FROM FamilyMembers; | Andie Quincey | 3600 | | Lela Quincey | 650 | | Annie Quincey | 1060 | -| Ernest Forrest | | -| Constance Forrest | | -| Wednesday Addams | | +| Ernest Forrest | \ | +| Constance Forrest | \ | +| Wednesday Addams | \ | In this case, the correlated subquery refers to the `member_id` column in the main query. diff --git a/course/module-3/if-function/article.md b/course/module-3/if-function/article.md index 508df8d..652c176 100644 --- a/course/module-3/if-function/article.md +++ b/course/module-3/if-function/article.md @@ -1,29 +1,48 @@ --- meta: - title: 'Conditional IF function, ISNULL, NULLIF functions' - description: 'Syntax and examples of conditional functions IF, IFNULL, NULLIF in MySQL' + title: "Conditional logic in SQL" + description: "Conditional logic in SQL: IF function in MySQL and additional functions in PostgreSQL (COALESCE, NULLIF)" --- +**MySQL** + # Conditional IF function In the previous lesson, we looked at the `CASE` statement for implementing conditional logic in SQL. However, this is not the only mechanism by which it is possible to implement logic branching in a query. It's time to turn our attention to the `IF` function. -## Syntax +## IF Syntax ```sql -IF(conditional_expression, - value_under_true_condition, - value_on_false_condition); +IF(conditional_expression, value_1, value_2); ``` -The `IF` function looks at the truth of the conditional expression and, depending on this truth, returns either -the value passed in the second argument or the third argument. +If the conditional expression passed as the first argument to the `IF` function is true, +the function will return the value of the second argument `value_1`, otherwise the value of the third argument `value_2` is returned. + +**PostgreSQL** + +# Additional conditional logic functions + +In the previous lesson, we studied the `CASE` statement for implementing conditional logic in SQL. +PostgreSQL provides additional functions that simplify working with conditional logic in special cases. +These functions are especially useful when working with `NULL` values and creating more readable code. + +## Functions for conditional logic + +In addition to the universal `CASE` operator, PostgreSQL provides: + +1. **COALESCE function** - for working with `NULL` values +2. **NULLIF function** - for special cases with `NULL` + +These functions are standard SQL functions and make code more readable in certain situations. ### Examples -- Simple example +**MySQL** + +- Simple comparison of two numbers. Since 10 is not greater than 20, the function will return 'FALSE'. ```sql SELECT IF(10>20, "TRUE", "FALSE"); @@ -33,7 +52,24 @@ the value passed in the second argument or the third argument. | -------------------------- | | FALSE | -- Example of use with a real database +**PostgreSQL** + +- Simple example of conditional logic using the CASE operator from the previous lesson: + + ```sql + SELECT CASE WHEN 10 > 20 THEN 'TRUE' ELSE 'FALSE' END; + ``` + + | case | + | ----- | + | FALSE | + +**MySQL** + +- Example of use with a real database. Based on the price, it is necessary to determine whether the housing belongs to one of two classes: "Comfort class" and "Economy class". + If the price is greater than or equal to `150`, then this housing belongs to "Comfort class". + + Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/if-function). ```sql SELECT id, price, @@ -94,7 +130,74 @@ the value passed in the second argument or the third argument. | 49 | 115 | Economy class | | 50 | 80 | Economy class | -- `IF` functions can also be nested +**PostgreSQL** + +- Example with real data. The CASE operator helps categorize housing by price: + + Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/if-function). + + ```sql + SELECT id, price, + CASE WHEN price >= 150 THEN 'Comfort class' ELSE 'Economy class' END AS category + FROM Rooms + ``` + + | id | price | category | + | --- | ----- | ------------- | + | 1 | 149 | Economy class | + | 2 | 225 | Comfort class | + | 3 | 150 | Comfort class | + | 4 | 89 | Economy class | + | 5 | 80 | Economy class | + | 6 | 200 | Comfort class | + | 7 | 60 | Economy class | + | 8 | 79 | Economy class | + | 9 | 79 | Economy class | + | 10 | 150 | Comfort class | + | 11 | 135 | Economy class | + | 12 | 85 | Economy class | + | 13 | 89 | Economy class | + | 14 | 85 | Economy class | + | 15 | 120 | Economy class | + | 16 | 140 | Economy class | + | 17 | 215 | Comfort class | + | 18 | 140 | Economy class | + | 19 | 99 | Economy class | + | 20 | 190 | Comfort class | + | 21 | 299 | Comfort class | + | 22 | 130 | Economy class | + | 23 | 80 | Economy class | + | 24 | 110 | Economy class | + | 25 | 120 | Economy class | + | 26 | 60 | Economy class | + | 27 | 80 | Economy class | + | 28 | 150 | Comfort class | + | 29 | 44 | Economy class | + | 30 | 180 | Comfort class | + | 31 | 50 | Economy class | + | 32 | 52 | Economy class | + | 33 | 55 | Economy class | + | 34 | 50 | Economy class | + | 35 | 70 | Economy class | + | 36 | 89 | Economy class | + | 37 | 35 | Economy class | + | 38 | 85 | Economy class | + | 39 | 150 | Comfort class | + | 40 | 40 | Economy class | + | 41 | 68 | Economy class | + | 42 | 120 | Economy class | + | 43 | 120 | Economy class | + | 44 | 135 | Economy class | + | 45 | 150 | Comfort class | + | 46 | 150 | Comfort class | + | 47 | 130 | Economy class | + | 48 | 110 | Economy class | + | 49 | 115 | Economy class | + | 50 | 80 | Economy class | + +**MySQL** + +- `IF` functions can also be nested within each other, emulating the `CASE` operator. ```sql SELECT id, price, @@ -157,9 +260,80 @@ the value passed in the second argument or the third argument. | 49 | 115 | Economy class | | 50 | 80 | Economy class | +**PostgreSQL** + +- CASE is perfect for multiple conditions: + + ```sql + SELECT id, price, + CASE + WHEN price >= 200 THEN 'Business Class' + WHEN price >= 150 THEN 'Comfort class' + ELSE 'Economy class' + END AS category + FROM Rooms + ``` + + | id | price | category | + | --- | ----- | -------------- | + | 1 | 149 | Economy class | + | 2 | 225 | Business Class | + | 3 | 150 | Comfort class | + | 4 | 89 | Economy class | + | 5 | 80 | Economy class | + | 6 | 200 | Business Class | + | 7 | 60 | Economy class | + | 8 | 79 | Economy class | + | 9 | 79 | Economy class | + | 10 | 150 | Comfort class | + | 11 | 135 | Economy class | + | 12 | 85 | Economy class | + | 13 | 89 | Economy class | + | 14 | 85 | Economy class | + | 15 | 120 | Economy class | + | 16 | 140 | Economy class | + | 17 | 215 | Business Class | + | 18 | 140 | Economy class | + | 19 | 99 | Economy class | + | 20 | 190 | Comfort class | + | 21 | 299 | Business Class | + | 22 | 130 | Economy class | + | 23 | 80 | Economy class | + | 24 | 110 | Economy class | + | 25 | 120 | Economy class | + | 26 | 60 | Economy class | + | 27 | 80 | Economy class | + | 28 | 150 | Comfort class | + | 29 | 44 | Economy class | + | 30 | 180 | Comfort class | + | 31 | 50 | Economy class | + | 32 | 52 | Economy class | + | 33 | 55 | Economy class | + | 34 | 50 | Economy class | + | 35 | 70 | Economy class | + | 36 | 89 | Economy class | + | 37 | 35 | Economy class | + | 38 | 85 | Economy class | + | 39 | 150 | Comfort class | + | 40 | 40 | Economy class | + | 41 | 68 | Economy class | + | 42 | 120 | Economy class | + | 43 | 120 | Economy class | + | 44 | 135 | Economy class | + | 45 | 150 | Comfort class | + | 46 | 150 | Comfort class | + | 47 | 130 | Economy class | + | 48 | 110 | Economy class | + | 49 | 115 | Economy class | + | 50 | 80 | Economy class | + +However, for special cases, PostgreSQL provides more specialized functions. + +**MySQL** + ## IFNULL and NULLIF functions -In addition to the `IF` function, SQL also has simpler, but less universal functions `IFNULL` and `NULLIF`, +In addition to the `IF` function, MySQL also has simpler, but less universal functions `IFNULL` and `NULLIF`, aimed at processing `NULL` values. ### IFNULL syntax @@ -168,12 +342,53 @@ aimed at processing `NULL` values. IFNULL(value, alternative_value); ``` -The 'IFNULL`function returns the`value`passed by the first argument if it is not equal to`NULL', otherwise it returns -an `alternative_value'. +The `IFNULL` function returns the `value` passed by the first argument if it is not equal to `NULL`, otherwise it returns +the `alternative_value`. + +**PostgreSQL** + +## COALESCE function + +The `COALESCE` function is an elegant solution for working with `NULL` values. +It returns the first non-NULL value from the list of arguments. + +### Syntax + +```sql +COALESCE(value1, value2, ..., valueN); +``` + +This is much more convenient than writing long CASE expressions to handle NULL. + +### Comparison of approaches + +Using CASE: + +```sql +CASE + WHEN value1 IS NOT NULL THEN value1 + WHEN value2 IS NOT NULL THEN value2 + ELSE value3 +END +``` + +Using COALESCE (much simpler): + +```sql +COALESCE(value1, value2, value3) +``` + +**MySQL** ### Examples with the IFNULL function -- If the first argument is not `NULL`, then it will be returned. +**PostgreSQL** + +### Examples with the COALESCE function + +**MySQL** + +- If the first argument is not equal to `NULL`, then it will be returned. ```sql SELECT IFNULL("SQL Academy", "Alternative SQL Academy") AS sql_trainer; @@ -183,7 +398,21 @@ an `alternative_value'. | ----------- | | SQL Academy | -- If the first argument is `NULL`, the value passed by the second argument will be returned. +**PostgreSQL** + +- If the first argument is not equal to `NULL`, then it will be returned. + + ```sql + SELECT COALESCE('SQL Academy', 'Alternative SQL Academy') AS sql_trainer; + ``` + + | coalesce | + | ----------- | + | SQL Academy | + +**MySQL** + +- If the first argument is equal to `NULL`, then the value passed by the second argument will be returned. ```sql SELECT IFNULL(NULL, "Alternative SQL Academy") AS sql_trainer; @@ -193,17 +422,46 @@ an `alternative_value'. | ----------------------- | | Alternative SQL Academy | +**PostgreSQL** + +- If the first argument is equal to `NULL`, then the next non-NULL value will be returned. + + ```sql + SELECT COALESCE(NULL, 'Alternative SQL Academy') AS sql_trainer; + ``` + + | coalesce | + | ----------------------- | + | Alternative SQL Academy | + +- `COALESCE` can accept multiple arguments, making the code very readable: + + ```sql + SELECT COALESCE(NULL, NULL, 'SQL Academy', 'Backup option') AS sql_trainer; + ``` + + | coalesce | + | ----------- | + | SQL Academy | + +## NULLIF function + +The `NULLIF` function is useful when you need to replace a specific value with NULL. +This can be helpful for filtering or processing "empty" values. + ### NULLIF syntax ```sql NULLIF(value_1, value_2); ``` -The `NULLIF` function returns `NULL` if `value_1` is equal to `value_2', otherwise it returns `value_1'. +The `NULLIF` function returns `NULL` if `value_1` is equal to `value_2`, otherwise it returns `value_1`. ### Examples with the NULLIF function -- If the value of the first argument is equal to the value of the second argument, `NULL` is returned. +**MySQL** + +- If the value of the first argument is equal to the value of the second argument, then `NULL` is returned. ```sql SELECT NULLIF("SQL Academy", "SQL Academy") AS sql_trainer; @@ -213,12 +471,46 @@ The `NULLIF` function returns `NULL` if `value_1` is equal to `value_2', otherwi | ----------- | | null | -- If the values of the first and second arguments are different, the value of the first argument is returned. +**PostgreSQL** + +- If the value of the first argument is equal to the value of the second argument, then `NULL` is returned. ```sql - SELECT NULLIF("SQL Academy", 'Alternative SQL Academy") AS sql_trainer; + SELECT NULLIF('SQL Academy', 'SQL Academy') AS sql_trainer; + ``` + + | nullif | + | ------ | + | null | + +**MySQL** + +- If the values of the first and second arguments are different, then the value of the first argument is returned. + + ```sql + SELECT NULLIF("SQL Academy", "Alternative SQL Academy") AS sql_trainer; ``` | sql_trainer | | ----------- | | SQL Academy | + +**PostgreSQL** + +- If the values of the first and second arguments are different, then the value of the first argument is returned. + + ```sql + SELECT NULLIF('SQL Academy', 'Alternative SQL Academy') AS sql_trainer; + ``` + + | nullif | + | ----------- | + | SQL Academy | + +### When to use each function: + +- **CASE**: When you need complex conditional logic with multiple conditions +- **COALESCE**: When you need to replace NULL values with default values +- **NULLIF**: When you need to turn specific values into NULL + +These functions make code more readable and are part of the SQL standard. diff --git a/course/module-3/inner-join/article.md b/course/module-3/inner-join/article.md index 2f03558..2d31d59 100644 --- a/course/module-3/inner-join/article.md +++ b/course/module-3/inner-join/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'INNER JOIN' - description: 'Description and syntax of INNER JOIN' + title: "INNER JOIN" + description: "Description and syntax of INNER JOIN" --- # INNER JOIN @@ -30,6 +30,8 @@ FROM table_1 For example, a query might look like this: +Family database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/inner-join). + ```sql SELECT family_member, member_name FROM Payments INNER JOIN FamilyMembers @@ -62,7 +64,7 @@ It creates a new table that includes fields from both the first and second table Visually, this looks like: -![Concept of Inner Join](https://sql-academy.org/static/guidePage/inner-join/inner-join-example.png 'Concept of Inner Join') +![Concept of Inner Join](https://sql-academy.org/static/guidePage/inner-join/inner-join-example.png "Concept of Inner Join") Since our condition specifies that `Payments.good_id` is equal to `Goods.good_id`, only the records where both tables have the same `good_id` value will be included in the resulting query. diff --git a/course/module-3/limit/article.md b/course/module-3/limit/article.md index ab06a3f..776cdd4 100644 --- a/course/module-3/limit/article.md +++ b/course/module-3/limit/article.md @@ -1,16 +1,16 @@ --- meta: - title: "Selection restriction, LIMIT operator" - description: "Description and syntax of the SQL limit statement, usage examples, and tasks for self-checking." + title: "Selection restriction, LIMIT operator" + description: "Description and syntax of the SQL limit statement, usage examples, and tasks for self-checking." --- # Selection restriction, LIMIT operator -The `LIMIT` operator allows you to extract a specific a range of records from one or more tables. +The `LIMIT` operator allows you to extract a specific range of records from one or more tables. ## General query structure with the LIMIT operator - +**MySQL** **Comma syntax:** @@ -30,9 +30,7 @@ LIMIT number_of_records_to_output [OFFSET number_of_skipped_records]; If you do not specify the number of skipped records, they will be counted from the beginning of the table. - - - +**PostgreSQL** ```sql SELECT table_fields @@ -42,38 +40,48 @@ LIMIT number_of_records_to_output [OFFSET number_of_skipped_records]; If you do not specify `OFFSET`, they will be counted from the beginning of the table. - - ## Examples Let's take a `Company` table: +| id | name | +| --- | ---------- | +| 1 | Don_avia | +| 2 | Aeroflot | +| 3 | Dale_avia | +| 4 | air_France | +| 5 | British_AW | + To output lines 3 to 5, you need to use this request: - +**MySQL** -```sql-executable-Airo +```sql SELECT * FROM Company LIMIT 2, 3; ``` Or what's the same thing: -```sql-executable-Airo +```sql SELECT * FROM Company LIMIT 3 OFFSET 2; ``` - +**PostgreSQL** - - -```sql-executable-Airo +```sql SELECT * FROM Company LIMIT 3 OFFSET 2; ``` - - The query returns the following selection: +| id | name | +| --- | ---------- | +| 3 | Dale_avia | +| 4 | air_France | +| 5 | British_AW | + This query skips the first two rows of the table (1, 2), and then outputs the next three entries (3, 4, 5). Now try it yourself ⚡️ + +The interactive demonstration is available [in the SQL Academy lesson](https://sql-academy.org/en/guide/limit). diff --git a/course/module-3/multi-table-request-join/article.md b/course/module-3/multi-table-request-join/article.md index 44539c4..6b3ae42 100644 --- a/course/module-3/multi-table-request-join/article.md +++ b/course/module-3/multi-table-request-join/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Multi-table queries, JOIN operator' - description: 'Description and syntax of SQL JOIN operator, examples of usage and self-check tasks' + title: "Multi-table queries, JOIN operator" + description: "Description and syntax of SQL JOIN operator, examples of usage and self-check tasks" --- # Multi-table queries, JOIN operator @@ -38,8 +38,11 @@ SELECT family_member, amount * unit_price AS price FROM Payments The `family_member` field in the resulting selection displays the record identifiers from the `Payments` table, but they mean little to us. Instead of these identifiers, it would be much more informative to output the names of those who made the purchases (the `member_name` field from the `FamilyMember` table). + This is exactly why table joining and the JOIN operator exist. +Family database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/multi-table-request-join). + ## The general structure of a multi-table query ```sql @@ -53,8 +56,8 @@ FROM table_1 As can be seen from the structure, joining can be: -- internal `INNER` (by default) -- outer `OUTER`, in which case the outer connection is divided into `LEFT`, `RIGHT`, and `FULL`. +- internal `INNER` (by default) +- outer `OUTER`, in which case the outer connection is divided into `LEFT`, `RIGHT`, and `FULL`. We will learn in more detail in the next articles what the difference is between internal and external joining and how they work. @@ -98,7 +101,7 @@ In our case, the `family_member` field points to the identifier in the `FamilyMe ## Output of all columns from a table in a multi-table query - Previously, when all queries were executed on one table, it was enough to specify the `*` character to output all fields from this table. Now, when there can be several tables, `*` will mean "output all columns from the tables listed in the expression `FROM`". +Previously, when all queries were executed on one table, it was enough to specify the `*` character to output all fields from this table. Now, when there can be several tables, `*` will mean "output all columns from the tables listed in the expression `FROM`". In some cases, we may need to output columns belonging only to a particular table. For example, the connection of the `Payments` and `FamilyMembers` tables is given, and only the fields from the `FamilyMembers` table should be output to the final selection. How to do it? It's very simple! It is necessary to add the name of the table before the `*` symbol: @@ -176,5 +179,5 @@ INNER JOIN Pass_in_trip When using aliases, always follow these simple rules to keep your queries concise and clear: -- Use logical abbreviations (e.g., first letters of the table name) -- Avoid overly short (single-character) or non-intuitive aliases +- Use logical abbreviations (e.g., first letters of the table name) +- Avoid overly short (single-character) or non-intuitive aliases diff --git a/course/module-3/nested-sql-queries/article.md b/course/module-3/nested-sql-queries/article.md index 064ac43..d76e7ff 100644 --- a/course/module-3/nested-sql-queries/article.md +++ b/course/module-3/nested-sql-queries/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Subqueries in SQL' - description: 'Subqueries, nested queries in SQL. Their types and usage.' + title: "Subqueries in SQL" + description: "Subqueries, nested queries in SQL. Their types and usage." --- # Subqueries diff --git a/course/module-3/operator-with/article.md b/course/module-3/operator-with/article.md index 33b2656..d6ca7dd 100644 --- a/course/module-3/operator-with/article.md +++ b/course/module-3/operator-with/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Common Table Expressions, operator WITH" - description: "Common Table Expression in SQL. Syntax of the WITH statement and examples of its use." + title: "Common Table Expressions, operator WITH" + description: "Common Table Expression in SQL. Syntax of the WITH statement and examples of its use." --- # Common Table Expressions, operator WITH @@ -9,7 +9,7 @@ meta: Common Table Expressions is a temporary dataset that can be accessed in subsequent queries. The `WITH` operator is used to write a common table expressions. -```sql-Trip-executable +```sql -- Example of using the WITH clause WITH Aeroflot_trips AS (SELECT TRIP.* FROM Company @@ -40,9 +40,11 @@ How to use the `WITH` operator: ## Query examples +Airo database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/operator-with). + 1. We create a common table expression `Aeroflot_trips` containing all the flights made by the Aeroflot airline -```sql-Trip-executable +```sql WITH Aeroflot_trips AS (SELECT plane, town_from, town_to FROM Company INNER JOIN Trip ON Trip.company = Company.id WHERE name = 'Aeroflot') @@ -50,9 +52,14 @@ WITH Aeroflot_trips AS SELECT * FROM Aeroflot_trips; ``` +| plane | town_from | town_to | +| ----- | --------- | ------- | +| IL-86 | Moscow | Rostov | +| IL-86 | Rostov | Moscow | + 2. Similarly, we create a common table expression `Aeroflot_trips`, but with renamed columns -```sql-Trip-executable +```sql WITH Aeroflot_trips (aeroflot_plane, town_from, town_to) AS (SELECT plane, town_from, town_to FROM Company INNER JOIN Trip ON Trip.company = Company.id WHERE name = 'Aeroflot') @@ -60,9 +67,14 @@ WITH Aeroflot_trips (aeroflot_plane, town_from, town_to) AS SELECT * FROM Aeroflot_trips; ``` +| aeroflot_plane | town_from | town_to | +| -------------- | --------- | ------- | +| IL-86 | Moscow | Rostov | +| IL-86 | Rostov | Moscow | + 3. Using the `WITH` operator, we define several common table expressions -```sql-Trip-executable +```sql WITH Aeroflot_trips AS (SELECT TRIP.* FROM Company INNER JOIN Trip ON Trip.company = Company.id WHERE name = 'Aeroflot'), @@ -73,6 +85,17 @@ WITH Aeroflot_trips AS SELECT * FROM Don_avia_trips UNION SELECT * FROM Aeroflot_trips; ``` +| id | company | plane | town_from | town_to | time_out | time_in | +| ---- | ------- | ------ | --------- | ------- | ------------------------ | ------------------------ | +| 1181 | 1 | TU-134 | Rostov | Moscow | 1900-01-01T06:12:00.000Z | 1900-01-01T08:01:00.000Z | +| 1182 | 1 | TU-134 | Moscow | Rostov | 1900-01-01T12:35:00.000Z | 1900-01-01T14:30:00.000Z | +| 1187 | 1 | TU-134 | Rostov | Moscow | 1900-01-01T15:42:00.000Z | 1900-01-01T17:39:00.000Z | +| 1188 | 1 | TU-134 | Moscow | Rostov | 1900-01-01T22:50:00.000Z | 1900-01-02T00:48:00.000Z | +| 1195 | 1 | TU-154 | Rostov | Moscow | 1900-01-01T23:30:00.000Z | 1900-01-02T01:11:00.000Z | +| 1196 | 1 | TU-154 | Moscow | Rostov | 1900-01-01T04:00:00.000Z | 1900-01-01T05:45:00.000Z | +| 1145 | 2 | IL-86 | Moscow | Rostov | 1900-01-01T09:35:00.000Z | 1900-01-01T11:23:00.000Z | +| 1146 | 2 | IL-86 | Rostov | Moscow | 1900-01-01T17:55:00.000Z | 1900-01-01T20:01:00.000Z | + ## Working with recursion in CTE CTEs can also be used to perform recursive queries, which allow iterative data processing, for example, working with hierarchical data structures such as manager-subordinate relationships. @@ -107,6 +130,15 @@ SELECT * FROM cte_name; Consider the `Employees` table, which contains employee IDs and their managers: +| id | name | managerId | +| --- | --------------- | --------- | +| 1 | John Smith | null | +| 2 | Michael Johnson | 1 | +| 3 | Robert Williams | 1 | +| 4 | James Brown | 2 | +| 5 | David Jones | 2 | +| 6 | Richard Davis | 3 | + We need to find all subordinates of John Smith (`id=1`) at all hierarchy levels. ```sql @@ -127,11 +159,19 @@ WITH RECURSIVE Subordinates AS ( SELECT * FROM Subordinates; ``` +| id | name | managerId | +| --- | --------------- | --------- | +| 2 | Michael Johnson | 1 | +| 3 | Robert Williams | 1 | +| 4 | James Brown | 2 | +| 5 | David Jones | 2 | +| 6 | Richard Davis | 3 | + ### Steps for executing a recursive CTE 1. **Initial dataset:** selects all employees whose `managerId=1` (direct subordinates of `John Smith`). 2. **Recursive part:** for each employee selected in the initial dataset, selects their subordinates (where `managerId` equals the `id` of the chosen employee). -3. **Union:** рunites the results of the initial dataset and the recursive parts using `UNION ALL`. +3. **Union:** unites the results of the initial dataset and the recursive parts using `UNION ALL`. 4. **Recursion:** the process repeats for each new set of subordinates until all hierarchy levels are retrieved. ## Conclusion diff --git a/course/module-3/outer-join/article.md b/course/module-3/outer-join/article.md index 0ff468c..25d8702 100644 --- a/course/module-3/outer-join/article.md +++ b/course/module-3/outer-join/article.md @@ -1,236 +1,234 @@ --- meta: - title: "Outer join" - description: "Description and syntax of outer join" + title: "Outer join" + description: "How LEFT, RIGHT and FULL OUTER JOIN work: rows without a match, NULL in the result and why the result grows" --- # Outer Join -An outer join can be of three types: (`LEFT`), (`RIGHT`), and (`FULL`). By default, it is full. +An inner join keeps only the rows that found a match in the other table. An outer join works differently: it always returns every row of one table or of both, filling the missing half with `NULL`. -The main difference between an outer join and an inner join is that it must return all rows of one (`LEFT`, `RIGHT`) or both tables (`FULL`). +There are three kinds of outer join: left (`LEFT`), right (`RIGHT`) and full (`FULL`). The kind is mandatory — a bare `OUTER JOIN` is a syntax error. The word `OUTER` itself is optional: `LEFT JOIN` and `LEFT OUTER JOIN` mean exactly the same, and the shorter form is used below. -## LEFT OUTER JOIN - -A join that returns all values from the left table joined with corresponding values from the right table -if they satisfy the join condition, or replaces them with `NULL` otherwise. - -For example, let's get the schedule of classes from a database, joined with the corresponding time pairs in the schedule. +> Do not confuse this with a bare `JOIN` — that is an inner join, the same as `INNER JOIN`. -Data in the `Timepair` table: +## LEFT OUTER JOIN -Data in the `Schedule` table +Returns every row of the left table. If a row finds a match in the right table, the two rows are glued together; if it does not, the right table columns are filled with `NULL`. + +For example, let's get the schedule of calls from the database, joined with the corresponding classes in the schedule. + +Schedule database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/outer-join). + +Data in the `Timepair` table (schedule of calls): + +| id | start_pair | end_pair | +| --- | ---------- | -------- | +| 1 | 08:30:00 | 09:15:00 | +| 2 | 09:20:00 | 10:05:00 | +| 3 | 10:15:00 | 11:00:00 | +| 4 | 11:05:00 | 11:50:00 | +| 5 | 12:50:00 | 13:35:00 | +| 6 | 13:40:00 | 14:25:00 | +| 7 | 14:35:00 | 15:20:00 | +| 8 | 15:25:00 | 16:10:00 | + +Data in the `Schedule` table (schedule of classes): + +| id | date | class | number_pair | teacher | subject | classroom | +| --- | ------------------------ | ----- | ----------- | ------- | ------- | --------- | +| 1 | 2019-09-01T00:00:00.000Z | 9 | 1 | 11 | 1 | 47 | +| 2 | 2019-09-01T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 3 | 2019-09-01T00:00:00.000Z | 9 | 3 | 4 | 3 | 13 | +| 4 | 2019-09-02T00:00:00.000Z | 9 | 1 | 4 | 3 | 13 | +| 5 | 2019-09-02T00:00:00.000Z | 9 | 2 | 2 | 4 | 34 | +| 6 | 2019-09-02T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 7 | 2019-09-03T00:00:00.000Z | 9 | 1 | 5 | 6 | 36 | +| 8 | 2019-09-03T00:00:00.000Z | 9 | 2 | 13 | 7 | 37 | +| 9 | 2019-09-03T00:00:00.000Z | 9 | 3 | 6 | 8 | 38 | +| 10 | 2019-09-04T00:00:00.000Z | 9 | 1 | 9 | 9 | 39 | +| 11 | 2019-09-04T00:00:00.000Z | 9 | 2 | 10 | 10 | 40 | +| 12 | 2019-09-04T00:00:00.000Z | 9 | 3 | 3 | 11 | 41 | +| 13 | 2019-09-05T00:00:00.000Z | 9 | 1 | 3 | 13 | 43 | +| 14 | 2019-09-05T00:00:00.000Z | 9 | 2 | 11 | 1 | 47 | +| 15 | 2019-09-05T00:00:00.000Z | 9 | 3 | 5 | 6 | 36 | +| 16 | 2019-08-30T00:00:00.000Z | 9 | 1 | 2 | 4 | 34 | +| 17 | 2019-08-30T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 18 | 2019-08-30T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 19 | 2019-08-30T00:00:00.000Z | 9 | 4 | 10 | 1 | 47 | +| 20 | 2019-09-03T00:00:00.000Z | 9 | 4 | 10 | 10 | 40 | +| 21 | 2019-08-30T00:00:00.000Z | 8 | 1 | 7 | 9 | 53 | +| 22 | 2019-08-30T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 23 | 2019-08-30T00:00:00.000Z | 8 | 3 | 8 | 2 | 38 | +| 24 | 2019-08-30T00:00:00.000Z | 8 | 4 | 11 | 1 | 43 | +| 25 | 2019-08-30T00:00:00.000Z | 8 | 5 | 8 | 3 | 39 | +| 26 | 2019-09-01T00:00:00.000Z | 8 | 2 | 2 | 4 | 34 | +| 27 | 2019-09-01T00:00:00.000Z | 8 | 3 | 6 | 5 | 35 | +| 28 | 2019-09-01T00:00:00.000Z | 8 | 4 | 12 | 6 | 36 | +| 29 | 2019-09-01T00:00:00.000Z | 8 | 5 | 13 | 7 | 37 | +| 30 | 2019-09-02T00:00:00.000Z | 8 | 3 | 6 | 8 | 38 | +| 31 | 2019-09-02T00:00:00.000Z | 8 | 4 | 7 | 9 | 53 | +| 32 | 2019-09-03T00:00:00.000Z | 8 | 1 | 10 | 10 | 40 | +| 33 | 2019-09-03T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 34 | 2019-09-03T00:00:00.000Z | 8 | 3 | 7 | 9 | 53 | +| 35 | 2019-09-04T00:00:00.000Z | 8 | 1 | 1 | 11 | 4 | +| 36 | 2019-09-04T00:00:00.000Z | 8 | 2 | 1 | 12 | 42 | +| 37 | 2019-09-04T00:00:00.000Z | 8 | 3 | 3 | 13 | 43 | +| 38 | 2019-09-04T00:00:00.000Z | 8 | 4 | 8 | 2 | 42 | +| 39 | 2019-09-04T00:00:00.000Z | 8 | 5 | 11 | 1 | 43 | +| 40 | 2019-09-05T00:00:00.000Z | 8 | 2 | 11 | 1 | 43 | -```sql-executable-Schedule -SELECT Timepair.id 'timepair.id', start_pair, end_pair, - Schedule.id 'schedule.id', date, class, number_pair, teacher, subject, classroom +```sql +SELECT Timepair.id "timepair.id", start_pair, end_pair, + Schedule.id "schedule.id", date, class, number_pair, teacher, subject, classroom FROM Timepair LEFT JOIN Schedule ON Schedule.number_pair = Timepair.id; ``` -The selection includes all rows from the left table, supplemented with data about classes. -Note that there are rows at the end of the table with fields filled with `NULL`. -These are the rows for which corresponding classes were not found, but they are present in the left table, so they were also output. +| timepair.id | start_pair | end_pair | schedule.id | date | class | number_pair | teacher | subject | classroom | +| ----------- | ---------- | -------- | ----------- | ------------------------ | ----- | ----------- | ------- | ------- | --------- | +| 1 | 08:30:00 | 09:15:00 | 35 | 2019-09-04T00:00:00.000Z | 8 | 1 | 1 | 11 | 4 | +| 1 | 08:30:00 | 09:15:00 | 32 | 2019-09-03T00:00:00.000Z | 8 | 1 | 10 | 10 | 40 | +| 1 | 08:30:00 | 09:15:00 | 21 | 2019-08-30T00:00:00.000Z | 8 | 1 | 7 | 9 | 53 | +| 1 | 08:30:00 | 09:15:00 | 16 | 2019-08-30T00:00:00.000Z | 9 | 1 | 2 | 4 | 34 | +| 1 | 08:30:00 | 09:15:00 | 13 | 2019-09-05T00:00:00.000Z | 9 | 1 | 3 | 13 | 43 | +| 1 | 08:30:00 | 09:15:00 | 10 | 2019-09-04T00:00:00.000Z | 9 | 1 | 9 | 9 | 39 | +| 1 | 08:30:00 | 09:15:00 | 7 | 2019-09-03T00:00:00.000Z | 9 | 1 | 5 | 6 | 36 | +| 1 | 08:30:00 | 09:15:00 | 4 | 2019-09-02T00:00:00.000Z | 9 | 1 | 4 | 3 | 13 | +| 1 | 08:30:00 | 09:15:00 | 1 | 2019-09-01T00:00:00.000Z | 9 | 1 | 11 | 1 | 47 | +| 2 | 09:20:00 | 10:05:00 | 40 | 2019-09-05T00:00:00.000Z | 8 | 2 | 11 | 1 | 43 | +| 2 | 09:20:00 | 10:05:00 | 36 | 2019-09-04T00:00:00.000Z | 8 | 2 | 1 | 12 | 42 | +| 2 | 09:20:00 | 10:05:00 | 33 | 2019-09-03T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 2 | 09:20:00 | 10:05:00 | 26 | 2019-09-01T00:00:00.000Z | 8 | 2 | 2 | 4 | 34 | +| 2 | 09:20:00 | 10:05:00 | 22 | 2019-08-30T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 2 | 09:20:00 | 10:05:00 | 17 | 2019-08-30T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 2 | 09:20:00 | 10:05:00 | 14 | 2019-09-05T00:00:00.000Z | 9 | 2 | 11 | 1 | 47 | +| 2 | 09:20:00 | 10:05:00 | 11 | 2019-09-04T00:00:00.000Z | 9 | 2 | 10 | 10 | 40 | +| 2 | 09:20:00 | 10:05:00 | 8 | 2019-09-03T00:00:00.000Z | 9 | 2 | 13 | 7 | 37 | +| 2 | 09:20:00 | 10:05:00 | 5 | 2019-09-02T00:00:00.000Z | 9 | 2 | 2 | 4 | 34 | +| 2 | 09:20:00 | 10:05:00 | 2 | 2019-09-01T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 3 | 10:15:00 | 11:00:00 | 37 | 2019-09-04T00:00:00.000Z | 8 | 3 | 3 | 13 | 43 | +| 3 | 10:15:00 | 11:00:00 | 34 | 2019-09-03T00:00:00.000Z | 8 | 3 | 7 | 9 | 53 | +| 3 | 10:15:00 | 11:00:00 | 30 | 2019-09-02T00:00:00.000Z | 8 | 3 | 6 | 8 | 38 | +| 3 | 10:15:00 | 11:00:00 | 27 | 2019-09-01T00:00:00.000Z | 8 | 3 | 6 | 5 | 35 | +| 3 | 10:15:00 | 11:00:00 | 23 | 2019-08-30T00:00:00.000Z | 8 | 3 | 8 | 2 | 38 | +| 3 | 10:15:00 | 11:00:00 | 18 | 2019-08-30T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 3 | 10:15:00 | 11:00:00 | 15 | 2019-09-05T00:00:00.000Z | 9 | 3 | 5 | 6 | 36 | +| 3 | 10:15:00 | 11:00:00 | 12 | 2019-09-04T00:00:00.000Z | 9 | 3 | 3 | 11 | 41 | +| 3 | 10:15:00 | 11:00:00 | 9 | 2019-09-03T00:00:00.000Z | 9 | 3 | 6 | 8 | 38 | +| 3 | 10:15:00 | 11:00:00 | 6 | 2019-09-02T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 3 | 10:15:00 | 11:00:00 | 3 | 2019-09-01T00:00:00.000Z | 9 | 3 | 4 | 3 | 13 | +| 4 | 11:05:00 | 11:50:00 | 38 | 2019-09-04T00:00:00.000Z | 8 | 4 | 8 | 2 | 42 | +| 4 | 11:05:00 | 11:50:00 | 31 | 2019-09-02T00:00:00.000Z | 8 | 4 | 7 | 9 | 53 | +| 4 | 11:05:00 | 11:50:00 | 28 | 2019-09-01T00:00:00.000Z | 8 | 4 | 12 | 6 | 36 | +| 4 | 11:05:00 | 11:50:00 | 24 | 2019-08-30T00:00:00.000Z | 8 | 4 | 11 | 1 | 43 | +| 4 | 11:05:00 | 11:50:00 | 20 | 2019-09-03T00:00:00.000Z | 9 | 4 | 10 | 10 | 40 | +| 4 | 11:05:00 | 11:50:00 | 19 | 2019-08-30T00:00:00.000Z | 9 | 4 | 10 | 1 | 47 | +| 5 | 12:50:00 | 13:35:00 | 39 | 2019-09-04T00:00:00.000Z | 8 | 5 | 11 | 1 | 43 | +| 5 | 12:50:00 | 13:35:00 | 29 | 2019-09-01T00:00:00.000Z | 8 | 5 | 13 | 7 | 37 | +| 5 | 12:50:00 | 13:35:00 | 25 | 2019-08-30T00:00:00.000Z | 8 | 5 | 8 | 3 | 39 | +| 6 | 13:40:00 | 14:25:00 | null | null | null | null | null | null | null | +| 7 | 14:35:00 | 15:20:00 | null | null | null | null | null | null | null | +| 8 | 15:25:00 | 16:10:00 | null | null | null | null | null | null | null | + +All eight calls made it into the result, exactly as a left join promises. But the result has 43 rows, not 8. + +A join does not supplement the left table — it goes through every matching pair of rows. The same pair number appears in the schedule many times, on different days and for different classes, and every match produces its own row. When the key is not unique in the right table, the result has more rows than the left table. + +At the end of the result there are rows where every class column is `NULL`. These are the calls with no class at all: there is no match, but a row of the left table is guaranteed to appear in the result. + +### Rows without a match + +Those `NULL` values are the basis of the most common practical trick — finding records that have no match. It is enough to keep only the rows where the key of the right table is empty: -## RIGHT OUTER JOIN - -A join that returns all values from the right table joined with corresponding values from the left table if they satisfy the join condition, or replaces them with `NULL` otherwise. +```sql +SELECT Timepair.id, start_pair, end_pair +FROM Timepair + LEFT JOIN Schedule ON Schedule.number_pair = Timepair.id +WHERE Schedule.number_pair IS NULL; +``` - +| id | start_pair | end_pair | +| --- | ---------- | -------- | +| 6 | 13:40:00 | 14:25:00 | +| 7 | 14:35:00 | 15:20:00 | +| 8 | 15:25:00 | 16:10:00 | -## FULL OUTER JOIN +Three calls are left — the ones with no class scheduled. -A join that performs an inner join of records and supplements them with a left outer join and a right outer join. +A join from which only the rows without a match are kept is called an **anti join** (`ANTI JOIN`). It has no operator of its own: both in MySQL and in PostgreSQL it is written exactly like this — a join plus an `IS NULL` condition. -The algorithm of the full join: +## RIGHT OUTER JOIN -- A table is formed based on the inner join. -- Values that did not enter the result of the formation from the left table are added to the table -- Values that did not enter the result of the formation from the right table are added to the table +The mirror image of the left join: every row of the right table is guaranteed to appear in the result, and the missing columns of the left table are filled with `NULL`. - +```sql +SELECT Timepair.id "timepair.id", start_pair, end_pair, + Schedule.id "schedule.id", date, class, number_pair, teacher, subject, classroom +FROM Timepair + RIGHT JOIN Schedule ON Schedule.number_pair = Timepair.id; +``` - +The result has 40 rows — exactly as many as there are records in `Schedule` — and not a single row with `NULL`. In other words, it matches the inner join completely. -## Emulating Full Join in MySQL +That happened because every class refers to an existing call: the right table simply has no unmatched rows. The kind of join sets the rule, but what ends up in the result is decided by the data. -Since MySQL does not support `FULL OUTER JOIN`, it can be emulated using `UNION ALL`: +## FULL OUTER JOIN -```sql -SELECT * -FROM left_table -LEFT JOIN right_table - ON right_table.key = left_table.key +Returns every row of both tables. Rows that found a match are glued together, while unmatched rows of the left and right tables appear in the result with `NULL` instead of the missing half. -UNION ALL +The result of a full join is made of three parts: -SELECT * -FROM left_table -RIGHT JOIN right_table -ON right_table.key = left_table.key - WHERE left_table.key IS NULL -``` +- the rows of the inner join (`INNER JOIN`); +- the rows of the left table that found no match; +- the rows of the right table that found no match. - - -## Basic queries for different types of table joins: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +2. Exactly eight: a left join returns all rows of the left table — All eight rows do appear in the result, but a row with several matches is multiplied — the result grows beyond eight rows. -
SchemaJOIN query
- - - Retrieving all data from the left table joined with corresponding data from the right table: - ```sql - SELECT table_fields - FROM left_table LEFT JOIN right_table - ON right_table.key = left_table.key - ``` -
- - - Retrieving all data from the right table joined with corresponding data from the left table: - ```sql - SELECT table_fields - FROM left_table RIGHT JOIN right_table - ON right_table.key = left_table.key - ``` -
- - - Retrieving data that only belongs to the left table: - ```sql - SELECT table_fields - FROM left_table LEFT JOIN right_table - ON right_table.key = left_table.key - WHERE right_table.key IS NULL - ``` -
- - - Retrieving data that only belongs to the right table: - ```sql - SELECT table_fields - FROM left_table RIGHT JOIN right_table - ON right_table.key = left_table.key - WHERE left_table.key IS NULL - ``` -
- - - Retrieving data that belongs to both the left and right tables: - ```sql - SELECT table_fields - FROM left_table INNER JOIN right_table - ON right_table.key = left_table.key - ``` -
- - - Retrieving all data that belongs to both the left and right tables, as well as their inner join: - - +**PostgreSQL** ```sql -SELECT table_fields -FROM left_table - FULL OUTER JOIN right_table - ON right_table.key = left_table.key +SELECT Timepair.id "timepair.id", start_pair, end_pair, + Schedule.id "schedule.id", date, class, number_pair, teacher, subject, classroom +FROM Timepair + FULL OUTER JOIN Schedule ON Schedule.number_pair = Timepair.id; ``` - +On the data of this database the result matches the left join — the same 43 rows: here the unmatched rows exist only on the left. - +**MySQL** + +MySQL does not support `FULL OUTER JOIN`, but the same result can be assembled by hand: take the left join and add the rows of the right table that found no match. ```sql SELECT table_fields FROM left_table -LEFT JOIN right_table - ON right_table.key = left_table.key + LEFT JOIN right_table ON right_table.key = left_table.key UNION ALL SELECT table_fields FROM left_table -RIGHT JOIN right_table - ON right_table.key = left_table.key -WHERE left_table.key IS NULL -``` - - - -
- - - Retrieving data that does not belong to both the left and right tables simultaneously (reverse INNER JOIN): - - - -```sql -SELECT table_fields -FROM left_table - FULL OUTER JOIN right_table - ON right_table.key = left_table.key -WHERE left_table.key IS NULL - OR right_table.key IS NULL + RIGHT JOIN right_table ON right_table.key = left_table.key +WHERE left_table.key IS NULL; ``` - - - +The condition in the second part is required: without it the matched rows would appear in the result twice. -```sql -SELECT table_fields -FROM left_table -LEFT JOIN right_table - ON right_table.key = left_table.key -WHERE right_table.key IS NULL +## All types of table joins -UNION ALL +| Join type | Result | Rows in the example | +| ----------------- | ----------------------------------- | ------------------: | +| `LEFT JOIN` | All rows of the left table | 4 | +| `INNER JOIN` | Only matching rows | 3 | +| `RIGHT JOIN` | All rows of the right table | 4 | +| `FULL JOIN` | All rows of both tables | 5 | +| `LEFT ANTI JOIN` | Left table without a match | 1 | +| `RIGHT ANTI JOIN` | Right table without a match | 1 | +| `FULL ANTI JOIN` | Everything except the matching rows | 2 | -SELECT table_fields -FROM left_table -RIGHT JOIN right_table - ON right_table.key = left_table.key -WHERE left_table.key IS NULL -``` +Let's check yourself. The left table has 8 rows. How many rows will a `LEFT JOIN` with the right table return? - +1. **Correct answer:** Eight or more — it depends on how many matches were found — Every row of the left table is guaranteed to appear in the result, but a row with several matches in the right table produces several rows. -
+3. No more than eight: the extra rows of the right table are dropped — Only the unmatched rows of the right table are dropped. Matches are not dropped: each one produces its own row of the result. diff --git a/course/module-3/subquery-with-one-column-one-row/article.md b/course/module-3/subquery-with-one-column-one-row/article.md index 4f3d54c..264e7e8 100644 --- a/course/module-3/subquery-with-one-column-one-row/article.md +++ b/course/module-3/subquery-with-one-column-one-row/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Subquery with one row and one column" - description: "Scalar subqueries in SQL, examples and syntax" + title: "Subquery with one row and one column" + description: "Scalar subqueries in SQL, examples and syntax" --- # Subquery with one row and one column @@ -17,17 +17,25 @@ in selection restriction conditions using comparison operators (`=`, `<>`, `>`, The following simplest query demonstrates the output of a single value (company name). In this form, it doesn't make much sense, but your queries can be much more complex. -```sql-executable-Trip +```sql SELECT (SELECT name FROM company LIMIT 1) AS company_name; ``` +| company_name | +| ------------ | +| Don_avia | + Similarly, scalar subqueries can be used to filter rows using `WHERE`, using comparison operators. -```sql-executable-Family +```sql SELECT * FROM FamilyMembers WHERE birthday = (SELECT MAX(birthday) FROM FamilyMembers); ``` +| member_id | status | member_name | birthday | +| --------- | -------- | ---------------- | ------------------------ | +| 8 | daughter | Wednesday Addams | 2005-01-13T00:00:00.000Z | + With this query, it is possible to obtain the youngest family member. The subquery in this case is necessary to obtain the maximum date of birth, which is then used in the main query to filter rows. @@ -35,19 +43,15 @@ The subquery in this case is necessary to obtain the maximum date of birth, whic When using the result of a subquery with comparison operators, as in our example, it is important that the subquery returns exactly a scalar value (1 row and 1 column). - +**MySQL** If this subquery returned multiple values, the DBMS would return an error, indicating that it expected the subquery to return only 1 record: «ER_SUBQUERY_NO_1_ROW: Subquery returns more than 1 row». - - - +**PostgreSQL** If this subquery returned multiple values, the DBMS would return an error, indicating that it expected the subquery to return only 1 record: «ERROR: more than one row returned by a subquery used as an expression». - - Therefore, it is important to be careful when writing subqueries and to understand what result the subquery will return, and what operators we can use together with the resulting set. diff --git a/course/module-3/subquery-with-one-column-several-row/article.md b/course/module-3/subquery-with-one-column-several-row/article.md index 4220f74..427c410 100644 --- a/course/module-3/subquery-with-one-column-several-row/article.md +++ b/course/module-3/subquery-with-one-column-several-row/article.md @@ -1,12 +1,12 @@ --- meta: - title: 'Subqueries with multiple rows and one column' - description: 'Subqueries using ANY, IN, ALL operators' + title: "Subqueries with multiple rows and one column" + description: "Subqueries using ANY, IN, ALL operators" --- # Subqueries with multiple rows and one column -If a subquery returns more than one row, it cannot be used with comparison operators in the same way as scalar subqueries could be used as described here. +If a subquery returns more than one row, it cannot be used with comparison operators in the same way as scalar subqueries could be used as described here. However, with subqueries that return multiple rows and one column, there are three additional operators that can be used. @@ -24,26 +24,30 @@ SELECT 200 > ALL(SELECT price FROM Rooms) Or a more practical example: we need to find the names of all property owners who have never rented out their property themselves. To obtain this list, we can proceed as follows: +Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/subquery-with-one-column-several-row). + - Get a list of names of all property owners - ```sql - SELECT DISTINCT name FROM Users INNER JOIN Rooms - ON Users.id = Rooms.owner_id - ``` + + ```sql + SELECT DISTINCT name FROM Users INNER JOIN Rooms + ON Users.id = Rooms.owner_id + ``` + - Get a list of identifiers of all users who have rented out property - ```sql - SELECT DISTINCT user_id FROM Reservations - ``` + ```sql + SELECT DISTINCT user_id FROM Reservations + ``` - Filter the first list of all property owners by the condition that the property owner identifier is not equal to any of the identifiers of users who have ever rented out property - ```sql - SELECT DISTINCT name FROM Users INNER JOIN Rooms - ON Users.id = Rooms.owner_id - WHERE Users.id <> ALL ( - SELECT DISTINCT user_id FROM Reservations - ) - ``` + ```sql + SELECT DISTINCT name FROM Users INNER JOIN Rooms + ON Users.id = Rooms.owner_id + WHERE Users.id <> ALL ( + SELECT DISTINCT user_id FROM Reservations + ) + ``` ## Subquery and IN operator diff --git a/course/module-3/subquery-with-several-column/article.md b/course/module-3/subquery-with-several-column/article.md index 2389ab4..fc5d55e 100644 --- a/course/module-3/subquery-with-several-column/article.md +++ b/course/module-3/subquery-with-several-column/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Multi-column subqueries' - description: 'Multi-column subqueries in SQL, subqueries with arbitrary table and comparison with multiple columns in SQL.' + title: "Multi-column subqueries" + description: "Multi-column subqueries in SQL, subqueries with arbitrary table and comparison with multiple columns in SQL." --- # Multi-column subqueries @@ -14,6 +14,8 @@ SQL supports comparison not only with a single column, but also allows pairwise For example, if we want to get information about all reservations where the accommodation price at the time of booking (`Reservations.price`) matches the current price of the accommodation (`Rooms.price`), we can do it as follows: +Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/subquery-with-several-column). + ```sql SELECT * FROM Reservations WHERE (room_id, price) IN (SELECT id, price FROM Rooms); @@ -39,8 +41,8 @@ SELECT * FROM Reservations | 25 | 18 | 19 | 2019-11-01T10:00:00.000Z | 2019-11-16T10:00:00.000Z | 99 | 1485 | | 26 | 21 | 17 | 2019-11-03T09:00:00.000Z | 2019-11-05T09:00:00.000Z | 215 | 430 | | 27 | 31 | 25 | 2020-04-20T09:00:00.000Z | 2020-04-22T09:00:00.000Z | 120 | 240 | -| 28 | 21 | 14 | 2020-02-08T10:00:00Z | 2020-02-12T10:00:00Z | 85 | 340 | -| 29 | 21 | 39 | 2019-12-08T10:00:00Z | 2019-12-09T10:00:00Z | 150 | 150 | +| 28 | 21 | 14 | 2020-02-08T10:00:00.000Z | 2020-02-12T10:00:00.000Z | 85 | 340 | +| 29 | 21 | 39 | 2019-12-08T10:00:00.000Z | 2019-12-09T10:00:00.000Z | 150 | 150 | In this example, the subquery returns a table with the identifiers of residential properties and their current price: diff --git a/course/module-4/operator-delete/article.md b/course/module-4/operator-delete/article.md index 766743c..a57b528 100644 --- a/course/module-4/operator-delete/article.md +++ b/course/module-4/operator-delete/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Syntax of DELETE operator" - description: "Delete records in sql. SQL operators delete, truncate and their differences. Delete query c join" + title: "Syntax of DELETE operator" + description: "Delete records in sql. SQL operators delete, truncate and their differences. Delete query c join" --- # Syntax of DELETE operator @@ -16,7 +16,7 @@ DELETE FROM table_name [WHERE the_conditions_of_the_limitations]; ``` -If there is no `WHERE` record selection condition, then all records will be deleted the specified table. +If there is no `WHERE` record selection condition, then all records in the specified table will be deleted. The same operation (deleting all records) can also be done using `TRUNCATE` operator. It will drop the table and re-create it - this option is much faster, than deleting all records one by one (as is the case with `DELETE`) especially for large tables. @@ -26,27 +26,29 @@ The same operation (deleting all records) can also be done using `TRUNCATE` oper TRUNCATE TABLE table_name; ``` - +**MySQL** > The MySQL query optimizer automatically uses the `TRUNCATE` statement if the `DELETE` statement does not contain a `WHERE` clause or `LIMIT` constructs. - - However, the `TRUNCATE` statement has several differences: +**MySQL** + - Triggers are not processed, in particular, the delete trigger - Deletes all rows in a table without writing the deletion of individual rows of data to the transaction log -- In MySQL, resets the identifier counter to its initial value +- Resets the counter of identifiers to the initial value - To use, you must have edit rights to the table -### PostgreSQL +**PostgreSQL** -- In PostgreSQL, the identifier counter is reset only when the `RESTART IDENTITY` option is used -- By default, `CONTINUE IDENTITY` is used, so the counter is not reset after `TRUNCATE` +- Triggers are not processed, in particular, the delete trigger +- Deletes all rows in a table without writing the deletion of individual rows of data to the transaction log +- Can reset the identifier counter when using the `RESTART IDENTITY` option (`CONTINUE IDENTITY` is used by default, so the counter is not reset) +- To use, you must have edit rights to the table ## Deleting records for multi-table queries - +**MySQL** If the `DELETE` query uses a `JOIN`, you need to specify which tables should have their rows removed. @@ -57,9 +59,7 @@ ON table_name_1.field = table_name_2.field [WHERE the_conditions_of_the_limitations]; ``` - - - +**PostgreSQL** If the `DELETE` query uses `USING`, specify the additional tables that help select the rows to delete after it. @@ -70,11 +70,9 @@ WHERE table_name_1.field = table_name_2.field [AND the_conditions_of_the_limitations]; ``` - - For example, we need to delete all reservations for a home that does not have a kitchen. Then the request will look like this: - +**MySQL** ```sql DELETE Reservations FROM @@ -83,9 +81,7 @@ Reservations.room_id = Rooms.id WHERE Rooms.has_kitchen = false; ``` - - - +**PostgreSQL** ```sql DELETE FROM Reservations @@ -94,11 +90,9 @@ WHERE Reservations.room_id = Rooms.id AND Rooms.has_kitchen = false; ``` - - If, in addition to deleting the reservation, we also needed to delete the accommodation, then the query would look like this: - +**MySQL** ```sql DELETE Reservations, Rooms FROM @@ -107,9 +101,7 @@ Reservations.room_id = Rooms.id WHERE Rooms.has_kitchen = false; ``` - - - +**PostgreSQL** In PostgreSQL, to delete from multiple tables simultaneously, separate DELETE queries or transactions are used: @@ -124,5 +116,3 @@ DELETE FROM Rooms WHERE Rooms.has_kitchen = false; COMMIT; ``` - - diff --git a/course/module-4/operator-insert/article.md b/course/module-4/operator-insert/article.md index da81902..7bb0e2e 100644 --- a/course/module-4/operator-insert/article.md +++ b/course/module-4/operator-insert/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Adding data, insert statement" - description: "Adding a new record in sql. Auto-increment of the primary key when creating a row in the table. SQL insert into statement." + title: "Adding data, insert statement" + description: "Adding a new record in sql. Auto-increment of the primary key when creating a row in the table. SQL insert into statement." --- # Adding data, INSERT operator @@ -18,31 +18,130 @@ VALUES (value_of_table_field, ...) Values can be inserted by enumeration using the word `VALUES` listing them in parentheses separated by commas or using the operator `SELECT`. +## Field enumeration and value correspondence + +When using the `INSERT` operator, you can explicitly specify which fields of the table the data will be inserted into. This is done by listing the field names in parentheses after the table name: + +```sql +INSERT INTO table_name (field1, field2, field3) +VALUES (value1, value2, value3); +``` + +**Important rules:** + +- The order of values in `VALUES` must strictly correspond to the order of fields in the enumeration +- The number of values must match the number of specified fields +- If a field is not specified in the enumeration, it will receive the default value (if one is set) or `NULL` (if the field allows `NULL`) + +For example, if the `Goods` table has fields `good_id`, `good_name`, and `type`, then the following queries are equivalent: + +```sql +-- Explicit field specification +INSERT INTO Goods (good_id, good_name, type) +VALUES (20, 'Table', 2); + +-- Changed field order - values change accordingly +INSERT INTO Goods (good_name, type, good_id) +VALUES ('Table', 2, 20); +``` + +If you don't specify the list of fields, then values must be listed for **all** table fields in the order they were defined when creating the table: + +```sql +INSERT INTO Goods +VALUES (20, 'Table', 2); +``` + +> It is recommended to always explicitly specify the list of fields. +> This makes the code more readable, protects against errors when changing the table structure, and allows inserting values only into the required fields. + +## Differences between INSERT syntaxes + +The `INSERT` operator supports two main syntaxes for specifying data: + +### INSERT INTO ... VALUES + +Used to insert **predefined** values. Can insert one or more rows at once: + +```sql +-- Single row +INSERT INTO Goods (good_id, good_name, type) +VALUES (20, 'Table', 2); + +-- Multiple rows +INSERT INTO Goods (good_id, good_name, type) +VALUES + (20, 'Table', 2), + (21, 'Chair', 2), + (22, 'Lamp', 8); +``` + +**When to use:** for inserting specific, static data that is known in advance. + +### INSERT INTO ... SELECT + +Used to insert data **obtained from a query**. Allows copying data from one table to another or inserting results of complex calculations: + +```sql +INSERT INTO Goods (good_id, good_name, type) +SELECT 20, 'Table', 2; + +-- Or copying from another table +INSERT INTO Goods (good_id, good_name, type) +SELECT good_id + 100, good_name, type +FROM Goods +WHERE type = 2; +``` + +**When to use:** for copying data between tables, inserting calculation results, or when data depends on existing records in the database. + Thus, You can add new entries in the following ways: +Family database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/operator-insert). + - Using the syntax `INSERT INTO ... SELECT` - ```sql-executable-Family-targetTable:Goods - INSERT INTO Goods (good_id, good_name, type) - SELECT 20, 'Table', 2; - ``` + ```sql + INSERT INTO Goods (good_id, good_name, type) + SELECT 20, 'Table', 2; + ``` - Using the syntax `INSERT INTO ... VALUES (...)` - ```sql-executable-Family-targetTable:Goods - INSERT INTO Goods (good_id, good_name, type) - VALUES (20, 'Table', 2); - ``` + ```sql + INSERT INTO Goods (good_id, good_name, type) + VALUES (20, 'Table', 2); + ``` Each of these queries will give the same result: +| good_id | good_name | type | +| ------- | ------------------ | ---- | +| 1 | apartment fee | 1 | +| 2 | phone fee | 1 | +| 3 | bread | 2 | +| 4 | milk | 2 | +| 5 | red caviar | 3 | +| 6 | cinema | 4 | +| 7 | black caviar | 3 | +| 8 | cough tablets | 5 | +| 9 | potato | 2 | +| 10 | pineapples | 3 | +| 11 | television | 8 | +| 12 | vacuum cleaner | 8 | +| 13 | jacket | 7 | +| 14 | fur coat | 7 | +| 15 | music school fee | 6 | +| 16 | english school fee | 6 | +| 20 | Table | 2 | + ## Primary key when adding a new record It should be remembered that the primary key of the table is a unique value and adding an existing value will result in an error. When adding a new record with unique indices, the choice of such a unique values can be a daunting task. The solution may be an additional request, aimed at identifying the maximum value of the primary key to generate a new unique value. -```sql-executable-Family-targetTable:Goods +```sql INSERT INTO Goods SELECT MAX(good_id) + 1, 'Table', 2 FROM Goods; ``` @@ -50,7 +149,7 @@ Here, we use the `MAX` function to find the maximum value in the primary key col ## Automatic primary key generation - +**MySQL** MySQL introduced a mechanism for automatic primary key generation. To do this, just provide the primary key `good_id` attribute `AUTO_INCREMENT`. Then when creating a new record as the value `good_id` just pass `NULL` or `0` - the field will automatically get a value greater than the previous one by one. @@ -67,9 +166,7 @@ CREATE TABLE Goods ( INSERT INTO Goods VALUES (NULL, 'Table', 2); ``` - - - +**PostgreSQL** PostgreSQL has a mechanism for automatically generating a unique identifier. For this, it has types `SMALLSERIAL`, `SERIAL`, `BIGSERIAL`, which are not real types, but rather just the convenience of writing columns with a unique identifier. @@ -86,5 +183,3 @@ CREATE TABLE Goods ( ```sql INSERT INTO Goods (good_name, type) VALUES ('Table', 2); ``` - - diff --git a/course/module-4/operator-update/article.md b/course/module-4/operator-update/article.md index 1bca176..4665dce 100644 --- a/course/module-4/operator-update/article.md +++ b/course/module-4/operator-update/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Updating data, UPDATE operator' - description: 'Editing (updating) records in sql. Change data in relational databases.' + title: "Updating data, UPDATE operator" + description: "Editing (updating) records in sql. Change data in relational databases." --- # Updating data, UPDATE operator @@ -19,22 +19,24 @@ SET table_field1 = table_field_value1, So, for example, if you need to change the name, the request will look like this: +Family database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/operator-update). + ```sql UPDATE FamilyMembers -SET member_name = "Andie Anthony" -WHERE member_name = "Andie Quincey"; +SET member_name = 'Andie Anthony' +WHERE member_name = 'Andie Quincey'; ``` -| member_id | status | member_name | birthday | -| --------- | ----------- | ----------------- | -------------------- | -| 1 | father | Headley Quincey | 1960-05-13T00:00:00Z | -| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00Z | -| 3 | varchar(50) | Andie Anthony | 1983-06-05T00:00:00Z | -| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00Z | -| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00Z | -| 6 | father | Ernest Forrest | 1961-09-11T00:00:00Z | -| 7 | mother | Constance Forrest | 1968-09-06T00:00:00Z | -| 8 | daughter | Wednesday Addams | 2005-01-13T00:00:00Z | +| member_id | status | member_name | birthday | +| --------- | ----------- | ----------------- | ------------------------ | +| 1 | father | Headley Quincey | 1960-05-13T00:00:00.000Z | +| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00.000Z | +| 3 | varchar(50) | Andie Anthony | 1983-06-05T00:00:00.000Z | +| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00.000Z | +| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00.000Z | +| 6 | father | Ernest Forrest | 1961-09-11T00:00:00.000Z | +| 7 | mother | Constance Forrest | 1968-09-06T00:00:00.000Z | +| 8 | daughter | Wednesday Addams | 2005-01-13T00:00:00.000Z | > Be careful when updating data. If you skip the `WHERE` operator, all entries will be updated. diff --git a/course/module-5/creating-transactions/article.md b/course/module-5/creating-transactions/article.md index 3c87ccd..0e513c6 100644 --- a/course/module-5/creating-transactions/article.md +++ b/course/module-5/creating-transactions/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Creating transactions: MySQL and PostgreSQL" - description: "Learn how to create secure transactions in MySQL and PostgreSQL databases to protect your funds and data. Discover the importance of COMMIT and ROLLBACK commands to manage changes and ensure data stability. Explore the use of savepoints for flexible control over transactions, minimizing risks and enhancing data processing efficiency." + title: "Creating transactions: MySQL and PostgreSQL" + description: "Learn how to create secure transactions in MySQL and PostgreSQL databases to protect your funds and data. Discover the importance of COMMIT and ROLLBACK commands to manage changes and ensure data stability. Explore the use of savepoints for flexible control over transactions, minimizing risks and enhancing data processing efficiency." --- # Creating transactions @@ -40,18 +40,14 @@ With a transaction, the program ensures the safety of your $1,000, guaranteeing ## Starting and completing transactions - +**MySQL** Every explicit transaction in MySQL begins with the use of the `START TRANSACTION` or `BEGIN` statement. - - - +**PostgreSQL** Every explicit transaction in PostgreSQL begins with the use of the `BEGIN` or `START TRANSACTION` statement. - - A transaction can be completed by: - Using the `COMMIT` command, which instructs the server to mark the changes as permanent and release all resources (e.g., row locks) used during the transaction @@ -76,7 +72,7 @@ SAVEPOINT my_savepoint; To roll back to a specific savepoint, simply enter the command `ROLLBACK`, followed by the keywords `TO SAVEPOINT` and the name of the savepoint, for example: - +**MySQL** ```sql START TRANSACTION; @@ -98,9 +94,7 @@ UPDATE accounts SET balance = balance + 200 WHERE user_id = 2; COMMIT; ``` - - - +**PostgreSQL** ```sql BEGIN; @@ -122,8 +116,6 @@ UPDATE accounts SET balance = balance + 200 WHERE user_id = 2; COMMIT; ``` - - As a result of this transaction, the balance of the first user remains unchanged due to the rollback to the savepoint, while the balance of the second user increases by 200. This demonstrates how you can manage changes in the database with a high level of control using transactions and savepoints. diff --git a/course/module-5/locking/article.md b/course/module-5/locking/article.md index 19030b2..8a0b2b8 100644 --- a/course/module-5/locking/article.md +++ b/course/module-5/locking/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Locks in DBMS: MySQL and PostgreSQL" - description: "Understanding locks in MySQL and PostgreSQL: Discover how different types of locks help manage simultaneous data access and ensure correct transaction processing. Explore the various levels of lock granularity—from tables to rows—and their impact on performance and data consistency in your database." + title: "Locks in DBMS: MySQL and PostgreSQL" + description: "Understanding locks in MySQL and PostgreSQL: Discover how different types of locks help manage simultaneous data access and ensure correct transaction processing. Explore the various levels of lock granularity—from tables to rows—and their impact on performance and data consistency in your database." --- # Locks in DBMS @@ -37,30 +37,30 @@ When data in the database is locked, other users who want to change or read the There are several different strategies that can be used to lock a resource. The server can apply a lock at one of three different levels, or granularities: -- Table locks - Prevent multiple users from simultaneously modifying data in the same table. -- Page locks - Prevent multiple users from changing data on the same page (a page is a memory segment, usually ranging from 2 to 16 KB) - of a table simultaneously. -- Row locks - Prevent multiple users from simultaneously changing the same row in the table. +- **Table lock.** While the change is in progress, the whole table is unavailable to everyone else +- **Page lock.** Only those who hit the same memory segment — 2 to 16 KB — have to wait +- **Row lock.** Only someone changing that very row has to wait These approaches have their advantages and disadvantages. Locking an entire table requires minimal time, but as the number of users increases, it can lead to long waits. Row locking requires more overhead, but it allows multiple users to modify the same table if they are working on different rows. - +**MySQL** MySQL can use table, page, or row locking depending on your storage engine choice. By default, MySQL uses the InnoDB storage engine, which provides row-level locking. - - - +**PostgreSQL** PostgreSQL uses Multi-Version Concurrency Control (MVCC) and supports row-level locking by default. This ensures high performance with simultaneous access by multiple users to the data. - - Before moving on to the next article about creating transactions, let's check how well you understood this lesson. + +**Why are locks needed in a DBMS?** + +1. **Correct answer:** Locks in a DBMS are needed to manage simultaneous access to data resources. — The primary purpose of locking in databases is to prevent access conflicts and ensure data integrity by temporarily blocking access to the data. + +2. Locks in a DBMS are needed to speed up the operation of the database server. — This answer is incorrect because locking adds some delay in data access, not speeding it up. It is necessary to prevent conflicts and maintain data integrity, which can sometimes lead to delays in processing requests. + +3. Locks in a DBMS are needed to execute multiple SQL statements as one logical operation. — This answer is incorrect because locking is not necessarily related to performing multiple SQL instructions as one operation. It more so ensures consistent access to data during simultaneous modifications by multiple users. diff --git a/course/module-5/operators-if-case-while-in-stored-procedures/article.md b/course/module-5/operators-if-case-while-in-stored-procedures/article.md index e3dedc7..a9b9fac 100644 --- a/course/module-5/operators-if-case-while-in-stored-procedures/article.md +++ b/course/module-5/operators-if-case-while-in-stored-procedures/article.md @@ -1,10 +1,16 @@ --- meta: - title: 'IF, CASE, WHILE Operators in Stored Procedures and Functions' - description: 'Learn conditional statements and loops in SQL stored procedures and functions. Syntax and examples of IF, CASE, WHILE for MySQL and PostgreSQL.' + title: "IF, CASE, WHILE Operators in Stored Procedures and Functions" + description: "Learn conditional statements and loops in SQL stored procedures and functions. Syntax and examples of IF, CASE, WHILE for MySQL and PostgreSQL." --- -# IF, CASE, WHILE Operators in Stored Procedures and Functions +**MySQL** + +# IF, CASE, WHILE Operators in Stored Procedures + +**PostgreSQL** + +# IF, CASE, WHILE Operators in Stored Functions Stored procedures and functions are not just convenient containers for groups of queries. They allow you to implement quite complex logic using conditional operators and loops. @@ -16,7 +22,7 @@ The `IF` operator allows you to execute code based on whether a condition is met ### IF Syntax - +**MySQL** ```sql IF condition THEN @@ -28,9 +34,7 @@ ELSE END IF; ``` - - - +**PostgreSQL** ```sql IF condition THEN @@ -42,15 +46,13 @@ ELSE END IF; ``` - - ### IF Usage Example - +**MySQL** Let's create a procedure that categorizes students by age: -```sql-executable-Schedule +```sql CREATE PROCEDURE categorize_student_by_age( IN student_id INT, OUT category VARCHAR(20) @@ -79,13 +81,11 @@ CALL categorize_student_by_age(1, @category); SELECT @category AS age_category; ``` - - - +**PostgreSQL** Let's create a function that categorizes students by age: -```sql-executable-Schedule +```sql CREATE OR REPLACE FUNCTION categorize_student_by_age(student_id INT) RETURNS VARCHAR(20) LANGUAGE plpgsql @@ -117,7 +117,11 @@ $$; SELECT categorize_student_by_age(1) AS age_category; ``` - +**MySQL** + +| age_category | +| ------------ | +| Young | ## CASE Selection Statement @@ -125,7 +129,7 @@ The `CASE` operator provides a more elegant way to handle multiple conditions. ### CASE Syntax - +**MySQL** ```sql CASE @@ -135,9 +139,7 @@ CASE END CASE; ``` - - - +**PostgreSQL** ```sql CASE @@ -147,15 +149,13 @@ CASE END CASE; ``` - - ### CASE Usage Example - +**MySQL** Let's create the same student categorization procedure, but using the CASE operator: -```sql-executable-Schedule +```sql CREATE PROCEDURE categorize_student_with_case( IN student_id INT, OUT category VARCHAR(20) @@ -182,13 +182,11 @@ CALL categorize_student_with_case(1, @category); SELECT @category AS age_category; ``` - - - +**PostgreSQL** Let's create the same student categorization function, but using the CASE operator: -```sql-executable-Schedule +```sql CREATE OR REPLACE FUNCTION categorize_student_with_case(student_id INT) RETURNS VARCHAR(20) LANGUAGE plpgsql @@ -218,7 +216,11 @@ $$; SELECT categorize_student_with_case(1) AS age_category; ``` - +**MySQL** + +| age_category | +| ------------ | +| Young | ## WHILE Loop @@ -226,7 +228,7 @@ The `WHILE` loop allows you to execute code repeatedly while a certain condition ### WHILE Syntax - +**MySQL** ```sql WHILE condition DO @@ -234,9 +236,7 @@ WHILE condition DO END WHILE; ``` - - - +**PostgreSQL** ```sql WHILE condition LOOP @@ -244,15 +244,13 @@ WHILE condition LOOP END LOOP; ``` - - ### WHILE Usage Example Let's look at an example of a stored procedure for creating several test subjects: - +**MySQL** -```sql-executable-Schedule +```sql CREATE PROCEDURE create_test_subjects(IN count_subjects INT) BEGIN DECLARE i INT DEFAULT 1; @@ -277,11 +275,9 @@ CALL create_test_subjects(3); SELECT * FROM Subject WHERE name LIKE 'Test Subject%'; ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql CREATE OR REPLACE PROCEDURE create_test_subjects(count_subjects INT) LANGUAGE plpgsql AS $$ @@ -311,7 +307,10 @@ CALL create_test_subjects(3); SELECT * FROM Subject WHERE name LIKE 'Test Subject%'; ``` - - +| id | name | +| --- | -------------- | +| 21 | Test Subject 1 | +| 22 | Test Subject 2 | +| 23 | Test Subject 3 | Flow control operators make stored procedures and functions a powerful tool for implementing complex business logic directly in the database! 🚀 diff --git a/course/module-5/partitions/article.md b/course/module-5/partitions/article.md index 53d2415..7cb2199 100644 --- a/course/module-5/partitions/article.md +++ b/course/module-5/partitions/article.md @@ -1,13 +1,13 @@ --- meta: - title: 'Partitions in window functions' - description: 'Partitions in SQL window functions. Using partitions across multiple columns. Partition syntax.' + title: "Partitions in window functions" + description: "Partitions in SQL window functions. Using partitions across multiple columns. Partition syntax." --- # Partitions in SQL Window Functions -In the [previous article](https://sql-academy.org//guide/windows-functions), we briefly mentioned what partitions -are and how to use them in window functions. Now it's time to dive deeper into partitions. +In the [previous article](https://sql-academy.org/en/guide/windows-functions), we briefly mentioned what partitions +are and how to use them in window functions. Now it's time to dive deeper into partitions 🤓. ## Understanding partitions @@ -34,14 +34,67 @@ OVER ( Now let's look at an example of using a partition with a window function using a simple example. - +Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/partitions). Consider the `Rooms` table from the `Airbnb` database, specifically the `home_type` and `price` fields: -```sql-Airbnb-executable +```sql SELECT home_type, price FROM Rooms; ``` +| home_type | price | +| --------------- | ----- | +| Private room | 149 | +| Entire home/apt | 225 | +| Private room | 150 | +| Entire home/apt | 89 | +| Entire home/apt | 80 | +| Entire home/apt | 200 | +| Private room | 60 | +| Private room | 79 | +| Private room | 79 | +| Entire home/apt | 150 | +| Entire home/apt | 135 | +| Private room | 85 | +| Private room | 89 | +| Private room | 85 | +| Entire home/apt | 120 | +| Entire home/apt | 140 | +| Entire home/apt | 215 | +| Private room | 140 | +| Entire home/apt | 99 | +| Entire home/apt | 190 | +| Entire home/apt | 299 | +| Private room | 130 | +| Private room | 80 | +| Private room | 110 | +| Entire home/apt | 120 | +| Private room | 60 | +| Private room | 80 | +| Entire home/apt | 150 | +| Private room | 44 | +| Entire home/apt | 180 | +| Private room | 50 | +| Private room | 52 | +| Private room | 55 | +| Private room | 50 | +| Private room | 70 | +| Private room | 89 | +| Private room | 35 | +| Entire home/apt | 85 | +| Private room | 150 | +| Shared room | 40 | +| Private room | 68 | +| Entire home/apt | 120 | +| Private room | 120 | +| Private room | 135 | +| Entire home/apt | 150 | +| Entire home/apt | 150 | +| Private room | 130 | +| Entire home/apt | 110 | +| Entire home/apt | 115 | +| Private room | 80 | + We can see that all rental homes are divided into 3 categories: "Private room," "Entire home/apt," and "Shared room." @@ -49,13 +102,66 @@ Each category of housing has its own price range. To find out the average price Let's add another column, `avg_price`, to our result table that calculates the average price per category. It will look like this: -```sql-Airbnb-executable +```sql SELECT home_type, price, AVG(price) OVER (PARTITION BY home_type) AS avg_price - FROM Rooms +FROM Rooms ``` +| home_type | price | avg_price | +| --------------- | ----- | --------- | +| Entire home/apt | 225 | 148.6667 | +| Entire home/apt | 180 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 85 | 148.6667 | +| Entire home/apt | 120 | 148.6667 | +| Entire home/apt | 120 | 148.6667 | +| Entire home/apt | 299 | 148.6667 | +| Entire home/apt | 190 | 148.6667 | +| Entire home/apt | 99 | 148.6667 | +| Entire home/apt | 215 | 148.6667 | +| Entire home/apt | 140 | 148.6667 | +| Entire home/apt | 120 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 135 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 110 | 148.6667 | +| Entire home/apt | 115 | 148.6667 | +| Entire home/apt | 200 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 80 | 148.6667 | +| Entire home/apt | 89 | 148.6667 | +| Private room | 68 | 89.4286 | +| Private room | 50 | 89.4286 | +| Private room | 70 | 89.4286 | +| Private room | 80 | 89.4286 | +| Private room | 89 | 89.4286 | +| Private room | 149 | 89.4286 | +| Private room | 35 | 89.4286 | +| Private room | 150 | 89.4286 | +| Private room | 130 | 89.4286 | +| Private room | 120 | 89.4286 | +| Private room | 135 | 89.4286 | +| Private room | 130 | 89.4286 | +| Private room | 150 | 89.4286 | +| Private room | 60 | 89.4286 | +| Private room | 79 | 89.4286 | +| Private room | 79 | 89.4286 | +| Private room | 85 | 89.4286 | +| Private room | 89 | 89.4286 | +| Private room | 85 | 89.4286 | +| Private room | 140 | 89.4286 | +| Private room | 55 | 89.4286 | +| Private room | 80 | 89.4286 | +| Private room | 110 | 89.4286 | +| Private room | 60 | 89.4286 | +| Private room | 80 | 89.4286 | +| Private room | 44 | 89.4286 | +| Private room | 50 | 89.4286 | +| Private room | 52 | 89.4286 | +| Shared room | 40 | 40 | + What's happening in the added line? - `PARTITION BY home_type` divides all records into different partitions based on the unique values in the `home_type` column. @@ -67,17 +173,70 @@ The result of executing this part of the query will be the `avg_price` column, w Partitioning can also be done on multiple columns, allowing for more complex and precise segmentation for analysis. -For example, for our `Rooms` table, we can create partitions based on two columns: the housing category `home_type` and the presence of a TV in the accommodation `has_tv` . +For example, for our `Rooms` table, we can create partitions based on two columns: the housing category `home_type` and the presence of a TV in the accommodation `has_tv`. Here's an example query with partitioning on two columns: -```sql-Airbnb-executable +```sql SELECT home_type, has_tv, price, AVG(price) OVER (PARTITION BY home_type, has_tv) AS avg_price FROM Rooms ``` +| home_type | has_tv | price | avg_price | +| --------------- | ------ | ----- | --------- | +| Entire home/apt | 0 | 225 | 170 | +| Entire home/apt | 0 | 180 | 170 | +| Entire home/apt | 0 | 80 | 170 | +| Entire home/apt | 0 | 200 | 170 | +| Entire home/apt | 0 | 150 | 170 | +| Entire home/apt | 0 | 150 | 170 | +| Entire home/apt | 0 | 190 | 170 | +| Entire home/apt | 0 | 215 | 170 | +| Entire home/apt | 0 | 140 | 170 | +| Entire home/apt | 1 | 99 | 132.6667 | +| Entire home/apt | 1 | 85 | 132.6667 | +| Entire home/apt | 1 | 150 | 132.6667 | +| Entire home/apt | 1 | 120 | 132.6667 | +| Entire home/apt | 1 | 120 | 132.6667 | +| Entire home/apt | 1 | 299 | 132.6667 | +| Entire home/apt | 1 | 120 | 132.6667 | +| Entire home/apt | 1 | 135 | 132.6667 | +| Entire home/apt | 1 | 150 | 132.6667 | +| Entire home/apt | 1 | 110 | 132.6667 | +| Entire home/apt | 1 | 89 | 132.6667 | +| Entire home/apt | 1 | 115 | 132.6667 | +| Private room | 0 | 85 | 78.5455 | +| Private room | 0 | 35 | 78.5455 | +| Private room | 0 | 150 | 78.5455 | +| Private room | 0 | 55 | 78.5455 | +| Private room | 0 | 52 | 78.5455 | +| Private room | 0 | 50 | 78.5455 | +| Private room | 0 | 68 | 78.5455 | +| Private room | 0 | 60 | 78.5455 | +| Private room | 0 | 135 | 78.5455 | +| Private room | 0 | 85 | 78.5455 | +| Private room | 0 | 89 | 78.5455 | +| Private room | 1 | 120 | 96.4706 | +| Private room | 1 | 80 | 96.4706 | +| Private room | 1 | 149 | 96.4706 | +| Private room | 1 | 130 | 96.4706 | +| Private room | 1 | 89 | 96.4706 | +| Private room | 1 | 70 | 96.4706 | +| Private room | 1 | 50 | 96.4706 | +| Private room | 1 | 44 | 96.4706 | +| Private room | 1 | 80 | 96.4706 | +| Private room | 1 | 60 | 96.4706 | +| Private room | 1 | 110 | 96.4706 | +| Private room | 1 | 80 | 96.4706 | +| Private room | 1 | 130 | 96.4706 | +| Private room | 1 | 140 | 96.4706 | +| Private room | 1 | 79 | 96.4706 | +| Private room | 1 | 79 | 96.4706 | +| Private room | 1 | 150 | 96.4706 | +| Shared room | 1 | 40 | 40 | + Here, `PARTITION BY home_type, has_tv` creates unique partitions for each combination of `home_type` and `has_tv`, allowing us to calculate the average price of housing for the current housing category with or without a TV. ![Partitions on two columns](https://sql-academy.org/static/guidePage/partitions/2-columns-partition_en.png "Partitions on two columns") diff --git a/course/module-5/scheduled-events/article.md b/course/module-5/scheduled-events/article.md new file mode 100644 index 0000000..35bfc49 --- /dev/null +++ b/course/module-5/scheduled-events/article.md @@ -0,0 +1,407 @@ +--- +meta: + title: "SQL Event Scheduler: MySQL EVENT & PostgreSQL pg_cron Guide" + description: "Complete guide to creating events in MySQL and pg_cron tasks in PostgreSQL. Learn to use EVENT scheduler and pg_cron for data cleanup, statistics updates, and report generation on schedule. Code examples and practical tips included." +--- + +# Event Scheduler + +In real-world applications, there's often a need to automatically execute certain actions on a schedule: cleaning up old records, updating statistics, generating reports. + +**MySQL** + +For these tasks, MySQL provides a mechanism called **scheduled events**. + +> **Event** is a task the database runs for you on a schedule. You set it up — it runs automatically. + +Events in MySQL are similar to a task scheduler in an operating system: you create a task once, and the database executes it automatically on schedule. + +**PostgreSQL** + +For these tasks, PostgreSQL uses the **pg_cron** extension. It lets you create scheduled tasks using cron syntax (as in Unix systems). + +## When it is useful + +**MySQL** + +Scheduled events help automate the following tasks: + +**PostgreSQL** + +With pg_cron, you can automate: + +- **Data cleanup**: removing outdated log records or temporary data +- **Statistics updates**: recalculating aggregated data for analytics +- **Report generation**: automatically creating periodic reports +- **Data maintenance**: moving records to archive tables and performing other routine operations + +## Enabling the scheduler + +**MySQL** + +Before creating events, make sure the event scheduler is enabled: + +```sql +SHOW VARIABLES LIKE 'event_scheduler'; +``` + +If the scheduler is disabled, enable it: + +```sql +SET GLOBAL event_scheduler = ON; +``` + +This command changes the setting until the next server restart and requires permission to modify global system variables. To enable the scheduler permanently, use the server configuration or `SET PERSIST` if it is available in your MySQL version. + +**PostgreSQL** + +First, install pg_cron on the server, add it to `shared_preload_libraries`, and restart PostgreSQL. You can then create the extension in the database: + +```sql +CREATE EXTENSION IF NOT EXISTS pg_cron; +``` + +> **Important:** An administrator usually installs and creates the extension. Regular users can be allowed to create tasks with `GRANT USAGE ON SCHEMA cron TO user_name;`. The procedure for enabling pg_cron in a managed database depends on the provider. + +## One-Time Execution + +**MySQL** + +Let's start with the simplest case — an event that executes once at a specific time: + +**PostgreSQL** + +Let's start with the simplest case — a task that executes once at a specific time: + +**MySQL** + +```sql +CREATE EVENT cleanup_old_logs +ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY +DO + DELETE FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY; +``` + +This event will delete log records older than 30 days, 24 hours after the event is created. + +**Breaking down the syntax:** + +- `CREATE EVENT cleanup_old_logs` — create an event named `cleanup_old_logs` +- `ON SCHEDULE AT` — specify when the event should execute +- `CURRENT_TIMESTAMP + INTERVAL 1 DAY` — execution time (in 1 day) +- `DO` — the event body: one simple SQL statement or a `BEGIN ... END` compound statement + +**PostgreSQL** + +pg_cron does not have a separate schedule type for a one-time run. Use an external application scheduler for this case, or create a temporary task and remove it after it runs. + +For example, this task deletes old log records the next time 3:00 AM occurs and then removes itself: + +```sql +SELECT cron.schedule( + 'cleanup_old_logs_once', + '0 3 * * *', + $command$ + DO $$ + BEGIN + DELETE FROM logs WHERE created_at < NOW() - INTERVAL '30 days'; + PERFORM cron.unschedule('cleanup_old_logs_once'); + END; + $$; + $command$ +); +``` + +Normally, the `'0 3 * * *'` schedule runs a task every day at 3:00 AM. After its first run, however, this task calls `cron.unschedule()` with its own name, so it does not run again. + +## Recurring Execution + +**MySQL** + +More often, events need to run periodically — every day, hour, or minute: + +**PostgreSQL** + +More often, tasks need to run periodically — every day, hour, or minute: + +**MySQL** + +```sql +CREATE EVENT update_statistics +ON SCHEDULE EVERY 1 HOUR +DO +BEGIN + UPDATE product_stats SET + total_sales = (SELECT SUM(amount) FROM orders WHERE product_id = product_stats.product_id), + last_updated = NOW(); +END; +``` + +This event will update sales statistics every hour. + +**Breaking down the syntax:** + +- `ON SCHEDULE EVERY 1 HOUR` — execute every hour +- `BEGIN ... END` — a compound statement to which you can add multiple SQL statements when needed + +**Interval options:** + +- `EVERY 1 MINUTE` — every minute +- `EVERY 1 HOUR` — every hour +- `EVERY 1 DAY` — every day +- `EVERY 1 WEEK` — every week +- `EVERY 1 MONTH` — every month +- `EVERY 30 SECOND` — every 30 seconds + +**PostgreSQL** + +```sql +SELECT cron.schedule( + 'cleanup_old_logs', + '0 3 * * *', + 'DELETE FROM logs WHERE created_at < NOW() - INTERVAL ''30 days''' +); +``` + +This task will run every day at 3:00 AM and delete log records older than 30 days. + +**Breaking down the syntax:** + +- `cron.schedule()` — function to create a scheduled task +- `'cleanup_old_logs'` — task name +- `'0 3 * * *'` — schedule in cron format (minute, hour, day of month, month, day of week) +- last parameter — SQL command to execute + +**Cron schedule format:** + +![Format cron scheduler](https://sql-academy.org/static/guidePage/scheduled-events/cron_schedule_en.png "Format cron scheduler") + +```sql +SELECT cron.schedule( + 'update_statistics_hourly', + '0 * * * *', + $$ + UPDATE product_stats SET + total_sales = (SELECT SUM(amount) FROM orders WHERE product_id = product_stats.product_id), + last_updated = NOW() + $$ +); +``` + +This task will update sales statistics every hour (at the start of each hour). + +**Schedule examples:** + +- `'*/5 * * * *'` — every 5 minutes +- `'0 * * * *'` — every hour (at the start of the hour) +- `'0 0 * * *'` — every day at midnight +- `'0 0 * * 0'` — every Sunday at midnight +- `'0 9 1 * *'` — first day of each month at 9:00 AM +- `'30 seconds'` — every 30 seconds in pg_cron 1.5 and later + +Second-based intervals use a separate string rather than a sixth cron field. pg_cron supports values from 1 to 59 seconds. + +## Limiting the Execution Period + +**MySQL** + +Sometimes you need an event to run only during a specific period. + +**PostgreSQL** + +Sometimes you need a task to run only during a specific period. + +**MySQL** + +```sql +CREATE EVENT temporary_log_cleanup +ON SCHEDULE EVERY 1 DAY +STARTS CURRENT_TIMESTAMP +ENDS CURRENT_TIMESTAMP + INTERVAL 30 DAY +DO + DELETE FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY; +``` + +This event will delete outdated logs once a day for 30 days. + +**New elements:** + +- `STARTS` — start of the event's active period +- `ENDS` — end of the event's active period + +After `ENDS`, the event stops running and is dropped by default. Add `ON COMPLETION PRESERVE` when creating it if you want to retain its definition. + +**PostgreSQL** + +A pg_cron schedule cannot specify a date when a task should stop automatically. For example, create a task that cleans up logs daily for the next 30 days with a regular schedule: + +```sql +SELECT cron.schedule( + 'temporary_log_cleanup', + '0 0 * * *', + $$DELETE FROM logs WHERE created_at < NOW() - INTERVAL '30 days'$$ +); +``` + +To stop the task automatically, use the same approach as in the one-time execution example above: create a `stop_temporary_log_cleanup` task for a date 30 days from now. Its command body looks like this: + +```sql +DO $$ +BEGIN + PERFORM cron.unschedule('temporary_log_cleanup'); + PERFORM cron.unschedule('stop_temporary_log_cleanup'); +END; +$$; +``` + +The first call removes the cleanup task, and the second removes the helper task. In the helper task's schedule, specify the minute, hour, day, and month of the date 30 days from now. + +## Viewing the Schedule + +**MySQL** + +To see all created events: + +```sql +SHOW EVENTS; +``` + +To view events in a specific database: + +```sql +SHOW EVENTS FROM your_database_name; +``` + +**PostgreSQL** + +To see scheduled tasks available to the current user: + +```sql +SELECT * FROM cron.job; +``` + +A regular user sees only their own tasks. A superuser or a role with the `BYPASSRLS` attribute can see tasks created by other users. + +To view task execution history: + +```sql +SELECT * FROM cron.job_run_details +ORDER BY start_time DESC +LIMIT 10; +``` + +## Managing the Schedule + +**MySQL** + +**Temporarily disable an event:** + +```sql +ALTER EVENT cleanup_old_logs DISABLE; +``` + +**Enable an event:** + +```sql +ALTER EVENT cleanup_old_logs ENABLE; +``` + +**Change event schedule:** + +```sql +ALTER EVENT cleanup_old_logs +ON SCHEDULE EVERY 2 HOUR; +``` + +**Delete an event:** + +```sql +DROP EVENT IF EXISTS cleanup_old_logs; +``` + +**PostgreSQL** + +**Remove a scheduled task:** + +```sql +SELECT cron.unschedule('cleanup_old_logs'); +``` + +Or by task ID: + +```sql +SELECT cron.unschedule(42); -- where 42 is the jobid from cron.job table +``` + +**Modify a task:** + +You can change the schedule, command, and active state of an existing task with `cron.alter_job()`: + +```sql +SELECT cron.alter_job( + 42, + schedule := '0 */2 * * *' +); +``` + +Here, `42` is the task's `jobid` from the `cron.job` table. + +**MySQL** + +## Important Considerations for Events + +**PostgreSQL** + +## Important Considerations for pg_cron Tasks + +**MySQL** + +1. **Access privileges**: Creating events requires the `EVENT` privilege. + +2. **Time zone**: MySQL interprets the schedule using the current session's `time_zone` when the event is created or altered and stores that time zone with the event. + +3. **Overlapping runs**: If an event runs longer than its interval, MySQL may start multiple instances at the same time. Use a lock or another concurrency guard when overlapping runs are not acceptable. + +4. **Performance**: A suitable frequency depends on the cost of the operation and the database load, not on a universal minimum interval. + +**PostgreSQL** + +1. **Access privileges**: A superuser usually installs the extension, after which regular users can be granted `USAGE` on the `cron` schema. A task runs with the privileges of the user who created it. + +2. **Time zone**: Cron expressions use the `cron.timezone` setting, which defaults to `GMT`. Check the current value with `SHOW cron.timezone;`. + +3. **Intervals**: pg_cron 1.5 and later supports intervals from 1 to 59 seconds. Choose the frequency based on the cost of the task and the expected load. + +4. **Overlapping runs**: pg_cron does not run multiple instances of the same task concurrently. If the next run becomes due while the task is still running, it is queued. + +5. **Logging**: When `cron.log_run` is enabled, execution details are saved in `cron.job_run_details`. Logging is enabled by default. + +## Self-Check + +**MySQL** + +What is the minimum interval you can use for recurring events? + +1. **Correct answer:** Events can run every second — MySQL allows \`EVERY 1 SECOND\`. In practice, choose the frequency based on how long the operation takes and the load it creates. + +2. The minimum interval is 1 minute — A one-minute interval is common in practice, but MySQL technically allows events to run every second. + +3. The minimum interval is 1 hour — Running once an hour may suit a particular task, but that is a scenario-specific recommendation rather than a scheduler limitation. + +**PostgreSQL** + +What is the minimum interval you can use for recurring tasks? + +1. **Correct answer:** Tasks can run every second — pg_cron 1.5 and later accepts intervals such as \`1 second\`. In practice, choose the frequency based on the task duration and database load. + +2. The minimum interval is 1 minute — A standard five-field cron expression has minute-level precision, but pg_cron 1.5 and later additionally supports second-based intervals. + +3. The minimum interval is 1 hour — Running once an hour may suit a particular task, but that is a scenario-specific recommendation rather than a pg_cron limitation. + +**MySQL** + +Scheduled events are a powerful tool for automating routine database tasks. They help maintain data cleanliness, update statistics, and perform maintenance operations without developer intervention! 🚀 + +**PostgreSQL** + +Scheduled tasks are a powerful tool for automating routine database work. They help maintain data cleanliness, update statistics, and perform maintenance operations without developer intervention! 🚀 diff --git a/course/module-5/sorting-in-windows-functions/article.mdx b/course/module-5/sorting-in-windows-functions/article.md similarity index 87% rename from course/module-5/sorting-in-windows-functions/article.mdx rename to course/module-5/sorting-in-windows-functions/article.md index 7f0c814..9c5230d 100644 --- a/course/module-5/sorting-in-windows-functions/article.mdx +++ b/course/module-5/sorting-in-windows-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Sorting inside the window' - description: 'Sorting within a window is an important feature of SQL window functions. Learn how to use in-window sorting to organize your data and get more accurate aggregate calculations. An example of use and explanation of the features of sorting without specifying window frames.' + title: "Sorting inside the window" + description: "Sorting within a window is an important feature of SQL window functions. Learn how to use in-window sorting to organize your data and get more accurate aggregate calculations. An example of use and explanation of the features of sorting without specifying window frames." --- # Sorting within a window @@ -22,11 +22,11 @@ Let's say we need to analyze data on room bookings to understand how the total a We have the following sample data of bookings: -![Window function without sorting](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/initial-data_en.png 'Window function without sorting') +![Window function without sorting](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/initial-data_en.png "Window function without sorting") And we want to see the change in expenses for each user over time, resulting in a table like this: -![Using a window function with sorting](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png 'Using a window function with sorting') +![Using a window function with sorting](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png "Using a window function with sorting") #### Splitting data into partitions @@ -43,7 +43,7 @@ SELECT user_id, FROM Reservations; ``` -![Intermediate result](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/result-1.png 'Intermediate result') +![Intermediate result](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/result-1.png "Intermediate result") The result of this query shows the total expenses with a breakdown by user in the `total_expenses` column. However, this is not exactly what we want: the data in the table is not ordered by date, @@ -62,7 +62,7 @@ SELECT user_id, FROM Reservations; ``` -![Using a window function with sorting](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png 'Using a window function with sorting') +![Using a window function with sorting](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png "Using a window function with sorting") Now we have achieved what we wanted. But what changed after adding `ORDER BY start_date`? @@ -99,6 +99,6 @@ This means that the window starts from the first row and ends at the current row In the case of our query, the values for the `cumulative_total` column are calculated as follows: -![Explanation of how sorting worked](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/explanation.png 'Explanation of how sorting worked') +![Explanation of how sorting worked](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/explanation.png "Explanation of how sorting worked") We will dive into windows frames and their definitions in more detail in the next article. diff --git a/course/module-5/stored-functions/article.md b/course/module-5/stored-functions/article.md index 75b96fe..9aeffb4 100644 --- a/course/module-5/stored-functions/article.md +++ b/course/module-5/stored-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Stored Functions in SQL' - description: 'Creating and using stored functions in SQL. Syntax, parameters, return types, and practical examples.' + title: "Stored Functions in SQL" + description: "Creating and using stored functions in SQL. Syntax, parameters, return types, and practical examples." --- # Stored Functions @@ -12,7 +12,7 @@ Stored functions are a powerful SQL tool that allows you to create reusable code ## General Structure of a Stored Function - +**MySQL** ```sql CREATE FUNCTION function_name(parameter1 TYPE, parameter2 TYPE, ...) @@ -23,9 +23,7 @@ BEGIN END; ``` - - - +**PostgreSQL** ```sql CREATE OR REPLACE FUNCTION function_name(parameter1 TYPE, parameter2 TYPE, ...) @@ -43,15 +41,13 @@ $$; `AS $$ ... $$` — **dollar quoting**, a special way to delimit the function body. Allows you to avoid escaping characters inside the function. - - ## Simple Function Example Let's create a function to determine if a person is an adult based on their birth date: - +**MySQL** -```sql-executable +```sql CREATE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN BEGIN @@ -59,11 +55,9 @@ BEGIN END; ``` - - - +**PostgreSQL** -```sql-executable +```sql CREATE OR REPLACE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN LANGUAGE plpgsql @@ -74,13 +68,11 @@ END; $$; ``` - - Now this function can be used in any query: - +**MySQL** -```sql-executable +```sql -- Create the function CREATE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -94,11 +86,9 @@ SELECT is_adult('2000-03-20') AS adult_status; ``` - - - +**PostgreSQL** -```sql-executable +```sql -- Create the function CREATE OR REPLACE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -115,16 +105,25 @@ SELECT is_adult('2000-03-20') AS adult_status; ``` - +**MySQL** + +| child_status | adult_status | +| ------------ | ------------ | +| 0 | 1 | +**PostgreSQL** + +| child_status | adult_status | +| ------------ | ------------ | +| false | true | ## Using Functions in Table Queries Stored functions are especially useful when working with real data. For example, we can use our function to filter students by age: - +**MySQL** -```sql-executable-Schedule +```sql -- Create the function CREATE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -143,11 +142,9 @@ WHERE is_adult(birthday) = TRUE LIMIT 5; ``` - +**PostgreSQL** - - -```sql-executable-Schedule +```sql -- Create the function CREATE OR REPLACE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -169,15 +166,33 @@ WHERE is_adult(birthday) = TRUE LIMIT 5; ``` - +**MySQL** + +| first_name | last_name | birthday | is_adult | +| ---------- | --------- | ------------------------ | -------- | +| Nikolaj | Sokolov | 2000-10-01T00:00:00.000Z | 1 | +| Vyacheslav | Eliseev | 2000-11-21T00:00:00.000Z | 1 | +| Ivan | Efremov | 2000-09-19T00:00:00.000Z | 1 | +| Anatolij | ZHdanov | 2007-07-15T00:00:00.000Z | 1 | +| Georgij | Noskov | 2000-03-03T00:00:00.000Z | 1 | + +**PostgreSQL** + +| first_name | last_name | birthday | is_adult | +| ---------- | --------- | ------------------------ | -------- | +| Nikolaj | Sokolov | 2000-10-01T00:00:00.000Z | true | +| Vyacheslav | Eliseev | 2000-11-21T00:00:00.000Z | true | +| Ivan | Efremov | 2000-09-19T00:00:00.000Z | true | +| Anatolij | ZHdanov | 2007-07-15T00:00:00.000Z | true | +| Georgij | Noskov | 2000-03-03T00:00:00.000Z | true | ## Functions with Database Queries Stored functions can execute SQL queries inside themselves to retrieve necessary data: - +**MySQL** -```sql-executable-Schedule +```sql CREATE FUNCTION get_student_lessons_count(student_id INT, target_date DATE) RETURNS INT BEGIN @@ -193,11 +208,9 @@ BEGIN END; ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql CREATE OR REPLACE FUNCTION get_student_lessons_count(student_id INT, target_date DATE) RETURNS INT LANGUAGE plpgsql @@ -216,26 +229,23 @@ END; $$; ``` - - This function counts the number of lessons for a specific student on a given day: - +**MySQL** ```sql SELECT get_student_lessons_count(1, '2019-09-01') AS lessons_today; ``` - - - +**PostgreSQL** ```sql SELECT get_student_lessons_count(1, '2019-09-01') AS lessons_today; ``` - - +| lessons_today | +| ------------- | +| 3 | ## Breaking Down the Example with Variables @@ -247,12 +257,10 @@ DECLARE lessons_count INT; This line **declares a variable** `lessons_count` of type `INT`. The variable will store the result of our query. - +**PostgreSQL** > **Important for PostgreSQL:** All variables must be declared in the `DECLARE` block before the function body starts (before `BEGIN`). You cannot declare variables inside the function body. - - ```sql SELECT COUNT(*) INTO lessons_count FROM Schedule s @@ -263,9 +271,9 @@ WHERE sic.student = student_id Here we **save the query result into a variable**: -- `SELECT COUNT(*)` — counts the number of records -- `INTO lessons_count` — saves the result into the `lessons_count` variable -- The rest — a regular SQL query with JOIN and conditions +- `SELECT COUNT(*)` — counts the number of records +- `INTO lessons_count` — saves the result into the `lessons_count` variable +- The rest — a regular SQL query with JOIN and conditions ```sql RETURN lessons_count; @@ -277,17 +285,15 @@ RETURN lessons_count; ## Managing Stored Functions -- **Viewing Existing Functions** +- **Viewing Existing Functions** - + **MySQL** ```sql SHOW FUNCTION STATUS WHERE Db = 'your_database_name'; ``` - - - + **PostgreSQL** ```sql SELECT routine_name, routine_type @@ -295,29 +301,23 @@ RETURN lessons_count; WHERE routine_type = 'FUNCTION' AND routine_schema = 'public'; ``` - +- **Dropping a Function** -- **Dropping a Function** - - + **MySQL** ```sql DROP FUNCTION IF EXISTS is_adult; ``` - - - + **PostgreSQL** ```sql DROP FUNCTION IF EXISTS is_adult(DATE); ``` - +- **Modifying a Function** -- **Modifying a Function** - - + **MySQL** To modify a function in MySQL, you need to drop the old version first, then create a new one: @@ -327,9 +327,7 @@ RETURN lessons_count; CREATE FUNCTION is_adult(birth_date DATE) ... ``` - - - + **PostgreSQL** In PostgreSQL, you can use `CREATE OR REPLACE FUNCTION`: @@ -339,6 +337,4 @@ RETURN lessons_count; -- new implementation ``` - - Stored functions are a powerful tool for creating reusable business logic directly in the database. They help centralize calculations and ensure data consistency across the entire application! 🚀 diff --git a/course/module-5/stored-procedures-and-functions/article.md b/course/module-5/stored-procedures-and-functions/article.md index dd68ed0..c8e926a 100644 --- a/course/module-5/stored-procedures-and-functions/article.md +++ b/course/module-5/stored-procedures-and-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Stored Procedures and Functions in SQL' - description: 'Introduction to SQL stored procedures and functions. Their purpose, key differences, and when to use each type.' + title: "Stored Procedures and Functions in SQL" + description: "Introduction to SQL stored procedures and functions. Their purpose, key differences, and when to use each type." --- # Stored Procedures and Functions @@ -18,16 +18,16 @@ Instead of rewriting it each time, you can create a procedure or function and si Stored procedures and functions solve several important tasks: -- **🚀 Code Reusability** — write once, use everywhere. No more copies of the same code in different places. -- **⚡ Performance** — code executes directly on the database server, which is often faster than regular queries. -- **🔒 Security** — you can grant access to a procedure without giving direct access to tables. -- **🛡️ Centralized Logic** — all business logic is in one place, in the database. +- **🚀 Code Reusability** — write once, use everywhere. No more copies of the same code in different places. +- **⚡ Performance** — code executes directly on the database server, which is often faster than regular queries. +- **🔒 Security** — you can grant access to a procedure without giving direct access to tables. +- **🛡️ Centralized Logic** — all business logic is in one place, in the database. ## Key Differences Although procedures and functions are similar, there are important differences between them: - +**MySQL** | Characteristic | Stored Procedures | Stored Functions | | --------------------- | ---------------------------------------- | -------------------------------------------------------- | @@ -36,9 +36,7 @@ Although procedures and functions are similar, there are important differences b | **Data Modification** | Can modify data in tables | Designed only for reading data | | **Invocation** | `CALL procedure_name()` | `SELECT function_name()` | - - - +**PostgreSQL** | Characteristic | Stored Procedures | Stored Functions | | --------------------- | ------------------------- | -------------------------------------------------------- | @@ -47,16 +45,14 @@ Although procedures and functions are similar, there are important differences b | **Data Modification** | Can modify data in tables | Can modify data in tables | | **Invocation** | `CALL procedure_name()` | `SELECT function_name()` | - - ## When to use procedures? **Stored procedures** work best when you need to: -- Execute a sequence of operations (e.g., create order, deduct inventory, send notification) -- Modify data in multiple tables simultaneously -- Implement complex business logic -- Return multiple result sets +- Execute a sequence of operations (e.g., create order, deduct inventory, send notification) +- Modify data in multiple tables simultaneously +- Implement complex business logic +- Return multiple result sets ### Procedure Usage Example @@ -78,10 +74,10 @@ Such a procedure can: **Stored functions** are ideal when you need to: -- Perform calculations and return a result -- Create a reusable formula -- Transform data in a specific way -- Use the result in other SQL queries +- Perform calculations and return a result +- Create a reusable formula +- Transform data in a specific way +- Use the result in other SQL queries ### Function Usage Example @@ -102,13 +98,14 @@ Such a function takes price and customer type, and returns the discount amount t If you're unsure what to choose, use this simple rule: -- **Need to get a single value for use in a query?** → Function -- **Need to execute a set of actions or modify data?** → Procedure +- **Need to get a single value for use in a query?** → Function +- **Need to execute a set of actions or modify data?** → Procedure ## Reinforce Your Knowledge Now that you know the key differences between procedures and functions, try classifying tasks in this interactive game: +The interactive demonstration is available [in the SQL Academy lesson](https://sql-academy.org/en/guide/stored-procedures-and-functions). ## What's Next? diff --git a/course/module-5/stored-procedures/article.md b/course/module-5/stored-procedures/article.md index 4ecbc2b..3335a0e 100644 --- a/course/module-5/stored-procedures/article.md +++ b/course/module-5/stored-procedures/article.md @@ -1,28 +1,24 @@ --- meta: - title: 'Stored Procedures in SQL' - description: 'Creating and using stored procedures in SQL. Syntax, parameters, conditional logic, loops, and practical examples.' + title: "Stored Procedures in SQL" + description: "Creating and using stored procedures in SQL. Syntax, parameters, conditional logic, loops, and practical examples." --- # Stored Procedures in SQL Stored procedures are program blocks that execute a specific sequence of actions in a database. - +**MySQL** Unlike functions, procedures can modify data, perform complex business logic, and don't necessarily return a value. - - - +**PostgreSQL** Unlike functions, procedures can modify data, perform complex business logic, but cannot return values. - - ## General Structure of a Stored Procedure - +**MySQL** ```sql CREATE PROCEDURE procedure_name(parameter1 TYPE, parameter2 TYPE, ...) @@ -31,9 +27,7 @@ BEGIN END; ``` - - - +**PostgreSQL** ```sql CREATE OR REPLACE PROCEDURE procedure_name(parameter1 TYPE, parameter2 TYPE, ...) @@ -49,15 +43,13 @@ $$; `AS $$ ... $$` — **dollar quoting**, a special way to delimit the procedure body. Allows you to avoid escaping characters inside the procedure. - - ## Simple Procedure Example Let's create a procedure to update student information: - +**MySQL** -```sql-executable-Schedule +```sql -- Create procedure CREATE PROCEDURE update_student_info( IN student_id INT, @@ -78,11 +70,9 @@ CALL update_student_info(1, 'Alexander', 'Smirnov'); SELECT * FROM Student WHERE id = 1; ``` - +**PostgreSQL** - - -```sql-executable-Schedule +```sql -- Create procedure CREATE OR REPLACE PROCEDURE update_student_info( student_id INT, @@ -106,25 +96,27 @@ CALL update_student_info(1, 'Alexander', 'Smirnov'); SELECT * FROM Student WHERE id = 1; ``` - +| id | first_name | middle_name | last_name | birthday | address | +| --- | ---------- | ----------- | --------- | ------------------------ | -------------------------- | +| 1 | Alexander | Fedorovich | Smirnov | 2000-10-01T00:00:00.000Z | ul. Pushkina, d. 36, kv. 5 | This procedure takes a student ID and new data, then updates the corresponding record in the `Student` table. ## Types of Procedure Parameters - +**MySQL** MySQL procedures support three types of parameters that can be passed to a stored procedure: -- **IN** — input parameters (default) -- **OUT** — output parameters for returning values -- **INOUT** — parameters that can be both input and output +- **IN** — input parameters (default) +- **OUT** — output parameters for returning values +- **INOUT** — parameters that can be both input and output ### Input Parameters (IN) Input parameters pass data into the procedure. This is the most common type of parameter: -```sql-executable-Schedule +```sql CREATE PROCEDURE add_subject( IN subject_id INT, IN subject_name VARCHAR(100) @@ -142,7 +134,7 @@ CALL add_subject(15, 'Mathematics'); Output parameters allow procedures to return values: -```sql-executable-Schedule +```sql CREATE PROCEDURE get_student_info( IN student_id INT, OUT student_name VARCHAR(100), @@ -162,11 +154,15 @@ CALL get_student_info(1, @name, @age); SELECT @name AS student_name, @age AS student_age; ``` +| student_name | student_age | +| --------------- | ----------- | +| Nikolaj Sokolov | 24 | + ### Input-Output Parameters (INOUT) INOUT parameters can accept a value and return a modified value: -```sql-executable-Schedule +```sql CREATE PROCEDURE calculate_discount( INOUT price DECIMAL(10,2), IN discount_percent INT @@ -181,20 +177,21 @@ CALL calculate_discount(@original_price, 15); SELECT @original_price AS discounted_price; ``` - +**MySQL** +| discounted_price | +| ---------------- | +| 850 | +**MySQL** - ### Example of Three Parameter Types -![Examples of parameter usage in stored procedures](https://sql-academy.org/static/guidePage/stored-procedures/params-description.jpg 'Examples of parameter usage in stored procedures') - - +![Examples of parameter usage in stored procedures](https://sql-academy.org/static/guidePage/stored-procedures/params-description.jpg "Examples of parameter usage in stored procedures") ### Key Differences Between Parameter Types - +**MySQL** | Parameter Type | Direction | Usage | | -------------- | ------------- | ---------------------------- | @@ -204,29 +201,23 @@ SELECT @original_price AS discounted_price; > **Important:** OUT and INOUT parameters in MySQL require using session variables (e.g., `@variable_name`) when calling the procedure. - - - +**PostgreSQL** PostgreSQL procedures focus on performing actions rather than returning values. For returning values, it's better to use functions. > **Tip:** If you need to return a value from PostgreSQL, consider using a function instead of a procedure. - - ## Managing Stored Procedures -- **Viewing Existing Procedures** +- **Viewing Existing Procedures** - + **MySQL** ```sql SHOW PROCEDURE STATUS WHERE Db = 'your_database_name'; ``` - - - + **PostgreSQL** ```sql SELECT routine_name, routine_type @@ -234,29 +225,23 @@ PostgreSQL procedures focus on performing actions rather than returning values. WHERE routine_type = 'PROCEDURE' AND routine_schema = 'public'; ``` - +- **Dropping a Procedure** -- **Dropping a Procedure** - - + **MySQL** ```sql DROP PROCEDURE IF EXISTS add_student; ``` - - - + **PostgreSQL** ```sql DROP PROCEDURE IF EXISTS add_student(VARCHAR, VARCHAR, DATE); ``` - - -- **Modifying a Procedure** +- **Modifying a Procedure** - + **MySQL** To modify a procedure in MySQL, you need to drop the old version first, then create a new one: @@ -266,9 +251,7 @@ PostgreSQL procedures focus on performing actions rather than returning values. CREATE PROCEDURE add_student(...) ... ``` - - - + **PostgreSQL** In PostgreSQL, you can use `CREATE OR REPLACE PROCEDURE`: @@ -281,6 +264,4 @@ PostgreSQL procedures focus on performing actions rather than returning values. -- new implementation ``` - - Stored procedures are a powerful tool for implementing complex business logic directly in the database. They ensure logic centralization, improve performance, and guarantee data integrity! 🚀 diff --git a/course/module-5/transactions/article.md b/course/module-5/transactions/article.md index 3781f5b..9e20220 100644 --- a/course/module-5/transactions/article.md +++ b/course/module-5/transactions/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Transactions" - description: "Discover the importance of transactions in database management and how they ensure the reliability of applications. Learn why transactions are necessary to maintain data integrity and how they help prevent errors during simultaneous access by multiple users." + title: "Transactions" + description: "Discover the importance of transactions in database management and how they ensure the reliability of applications. Learn why transactions are necessary to maintain data integrity and how they help prevent errors during simultaneous access by multiple users." --- # Transactions diff --git a/course/module-5/type-conversion-functions/article.md b/course/module-5/type-conversion-functions/article.md index 3db23cf..dd21e39 100644 --- a/course/module-5/type-conversion-functions/article.md +++ b/course/module-5/type-conversion-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Type conversion functions, CAST: MySQL and PostgreSQL" - description: "SQL type conversion: CAST function in MySQL and PostgreSQL, CONVERT in MySQL. Data types for conversion, syntax and examples." + title: "Type conversion functions, CAST: MySQL and PostgreSQL" + description: "SQL type conversion: CAST function in MySQL and PostgreSQL, CONVERT in MySQL. Data types for conversion, syntax and examples." --- # Type conversion functions, CAST @@ -10,39 +10,39 @@ When we perform operations on values ​​with different data types, the DBMS t For example, in the example below we are comparing values ​​with `STRING` and `INT` types. To perform this comparison, the DBMS automatically will convert a string value to a numeric value. - +**MySQL** -```sql-executable +```sql SELECT '50' > 49 AS comparison_1, '50' > 51 AS comparison_2; ``` - +| comparison_1 | comparison_2 | +| ------------ | ------------ | +| 1 | 0 | - +**PostgreSQL** -```sql-executable +```sql SELECT '50' > 49 AS comparison_1, '50' > 51 AS comparison_2; ``` - +| comparison_1 | comparison_2 | +| ------------ | ------------ | +| true | false | But not all DBMS conversions can be done automatically, and then it is necessary to do an explicit type conversion. - +**MySQL** To do this, MySQL has two very similar functions `CAST` and `CONVERT`. - - - +**PostgreSQL** To do this, PostgreSQL has the `CAST` function and the `::` operator. - - ## Syntax - +**MySQL** ```sql CAST(value AS conversion_type); @@ -51,13 +51,15 @@ CONVERT(value, conversion_type); Example, -```sql-executable +```sql SELECT CAST(12005.6 AS DECIMAL) AS cast_example, CONVERT(12005.4, DECIMAL) AS convert_example; ``` - +| cast_example | convert_example | +| ------------ | --------------- | +| 12006 | 12005 | - +**PostgreSQL** ```sql CAST(value AS conversion_type); @@ -66,13 +68,15 @@ value::conversion_type; Example, -```sql-executable +```sql SELECT CAST(12005.6 AS INTEGER) AS cast_example, 12005.4::INTEGER AS operator_example; ``` - +| cast_example | operator_example | +| ------------ | ---------------- | +| 12006 | 12005 | - +**MySQL** The CAST function can convert the passed value to any of the following types: @@ -88,9 +92,7 @@ The CAST function can convert the passed value to any of the following types: | `BINARY` | Converts a value to `BINARY`. | | `YEAR` | Converts a value to a year. | - - - +**PostgreSQL** The CAST function can convert the passed value to any of the following types: @@ -106,34 +108,38 @@ The CAST function can convert the passed value to any of the following types: | `BOOLEAN` | Converts a value to a boolean type. | | `TEXT` | Converts a value to a text type. | - - ## Impossibility of any conversion Using the `CAST` function imposes requirements on the format of the original value. And the question immediately arises, what happens if the given format does not match the required one? For example, if you try to convert random text to a temporal data type: - +**MySQL** -```sql-executable +```sql SELECT CAST('SQL Academy' AS DATETIME) AS invalid_cast; ``` -In this case, MySQL will return `NULL` instead of the converted value. +| invalid_cast | +| ------------ | +| \ | - +In this case, MySQL will return `NULL` instead of the converted value. - +**PostgreSQL** -```sql-executable +```sql SELECT CAST('SQL Academy' AS TIMESTAMP) AS invalid_cast; ``` In this case, PostgreSQL will return an error, as the string cannot be converted to a date. - - ## Self test So, what is the responsibility of the `CAST` function in SQL 🧐? + +1. The function is used when it is necessary to determine the data type of the passed value. — The CAST function is responsible for converting a value, not for determining its data type. + +2. **Correct answer:** The function is responsible for converting a value from one data type to another — The function is really responsible for the explicit type conversion. + +3. The function is required to perform mathematical calculations — Perhaps you should revisit this lesson. The CAST function is responsible for type conversion, not for mathematical calculations. diff --git a/course/module-5/types-of-windows-functions/article.md b/course/module-5/types-of-windows-functions/article.md index 0f774f2..37b0f8f 100644 --- a/course/module-5/types-of-windows-functions/article.md +++ b/course/module-5/types-of-windows-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Fundamental window functions' - description: 'Fundamental window functions in SQL - aggregate, ranking, and offset functions. Learn how to use aggregate functions such as SUM, COUNT, AVG, MAX, and MIN to calculate total values. Ranking functions like ROW_NUMBER, RANK, and DENSE_RANK allow for ranking values within a window. Offset functions like LAG, LEAD, FIRST_VALUE, and LAST_VALUE enable access to data from previous and following rows of the window.' + title: "Fundamental window functions" + description: "Fundamental window functions in SQL - aggregate, ranking, and offset functions. Learn how to use aggregate functions such as SUM, COUNT, AVG, MAX, and MIN to calculate total values. Ranking functions like ROW_NUMBER, RANK, and DENSE_RANK allow for ranking values within a window. Offset functions like LAG, LEAD, FIRST_VALUE, and LAST_VALUE enable access to data from previous and following rows of the window." --- # Fundamental window functions @@ -11,7 +11,7 @@ which is passed to the window function. Now it's time to look at the types of wi ## Types of window functions -![categories of window functions](https://sql-academy.org/static/guidePage/types-of-windows-functions/categories_of_windows_functions_en.png 'categories of window functions') +![categories of window functions](https://sql-academy.org/static/guidePage/types-of-windows-functions/categories_of_windows_functions_en.png "categories of window functions") Window functions can be divided into 3 groups: @@ -29,7 +29,7 @@ Aggregate functions are those that perform arithmetic calculations on a data set - `MAX` — finds the highest value; - `MIN` — determines the lowest value. -```sql-Airbnb-executable +```sql SELECT id, home_type, price, @@ -41,6 +41,60 @@ SELECT id, FROM Rooms; ``` +| id | home_type | price | Sum | Count | Avg | Max | Min | +| --- | --------------- | ----- | ---- | ----- | -------- | --- | --- | +| 2 | Entire home/apt | 225 | 3122 | 21 | 148.6667 | 299 | 80 | +| 30 | Entire home/apt | 180 | 3122 | 21 | 148.6667 | 299 | 80 | +| 28 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 38 | Entire home/apt | 85 | 3122 | 21 | 148.6667 | 299 | 80 | +| 25 | Entire home/apt | 120 | 3122 | 21 | 148.6667 | 299 | 80 | +| 42 | Entire home/apt | 120 | 3122 | 21 | 148.6667 | 299 | 80 | +| 21 | Entire home/apt | 299 | 3122 | 21 | 148.6667 | 299 | 80 | +| 20 | Entire home/apt | 190 | 3122 | 21 | 148.6667 | 299 | 80 | +| 19 | Entire home/apt | 99 | 3122 | 21 | 148.6667 | 299 | 80 | +| 17 | Entire home/apt | 215 | 3122 | 21 | 148.6667 | 299 | 80 | +| 16 | Entire home/apt | 140 | 3122 | 21 | 148.6667 | 299 | 80 | +| 15 | Entire home/apt | 120 | 3122 | 21 | 148.6667 | 299 | 80 | +| 46 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 11 | Entire home/apt | 135 | 3122 | 21 | 148.6667 | 299 | 80 | +| 10 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 48 | Entire home/apt | 110 | 3122 | 21 | 148.6667 | 299 | 80 | +| 49 | Entire home/apt | 115 | 3122 | 21 | 148.6667 | 299 | 80 | +| 6 | Entire home/apt | 200 | 3122 | 21 | 148.6667 | 299 | 80 | +| 45 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 5 | Entire home/apt | 80 | 3122 | 21 | 148.6667 | 299 | 80 | +| 4 | Entire home/apt | 89 | 3122 | 21 | 148.6667 | 299 | 80 | +| 41 | Private room | 68 | 2504 | 28 | 89.4286 | 150 | 35 | +| 34 | Private room | 50 | 2504 | 28 | 89.4286 | 150 | 35 | +| 35 | Private room | 70 | 2504 | 28 | 89.4286 | 150 | 35 | +| 50 | Private room | 80 | 2504 | 28 | 89.4286 | 150 | 35 | +| 36 | Private room | 89 | 2504 | 28 | 89.4286 | 150 | 35 | +| 1 | Private room | 149 | 2504 | 28 | 89.4286 | 150 | 35 | +| 37 | Private room | 35 | 2504 | 28 | 89.4286 | 150 | 35 | +| 39 | Private room | 150 | 2504 | 28 | 89.4286 | 150 | 35 | +| 47 | Private room | 130 | 2504 | 28 | 89.4286 | 150 | 35 | +| 43 | Private room | 120 | 2504 | 28 | 89.4286 | 150 | 35 | +| 44 | Private room | 135 | 2504 | 28 | 89.4286 | 150 | 35 | +| 22 | Private room | 130 | 2504 | 28 | 89.4286 | 150 | 35 | +| 3 | Private room | 150 | 2504 | 28 | 89.4286 | 150 | 35 | +| 7 | Private room | 60 | 2504 | 28 | 89.4286 | 150 | 35 | +| 8 | Private room | 79 | 2504 | 28 | 89.4286 | 150 | 35 | +| 9 | Private room | 79 | 2504 | 28 | 89.4286 | 150 | 35 | +| 12 | Private room | 85 | 2504 | 28 | 89.4286 | 150 | 35 | +| 13 | Private room | 89 | 2504 | 28 | 89.4286 | 150 | 35 | +| 14 | Private room | 85 | 2504 | 28 | 89.4286 | 150 | 35 | +| 18 | Private room | 140 | 2504 | 28 | 89.4286 | 150 | 35 | +| 18 | Private room | 140 | 2504 | 28 | 89.4286 | 150 | 35 | +| 33 | Private room | 55 | 2504 | 28 | 89.4286 | 150 | 35 | +| 23 | Private room | 80 | 2504 | 28 | 89.4286 | 150 | 35 | +| 24 | Private room | 110 | 2504 | 28 | 89.4286 | 150 | 35 | +| 26 | Private room | 60 | 2504 | 28 | 89.4286 | 150 | 35 | +| 27 | Private room | 80 | 2504 | 28 | 89.4286 | 150 | 35 | +| 29 | Private room | 44 | 2504 | 28 | 89.4286 | 150 | 35 | +| 31 | Private room | 50 | 2504 | 28 | 89.4286 | 150 | 35 | +| 32 | Private room | 52 | 2504 | 28 | 89.4286 | 150 | 35 | +| 40 | Shared room | 40 | 40 | 1 | 40 | 40 | 40 | + ### Ranking window functions Ranking window functions are those that rank a value for each row in the window. @@ -49,14 +103,14 @@ In ranking functions, the `OVER` keyword is followed by the mandatory `ORDER BY` - `ROW_NUMBER` - returns the row number, used for numbering; - `RANK` - returns the rank of each row. Here's how it works: -- Sorting: firstly, rows are sorted by one or more columns. These columns are specified in `ORDER BY` in the `OVER` clause. -- Assigning ranks: each unique row or group of rows that have the same values in the sorting columns is assigned a rank. The rank starts from 1. -- Identical values: if several rows have the same values in the sorting columns, they receive the same rank. For example, if two rows are in second place, both receive rank 2. -- Skipping ranks: after a group of rows with the same rank, the next rank increases by the number of rows in that group. For example, if two rows have rank 2, the next row will get rank 4, not 3. -- Continuing sorting: this process continues until ranks have been assigned to all rows in the result set. + - Sorting: firstly, rows are sorted by one or more columns. These columns are specified in `ORDER BY` in the `OVER` clause. + - Assigning ranks: each unique row or group of rows that have the same values in the sorting columns is assigned a rank. The rank starts from 1. + - Identical values: if several rows have the same values in the sorting columns, they receive the same rank. For example, if two rows are in second place, both receive rank 2. + - Skipping ranks: after a group of rows with the same rank, the next rank increases by the number of rows in that group. For example, if two rows have rank 2, the next row will get rank 4, not 3. + - Continuing sorting: this process continues until ranks have been assigned to all rows in the result set. - `DENSE_RANK` - returns the rank of each row. Unlike the `RANK` function, it doesn't skip ranks and after a group of identical values, the rank increases by one, not by the number of rows. For example, if two rows have rank 2, the next row will get rank 3, not 4. -```sql-Airbnb-executable +```sql SELECT id, home_type, price, @@ -66,6 +120,59 @@ SELECT id, FROM Rooms; ``` +| id | home_type | price | row_number | rank | dense_rank | +| --- | --------------- | ----- | ---------- | ---- | ---------- | +| 5 | Entire home/apt | 80 | 1 | 1 | 1 | +| 38 | Entire home/apt | 85 | 2 | 2 | 2 | +| 4 | Entire home/apt | 89 | 3 | 3 | 3 | +| 19 | Entire home/apt | 99 | 4 | 4 | 4 | +| 48 | Entire home/apt | 110 | 5 | 5 | 5 | +| 49 | Entire home/apt | 115 | 6 | 6 | 6 | +| 25 | Entire home/apt | 120 | 7 | 7 | 7 | +| 15 | Entire home/apt | 120 | 8 | 7 | 7 | +| 42 | Entire home/apt | 120 | 9 | 7 | 7 | +| 11 | Entire home/apt | 135 | 10 | 10 | 8 | +| 16 | Entire home/apt | 140 | 11 | 11 | 9 | +| 28 | Entire home/apt | 150 | 12 | 12 | 10 | +| 10 | Entire home/apt | 150 | 13 | 12 | 10 | +| 45 | Entire home/apt | 150 | 14 | 12 | 10 | +| 46 | Entire home/apt | 150 | 15 | 12 | 10 | +| 30 | Entire home/apt | 180 | 16 | 16 | 11 | +| 20 | Entire home/apt | 190 | 17 | 17 | 12 | +| 6 | Entire home/apt | 200 | 18 | 18 | 13 | +| 17 | Entire home/apt | 215 | 19 | 19 | 14 | +| 2 | Entire home/apt | 225 | 20 | 20 | 15 | +| 21 | Entire home/apt | 299 | 21 | 21 | 16 | +| 37 | Private room | 35 | 1 | 1 | 1 | +| 29 | Private room | 44 | 2 | 2 | 2 | +| 34 | Private room | 50 | 3 | 3 | 3 | +| 31 | Private room | 50 | 4 | 3 | 3 | +| 32 | Private room | 52 | 5 | 5 | 4 | +| 33 | Private room | 55 | 6 | 6 | 5 | +| 26 | Private room | 60 | 7 | 7 | 6 | +| 7 | Private room | 60 | 8 | 7 | 6 | +| 41 | Private room | 68 | 9 | 9 | 7 | +| 35 | Private room | 70 | 10 | 10 | 8 | +| 8 | Private room | 79 | 11 | 11 | 9 | +| 9 | Private room | 79 | 12 | 11 | 9 | +| 27 | Private room | 80 | 13 | 13 | 10 | +| 23 | Private room | 80 | 14 | 13 | 10 | +| 50 | Private room | 80 | 15 | 13 | 10 | +| 12 | Private room | 85 | 16 | 16 | 11 | +| 14 | Private room | 85 | 17 | 16 | 11 | +| 13 | Private room | 89 | 18 | 18 | 12 | +| 36 | Private room | 89 | 19 | 18 | 12 | +| 24 | Private room | 110 | 20 | 20 | 13 | +| 43 | Private room | 120 | 21 | 21 | 14 | +| 22 | Private room | 130 | 22 | 22 | 15 | +| 47 | Private room | 130 | 23 | 22 | 15 | +| 44 | Private room | 135 | 24 | 24 | 16 | +| 18 | Private room | 140 | 25 | 25 | 17 | +| 1 | Private room | 149 | 26 | 26 | 18 | +| 3 | Private room | 150 | 27 | 27 | 19 | +| 39 | Private room | 150 | 28 | 27 | 19 | +| 40 | Shared room | 40 | 1 | 1 | 1 | + ### Offset window functions Offset window functions are those that allow moving and accessing different rows in the window relative to the current row, as well as accessing values at the beginning or end of the window. @@ -82,7 +189,7 @@ Offset window functions are those that allow moving and accessing different rows > When `ORDER BY` is used, the default window frame runs from the start of the partition to the current row (`RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`). Because of this, `LAST_VALUE` returns the value from the current row rather than the last row of the entire partition. To get the actual last value of the partition, explicitly extend the frame boundaries: `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`. -```sql-Airbnb-executable +```sql SELECT id, home_type, price, @@ -93,3 +200,56 @@ SELECT id, LAST_VALUE(price) OVER(PARTITION BY home_type ORDER BY price ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS "last_value" FROM Rooms; ``` + +| id | home_type | price | lag | lag_2 | lead | first_value | last_value | +| --- | --------------- | ----- | ---- | ----- | ---- | ----------- | ---------- | +| 5 | Entire home/apt | 80 | null | null | 85 | 80 | 299 | +| 38 | Entire home/apt | 85 | 80 | null | 89 | 80 | 299 | +| 4 | Entire home/apt | 89 | 85 | 80 | 99 | 80 | 299 | +| 19 | Entire home/apt | 99 | 89 | 85 | 110 | 80 | 299 | +| 48 | Entire home/apt | 110 | 99 | 89 | 115 | 80 | 299 | +| 49 | Entire home/apt | 115 | 110 | 99 | 120 | 80 | 299 | +| 25 | Entire home/apt | 120 | 115 | 110 | 120 | 80 | 299 | +| 15 | Entire home/apt | 120 | 120 | 115 | 120 | 80 | 299 | +| 42 | Entire home/apt | 120 | 120 | 120 | 135 | 80 | 299 | +| 11 | Entire home/apt | 135 | 120 | 120 | 140 | 80 | 299 | +| 16 | Entire home/apt | 140 | 135 | 120 | 150 | 80 | 299 | +| 28 | Entire home/apt | 150 | 140 | 135 | 150 | 80 | 299 | +| 10 | Entire home/apt | 150 | 150 | 140 | 150 | 80 | 299 | +| 45 | Entire home/apt | 150 | 150 | 150 | 150 | 80 | 299 | +| 46 | Entire home/apt | 150 | 150 | 150 | 180 | 80 | 299 | +| 30 | Entire home/apt | 180 | 150 | 150 | 190 | 80 | 299 | +| 20 | Entire home/apt | 190 | 180 | 150 | 200 | 80 | 299 | +| 6 | Entire home/apt | 200 | 190 | 180 | 215 | 80 | 299 | +| 17 | Entire home/apt | 215 | 200 | 190 | 225 | 80 | 299 | +| 2 | Entire home/apt | 225 | 215 | 200 | 299 | 80 | 299 | +| 21 | Entire home/apt | 299 | 225 | 215 | null | 80 | 299 | +| 37 | Private room | 35 | null | null | 44 | 35 | 150 | +| 29 | Private room | 44 | 35 | null | 50 | 35 | 150 | +| 34 | Private room | 50 | 44 | 35 | 50 | 35 | 150 | +| 31 | Private room | 50 | 50 | 44 | 52 | 35 | 150 | +| 32 | Private room | 52 | 50 | 50 | 55 | 35 | 150 | +| 33 | Private room | 55 | 52 | 50 | 60 | 35 | 150 | +| 26 | Private room | 60 | 55 | 52 | 60 | 35 | 150 | +| 7 | Private room | 60 | 60 | 55 | 68 | 35 | 150 | +| 41 | Private room | 68 | 60 | 60 | 70 | 35 | 150 | +| 35 | Private room | 70 | 68 | 60 | 79 | 35 | 150 | +| 8 | Private room | 79 | 70 | 68 | 79 | 35 | 150 | +| 9 | Private room | 79 | 79 | 70 | 80 | 35 | 150 | +| 27 | Private room | 80 | 79 | 79 | 80 | 35 | 150 | +| 23 | Private room | 80 | 80 | 79 | 80 | 35 | 150 | +| 50 | Private room | 80 | 80 | 80 | 85 | 35 | 150 | +| 12 | Private room | 85 | 80 | 80 | 85 | 35 | 150 | +| 14 | Private room | 85 | 85 | 80 | 89 | 35 | 150 | +| 13 | Private room | 89 | 85 | 85 | 89 | 35 | 150 | +| 36 | Private room | 89 | 89 | 85 | 110 | 35 | 150 | +| 24 | Private room | 110 | 89 | 89 | 120 | 35 | 150 | +| 43 | Private room | 120 | 110 | 89 | 130 | 35 | 150 | +| 22 | Private room | 130 | 120 | 110 | 130 | 35 | 150 | +| 47 | Private room | 130 | 130 | 120 | 135 | 35 | 150 | +| 44 | Private room | 135 | 130 | 130 | 140 | 35 | 150 | +| 18 | Private room | 140 | 135 | 130 | 149 | 35 | 150 | +| 1 | Private room | 149 | 140 | 135 | 150 | 35 | 150 | +| 3 | Private room | 150 | 149 | 140 | 150 | 35 | 150 | +| 39 | Private room | 150 | 150 | 149 | null | 35 | 150 | +| 40 | Shared room | 40 | null | null | null | 40 | 40 | diff --git a/course/module-5/windows-functions-frames/article.md b/course/module-5/windows-functions-frames/article.md index 92a33ef..1b78651 100644 --- a/course/module-5/windows-functions-frames/article.md +++ b/course/module-5/windows-functions-frames/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Window Frames, RANGE and ROWS' - description: 'Window frames in SQL - a concept that defines a subset of rows considered in window functions. Learn the difference between a window and a partition, as well as how to define window frames using ROWS and RANGE. Understand the differences between ROWS and RANGE in the context of SQL window functions.' + title: "Window Frames, RANGE and ROWS" + description: "Window frames in SQL - a concept that defines a subset of rows considered in window functions. Learn the difference between a window and a partition, as well as how to define window frames using ROWS and RANGE. Understand the differences between ROWS and RANGE in the context of SQL window functions." --- # Window frames @@ -20,25 +20,25 @@ Although the terms "window" and "partition" may seem similar, they represent dif where each subset contains rows with the same values in one or more columns. Window functions are applied separately to each partition, as if each were a separate data set. - ![Partition divition schema](https://sql-academy.org/static/guidePage/windows-functions-frames/partitions_visualisation_en.png "Partition divition schema") + ![Partition divition schema](https://sql-academy.org/static/guidePage/windows-functions-frames/partitions_visualisation_en.png "Partition divition schema") - Window. Defines which specific rows in each partition will be used for calculating the window function for each row. The window can change from row to row. - For example, if the rule `ROWS BETWEEN 1 PRECEDING AND CURRENT ROW` is used, - for each row the window will consist of the row itself and one preceding row. - This is like a "subpartition" within an existing partition. + For example, if the rule `ROWS BETWEEN 1 PRECEDING AND CURRENT ROW` is used, + for each row the window will consist of the row itself and one preceding row. + This is like a "subpartition" within an existing partition. - ![Partition divition schema](https://sql-academy.org/static/guidePage/windows-functions-frames/windows_visualisation_en.png "Partition divition schema") + ![Partition divition schema](https://sql-academy.org/static/guidePage/windows-functions-frames/windows_visualisation_en.png "Partition divition schema") - That is: + That is: - - The first window consists only of the 1st record, because there is no previous record. - The single record is passed to the aggregate function `AVG(price)` and the result is added to the `avg_price` field. - - The second window already contains records 1 and 2, which are sent to `AVG(price)` and return `(170 + 220) / 2 = 195`. - - The third window contains records 2 and 3, resulting in `(220 + 150) / 2 = 185`. - - and so on. + - The first window consists only of the 1st record, because there is no previous record. + The single record is passed to the aggregate function `AVG(price)` and the result is added to the `avg_price` field. + - The second window already contains records 1 and 2, which are sent to `AVG(price)` and return `(170 + 220) / 2 = 195`. + - The third window contains records 2 and 3, resulting in `(220 + 150) / 2 = 185`. + - and so on. ### Note on window without ROWS/RANGE @@ -96,13 +96,13 @@ For defining window frames, there are the keywords `ROWS` and `RANGE`. They work - Based on physical rows: - When using `ROWS`, the window definition is based on the physical position of rows relative to the current row. - For example, `1 PRECEDING `means one row before the current one. + When using `ROWS`, the window definition is based on the physical position of rows relative to the current row. + For example, `1 PRECEDING `means one row before the current one. - Precise frame: - Defining a window with `ROWS` clearly limits the number of rows included in the window, - making it predictable and specific. + Defining a window with `ROWS` clearly limits the number of rows included in the window, + making it predictable and specific. ![Window frame definition schema with rows](https://sql-academy.org/static/guidePage/windows-functions-frames/rows_example_en.png "Window frame definition schema with rows") @@ -110,12 +110,24 @@ For defining window frames, there are the keywords `ROWS` and `RANGE`. They work - Based on values: - `RANGE`, unlike `ROWS`, defines window frames based on column values, - ordered according to `ORDER BY` in the window function. + `RANGE`, unlike `ROWS`, defines window frames based on column values, + ordered according to `ORDER BY` in the window function. - Dynamic frames: - Frames defined with `RANGE` can vary - depending on the data, making the window flexible but potentially less predictable. + Frames defined with `RANGE` can vary + depending on the data, making the window flexible but potentially less predictable. ![Window frame definition schema with range](https://sql-academy.org/static/guidePage/windows-functions-frames/range_example_en.png "Window frame definition schema with range") + +Let's check if you understood the difference between `ROWS` and `RANGE` correctly: + +**Which of the following statements best describes the difference between using `ROWS` and `RANGE` in the context of SQL window functions?** + +1. ROWS and RANGE are interchangeable, as both define physical rows in the window — This is incorrect, as ROWS is based on the physical position of rows, while RANGE focuses on column values. + +2. **Correct answer:** ROWS defines window frames based on the physical position of rows, while RANGE is based on column values. — ROWS focuses on the physical position of rows, while RANGE uses column values to define window frames. + +3. RANGE uses the physical location of rows, while ROWS is based on column values. — This is incorrect, as ROWS is based on the physical position of rows, unlike RANGE, which focuses on column values. + +4. Both ROWS and RANGE define window frames solely based on column values. — This is incorrect, because only RANGE uses column values, while ROWS focuses on the physical location of rows. diff --git a/course/module-5/windows-functions/article.md b/course/module-5/windows-functions/article.md index 2a8e7b7..d0ef26d 100644 --- a/course/module-5/windows-functions/article.md +++ b/course/module-5/windows-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'SQL Window Functions' - description: 'SQL window functions, OVER syntax of a data window, window function, example of using a window function, execution queue of window functions in a select query' + title: "SQL Window Functions" + description: "SQL window functions, OVER syntax of a data window, window function, example of using a window function, execution queue of window functions in a select query" --- # SQL Window Functions @@ -29,28 +29,28 @@ Window functions always take a window of data as input, specified by the user, and return the result in a separate column. Let's consider an example using the `AVG` window function to calculate the average value. Here's a small table: -![Partitioning schema](https://sql-academy.org/static/guidePage/windows-functions/1_en.png "Partitioning schema") +![Initial table](https://sql-academy.org/static/guidePage/windows-functions/schema_table_en.png "Initial table") Now let's see how the window function works for different windows: - If the entire table is specified as the window, the window will be the same for all rows, and the same set of data will be passed to the `AVG` function, resulting in the same result. - ![Partitioning schema](https://sql-academy.org/static/guidePage/windows-functions/2_en.png "Partitioning schema") + ![Partitioning schema](https://sql-academy.org/static/guidePage/windows-functions/2_en.png "Partitioning schema") - If a partition is specified based on the `home_type` field, the `AVG` function will receive a set of residential properties with the same type, and the result will show the average cost of housing for the type that matches the current row. - ![Partitioning schema](https://sql-academy.org/static/guidePage/windows-functions/3_en.png "Partitioning schema") + ![Partitioning schema](https://sql-academy.org/static/guidePage/windows-functions/3_en.png "Partitioning schema") - A more specific set of rows can also be specified as the window. For example, the window can be defined as the "previous row + current row" of the table. In this case, it would look like this: - ![Partitioning schema](https://sql-academy.org/static/guidePage/windows-functions/4_en.png "Partitioning schema") + ![Partitioning schema](https://sql-academy.org/static/guidePage/windows-functions/4_en.png "Partitioning schema") - It's worth noting that for the first row, the window will consist of only one record, as there is no previous row. + It's worth noting that for the first row, the window will consist of only one record, as there is no previous row. ## Syntax of window functions @@ -81,11 +81,11 @@ We will delve into each of these parameters in more detail in the following arti Let's use window functions to get a list of students and their class sizes. - +Schedule database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/windows-functions). First, let's retrieve a list of students and their corresponding class IDs: -```sql-Schedule-executable +```sql SELECT Student.first_name, Student.last_name, @@ -96,9 +96,96 @@ JOIN Student ON Student_in_class.student = Student.id; ``` +| first_name | last_name | class | +| ---------- | ------------ | ----- | +| Nikolaj | Sokolov | 9 | +| Vyacheslav | Eliseev | 9 | +| Ivan | Efremov | 9 | +| Anatolij | ZHdanov | 9 | +| Georgij | Noskov | 9 | +| Artyom | Sergeev | 9 | +| Arina | Evseeva | 9 | +| Angelina | Voroncova | 9 | +| Ekaterina | Ustinova | 9 | +| Raisa | Lapina | 9 | +| Leonid | Ignatov | 9 | +| Snezhana | Seliverstova | 9 | +| Semyon | Biryukov | 9 | +| Georgij | Baranov | 8 | +| YUliya | Vishnyakova | 8 | +| Valentina | Bolshakova | 8 | +| Leonid | Kryukov | 8 | +| Vladislav | Cvetkov | 8 | +| Snezhana | Morozova | 8 | +| Lyubov | Borisova | 8 | +| Anfisa | Kalashnikova | 8 | +| Anna | Osipova | 8 | +| Kristina | Myasnikova | 8 | +| Kristina | Smirnova | 8 | +| Boris | Simonov | 7 | +| Dmitrij | Trofimov | 7 | +| YAkov | Rozhkov | 7 | +| Fyodor | Drozdov | 7 | +| Gleb | Strelkov | 7 | +| Angelina | Lukina | 7 | +| Nina | Odincova | 7 | +| Valeriya | Novikova | 7 | +| Grigorij | Kapustin | 7 | +| Vitalij | Panfilov | 7 | +| Svyatoslav | Tarasov | 6 | +| Matvej | YAkushev | 6 | +| Ilya | Alekseev | 6 | +| Lyubov | Zaharova | 6 | +| Polina | Sidorova | 6 | +| Elizaveta | Samojlova | 6 | +| YUliya | Avdeeva | 6 | +| Matvej | Bogdanov | 6 | +| Ilya | Filippov | 6 | +| Denis | Mel | 6 | +| Svyatoslav | Muravyov | 6 | +| Anna | Kulagina | 5 | +| ZHanna | Fokina | 5 | +| Valeriya | Lapina | 5 | +| Valentina | Sazonova | 5 | +| Nataliya | Myasnikova | 5 | +| Viktoriya | Makarova | 5 | +| Stanislav | Lazarev | 5 | +| Gennadij | Ovchinnikov | 5 | +| Roman | SHilov | 4 | +| Timur | Subbotin | 4 | +| Danila | Osipov | 4 | +| Arina | Silina | 4 | +| Nadezhda | Zaharova | 4 | +| Larisa | SHCHerbakova | 4 | +| Aleksandra | Belozyorova | 4 | +| Natalya | Davydova | 4 | +| Mariya | Fadeeva | 4 | +| YUrij | Markov | 3 | +| Kirill | SHubin | 3 | +| Grigorij | Kolobov | 3 | +| Semyon | Trofimov | 3 | +| Vasilij | Ustinov | 3 | +| Valentina | SHarova | 3 | +| Larisa | Savina | 3 | +| Galina | Orekhova | 3 | +| Arina | SHarapova | 2 | +| Viktoriya | Sergeeva | 2 | +| Vasilij | Krasilnikov | 2 | +| Timur | Rusakov | 2 | +| Gleb | Nesterov | 2 | +| Denis | Makarov | 2 | +| Elizaveta | SHilova | 2 | +| Vera | Evseeva | 1 | +| Margarita | Kabanova | 1 | +| Angelina | Lazareva | 1 | +| Semyon | Voronov | 1 | +| Innokentij | Nekrasov | 1 | +| Artyom | Nikitin | 1 | +| Egor | Belyakov | 1 | + To calculate the number of students studying in each class and display this information in a new column, we can use a window function: -```sql-Schedule-executable +```sql SELECT Student.first_name, Student.last_name, @@ -110,6 +197,93 @@ JOIN Student ON Student_in_class.student = Student.id; ``` +| first_name | last_name | class | student_count_in_class | +| ---------- | ------------ | ----- | ---------------------- | +| Egor | Belyakov | 1 | 7 | +| Artyom | Nikitin | 1 | 7 | +| Innokentij | Nekrasov | 1 | 7 | +| Semyon | Voronov | 1 | 7 | +| Angelina | Lazareva | 1 | 7 | +| Margarita | Kabanova | 1 | 7 | +| Vera | Evseeva | 1 | 7 | +| Denis | Makarov | 2 | 7 | +| Arina | SHarapova | 2 | 7 | +| Viktoriya | Sergeeva | 2 | 7 | +| Vasilij | Krasilnikov | 2 | 7 | +| Timur | Rusakov | 2 | 7 | +| Gleb | Nesterov | 2 | 7 | +| Elizaveta | SHilova | 2 | 7 | +| Kirill | SHubin | 3 | 8 | +| YUrij | Markov | 3 | 8 | +| Grigorij | Kolobov | 3 | 8 | +| Semyon | Trofimov | 3 | 8 | +| Valentina | SHarova | 3 | 8 | +| Larisa | Savina | 3 | 8 | +| Galina | Orekhova | 3 | 8 | +| Vasilij | Ustinov | 3 | 8 | +| Timur | Subbotin | 4 | 9 | +| Roman | SHilov | 4 | 9 | +| Danila | Osipov | 4 | 9 | +| Arina | Silina | 4 | 9 | +| Nadezhda | Zaharova | 4 | 9 | +| Larisa | SHCHerbakova | 4 | 9 | +| Aleksandra | Belozyorova | 4 | 9 | +| Natalya | Davydova | 4 | 9 | +| Mariya | Fadeeva | 4 | 9 | +| Gennadij | Ovchinnikov | 5 | 8 | +| Stanislav | Lazarev | 5 | 8 | +| Viktoriya | Makarova | 5 | 8 | +| Nataliya | Myasnikova | 5 | 8 | +| Valentina | Sazonova | 5 | 8 | +| Valeriya | Lapina | 5 | 8 | +| ZHanna | Fokina | 5 | 8 | +| Anna | Kulagina | 5 | 8 | +| Ilya | Filippov | 6 | 11 | +| Svyatoslav | Muravyov | 6 | 11 | +| Denis | Mel | 6 | 11 | +| Matvej | Bogdanov | 6 | 11 | +| YUliya | Avdeeva | 6 | 11 | +| Elizaveta | Samojlova | 6 | 11 | +| Polina | Sidorova | 6 | 11 | +| Lyubov | Zaharova | 6 | 11 | +| Ilya | Alekseev | 6 | 11 | +| Matvej | YAkushev | 6 | 11 | +| Svyatoslav | Tarasov | 6 | 11 | +| Nina | Odincova | 7 | 10 | +| Boris | Simonov | 7 | 10 | +| Dmitrij | Trofimov | 7 | 10 | +| YAkov | Rozhkov | 7 | 10 | +| Fyodor | Drozdov | 7 | 10 | +| Gleb | Strelkov | 7 | 10 | +| Angelina | Lukina | 7 | 10 | +| Valeriya | Novikova | 7 | 10 | +| Grigorij | Kapustin | 7 | 10 | +| Vitalij | Panfilov | 7 | 10 | +| Anna | Osipova | 8 | 11 | +| Georgij | Baranov | 8 | 11 | +| YUliya | Vishnyakova | 8 | 11 | +| Valentina | Bolshakova | 8 | 11 | +| Leonid | Kryukov | 8 | 11 | +| Vladislav | Cvetkov | 8 | 11 | +| Lyubov | Borisova | 8 | 11 | +| Anfisa | Kalashnikova | 8 | 11 | +| Snezhana | Morozova | 8 | 11 | +| Kristina | Myasnikova | 8 | 11 | +| Kristina | Smirnova | 8 | 11 | +| Vyacheslav | Eliseev | 9 | 13 | +| Ivan | Efremov | 9 | 13 | +| Anatolij | ZHdanov | 9 | 13 | +| Georgij | Noskov | 9 | 13 | +| Artyom | Sergeev | 9 | 13 | +| Arina | Evseeva | 9 | 13 | +| Angelina | Voroncova | 9 | 13 | +| Ekaterina | Ustinova | 9 | 13 | +| Raisa | Lapina | 9 | 13 | +| Leonid | Ignatov | 9 | 13 | +| Snezhana | Seliverstova | 9 | 13 | +| Semyon | Biryukov | 9 | 13 | +| Nikolaj | Sokolov | 9 | 13 | + ### What does our window function do? The expression `PARTITION BY Student_in_class.class` divides all rows of the table into @@ -127,3 +301,13 @@ When using window functions, it is important to understand the order in which th ## Conclusion In this article, we briefly covered the concept of window functions, their capabilities, and practical benefits. In the following articles, we will delve into each aspect of window functions in more detail. + +To wrap up, let's test your understanding: + +**What is the key difference between window functions and aggregate functions with grouping in SQL?** + +1. Window functions and aggregate functions with grouping perform the same calculations but with different syntax. — Window functions and aggregate functions with grouping have different functionality and cannot be used interchangeably. + +2. **Correct answer:** Window functions are calculated independently for each row, returning the result in a separate column. Aggregate functions with grouping, on the other hand, group rows and apply to the formed groups. — Window functions provide calculations for each row, taking into account a set of rows (window) related to the current row, while aggregate functions with grouping provide a single result for each group formed based on the grouping criteria. + +3. Window functions use PARTITION BY, while aggregate functions with grouping do not. — Although PARTITION BY is indeed a feature of window functions, the key difference lies in how the functions are applied to the data (by rows versus groups). diff --git a/course/module-5/work-with-datatypes/article.md b/course/module-5/work-with-datatypes/article.md index 9d44cd1..95fc926 100644 --- a/course/module-5/work-with-datatypes/article.md +++ b/course/module-5/work-with-datatypes/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Working with Data Types' - description: 'Advanced exploration of working with data types in SQL' + title: "Working with Data Types" + description: "Advanced exploration of working with data types in SQL" --- # Working with Data Types diff --git a/course/module-5/work-with-datetime-data-type/article.md b/course/module-5/work-with-datetime-data-type/article.md index 08eb6ca..326d91e 100644 --- a/course/module-5/work-with-datetime-data-type/article.md +++ b/course/module-5/work-with-datetime-data-type/article.md @@ -1,11 +1,9 @@ --- meta: - title: "Date and time in SQL: functions YEAR, MONTH, TIMESTAMPDIFF, STR_TO_DATE" - description: "Working with date and time in SQL: functions YEAR, MONTH, DAY, TIMESTAMPDIFF, STR_TO_DATE, EXTRACT. Data types DATE, TIME, DATETIME, TIMESTAMP in MySQL and PostgreSQL." + title: "Date and time in SQL: functions YEAR, MONTH, TIMESTAMPDIFF, STR_TO_DATE" + description: "Working with date and time in SQL: functions YEAR, MONTH, DAY, TIMESTAMPDIFF, STR_TO_DATE, EXTRACT. Data types DATE, TIME, DATETIME, TIMESTAMP in MySQL and PostgreSQL." --- - - # Date and time in SQL Among all the data types in SQL, date and time data is the most complex 🤯. @@ -28,7 +26,7 @@ Date and time data can be retrieved in one of the following ways: The following formats are used to set the date and time: - +**MySQL** | Type | Default Format | | :---------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -38,9 +36,7 @@ The following formats are used to set the date and time: | `TIME` | `hhh:mm:sss` | | `YEAR` | `YYYY` - full format
`YY` or `Y` - shorthand format that returns a year between 2000-2069 for values ​​0-69 and a year between 1970-1999 for values ​​70-99 | -
- - +**PostgreSQL** | Type | Default Format | | :---------- | :-------------------- | @@ -48,16 +44,14 @@ The following formats are used to set the date and time: | `TIMESTAMP` | `YYYY-MM-DD hh:mm:ss` | | `TIME` | `hh:mm:ss` | - - Moreover, when specifying a date, it is allowed to use any punctuation mark as a separator between parts of the date or time sections. It is also possible to set the date without a separator character at all, together. Examples of valid setting of values ​​for date and time via string representation: - +**MySQL** -```sql-executable +```sql SELECT CAST("2022-06-16 16:37:23" AS DATETIME) AS datetime_1, CAST("2014/02/22 16*37*22" AS DATETIME) AS datetime_2, CAST("20220616163723" AS DATETIME) AS datetime_3, @@ -66,11 +60,13 @@ SELECT CAST("2022-06-16 16:37:23" AS DATETIME) AS datetime_1, CAST("89" AS YEAR) AS year ``` - +| datetime_1 | datetime_2 | datetime_3 | date_1 | time_1 | year | +| ------------------------ | ------------------------ | ------------------------ | ------------------------ | --------- | ---- | +| 2022-06-16T16:37:23.000Z | 2014-02-22T16:37:22.000Z | 2022-06-16T16:37:23.000Z | 2021-02-12T00:00:00.000Z | 160:23:13 | 1989 | - +**PostgreSQL** -```sql-executable +```sql SELECT CAST('2022-06-16 16:37:23' AS TIMESTAMP) AS timestamp_1, CAST('2014/02/22 16:37:22' AS TIMESTAMP) AS timestamp_2, CAST('20220616163723' AS TIMESTAMP) AS timestamp_3, @@ -78,102 +74,100 @@ SELECT CAST('2022-06-16 16:37:23' AS TIMESTAMP) AS timestamp_1, CAST('16:23:13' AS TIME) AS time_1 ``` - +| timestamp_1 | timestamp_2 | timestamp_3 | date_1 | time_1 | +| ------------------------ | ------------------------ | ------------------------ | ------------------------ | -------- | +| 2022-06-16T16:37:23.000Z | 2014-02-22T16:37:22.000Z | 2022-06-16T16:37:23.000Z | 2021-02-12T00:00:00.000Z | 16:23:13 | In the query above, the `CAST` function was used to force the string to be converted to a date and time. It is needed if the server does not expect the date and time and, accordingly, does not automatically convert the string -to the correct type. We'll learn more about type conversion in "Type conversion functions, CAST". +to the correct type. We'll learn more about type conversion in "Type conversion functions, CAST". ### Date generation functions If you need to get the date and time from a string that does not match any format that accepts the `CAST` function, you can use special functions for parsing dates. - +**MySQL** MySQL has a built-in `STR_TO_DATE` function, which takes an arbitrary string containing a date and a format describing it. -```sql-executable +```sql SELECT STR_TO_DATE('November 13, 1998', '%M %d, %Y') AS date; ``` -For a more detailed description of the `STR_TO_DATE` function and its arguments, see in the reference. +| date | +| ------------------------ | +| 1998-11-13T00:00:00.000Z | - +For a more detailed description of the `STR_TO_DATE` function and its arguments, see in the reference. - +**PostgreSQL** PostgreSQL has a built-in `TO_DATE` function, which takes an arbitrary string containing a date and a format describing it. -```sql-executable +```sql SELECT TO_DATE('November 13, 1998', 'Month DD, YYYY') AS date; ``` -For a more detailed description of the `TO_DATE` function and its arguments, see in the reference. +| date | +| ------------------------ | +| 1998-11-13T00:00:00.000Z | - +For a more detailed description of the `TO_DATE` function and its arguments, see in the reference. To generate the current date or time, there is no need to create a string for its subsequent conversion to a date, because there are built-in functions for getting given values. - +**MySQL** In MySQL these are the `CURDATE`, `CURTIME` and `NOW` functions. -```sql-executable +```sql SELECT CURDATE(), CURTIME(), NOW(); ``` - - - +**PostgreSQL** In PostgreSQL these are the `CURRENT_DATE`, `CURRENT_TIME` and `NOW` functions. -```sql-executable +```sql SELECT CURRENT_DATE, CURRENT_TIME, NOW(); ``` - - ## Date and Time Extraction Functions Sometimes it is necessary to obtain information not about the full date, but about its specific part, for example, about its month or year. - +**MySQL** To do this, SQL has the following functions: -| Function | Description | -| :------------------------------------------------------------ | :--------------------------------------------------------------------------- | -| `YEAR` | Returns the year for the specified date | -| `MONTH` | Returns the numeric value of the month of the year (from 1 to 12) for a date | -| `DAY` | Returns the ordinal number of the day in the month (from 1 to 31) | -| `HOUR` | Returns the hour value (between 0 and 23) for the time | -| `MINUTE` | Returns the minutes value (from 0 to 59) for the time | - - +| Function | Description | +| :-------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | +| `YEAR` | Returns the year for the specified date | +| `MONTH` | Returns the numeric value of the month of the year (from 1 to 12) for a date | +| `DAY` | Returns the ordinal number of the day in the month (from 1 to 31) | +| `HOUR` | Returns the hour value (between 0 and 23) for the time | +| `MINUTE` | Returns the minutes value (from 0 to 59) for the time | - +**PostgreSQL** To do this, PostgreSQL uses the `EXTRACT` function: -| Function | Description | -| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | -| `EXTRACT(YEAR FROM date)` | Returns the year for the specified date | -| `EXTRACT(MONTH FROM date)` | Returns the numeric value of the month of the year (from 1 to 12) for a date | -| `EXTRACT(DAY FROM date)` | Returns the ordinal number of the day in the month (from 1 to 31) | -| `EXTRACT(HOUR FROM time)` | Returns the hour value (between 0 and 23) for the time | -| `EXTRACT(MINUTE FROM time)` | Returns the minutes value (from 0 to 59) for the time | +| Function | Description | +| :--------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | +| `EXTRACT(YEAR FROM date)` | Returns the year for the specified date | +| `EXTRACT(MONTH FROM date)` | Returns the numeric value of the month of the year (from 1 to 12) for a date | +| `EXTRACT(DAY FROM date)` | Returns the ordinal number of the day in the month (from 1 to 31) | +| `EXTRACT(HOUR FROM time)` | Returns the hour value (between 0 and 23) for the time | +| `EXTRACT(MINUTE FROM time)` | Returns the minutes value (from 0 to 59) for the time | - +**MySQL** - +## The difference between DATETIME and TIMESTAMP -## MySQL: The difference between DATETIME and TIMESTAMP - -MySQL has very similar data types: `DATETIME` and `TIMESTAMP`. Both are aimed at storing the date and time. +There are very similar data types: `DATETIME` and `TIMESTAMP`. Both are aimed at storing the date and time. But they have a number of differences that determine which of these data types is best to use when. | Criteria | `DATETIME` | `TIMESTAMP` | @@ -181,21 +175,17 @@ But they have a number of differences that determine which of these data types i | Range | from `1000-01-01 00:00:00`
to `9999-12-31 23:59:59` | from `1970-01-01 00:00:00`
to `2038-01-19 03:14:07` | | Time zone | Ignored
Displayed as the date was set | Taken into account
When making selections, it is displayed taking into account the current time zone of the database server | -
- - +**PostgreSQL** -## PostgreSQL: The difference between TIMESTAMP and TIMESTAMPTZ +## The difference between TIMESTAMP and TIMESTAMPTZ -PostgreSQL has the main types for storing date and time: `TIMESTAMP` (without time zone) and `TIMESTAMPTZ` (with time zone). +The main types for storing date and time are `TIMESTAMP` (without time zone) and `TIMESTAMPTZ` (with time zone). | Criteria | `TIMESTAMP` | `TIMESTAMPTZ` | | :-------- | :------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | | Range | from `4713 BC` to `294276 AD` | from `4713 BC` to `294276 AD` | | Time zone | Ignored
Displayed as the date was set | Taken into account
When making selections, it is displayed taking into account the current time zone of the database server | -
- ## Time zones Since people all over the world want noon to approximate the maximum rise of the Sun, there has never been a problem @@ -210,7 +200,7 @@ The time zone is one of the database server settings and can be set: - for the current user - for the current user session - +**MySQL** ```sql SET GLOBAL time_zone = '+03:00'; // globally @@ -220,9 +210,7 @@ SET @@session.time_zone = '+03:00'; // for the current user session Accordingly, when changing the time zone, all values ​​of the `TIMESTAMP` type will be displayed taking into account the current active time zone. - - - +**PostgreSQL** ```sql ALTER DATABASE mydb SET timezone = 'Europe/Moscow'; // globally for database @@ -233,8 +221,6 @@ SET TIME ZONE '+03:00'; // for current session Accordingly, when changing the time zone, all values ​​of the `TIMESTAMPTZ` type will be displayed taking into account the current active time zone. - - ## Examples of tasks for date and time I would like to pay special attention to the most popular tasks related to the temporary data type, @@ -245,22 +231,18 @@ where mistakes are often made. When setting the task to find the age of a person by the date of his birth, there is often a temptation 😈 to calculate the difference between the current year and the person's year of birth: - +**MySQL** -```sql-executable +```sql SELECT YEAR(NOW()) - YEAR('2003-07-03 14:10:26'); ``` - - - +**PostgreSQL** -```sql-executable +```sql SELECT EXTRACT(YEAR FROM NOW()) - EXTRACT(YEAR FROM TIMESTAMP '2003-07-03 14:10:26'); ``` - - The problem with this approach is that it does not take into account whether the person had a birthday this year or not yet. That is, if at the time of the request it was already July 3rd (07-03), then the person celebrated his birthday and he is already 20 years old, otherwise he is still 19 years old. @@ -269,46 +251,38 @@ The difference in functions will be useless here - in both cases it will give 20 If determining the age in terms of the difference in years is a non-working option, then you may want to find the age in terms of the difference of days between two dates, then divide this difference by the number of days in a year and round down: - +**MySQL** -```sql-executable +```sql SELECT FLOOR(DATEDIFF(NOW(), '2003-07-03 14:10:26') / 365); ``` - +**PostgreSQL** - - -```sql-executable +```sql SELECT FLOOR(EXTRACT(DAY FROM NOW() - TIMESTAMP '2003-07-03 14:10:26') / 365); ``` - - And this solution will be much more accurate than the previous one. But it will not be absolutely accurate due to the presence of leap years, when there are 366 days in a year. Although the error in calculating the age for 1 person due to the presence of a leap year is quite small, in the calculations for determining, say, average age among a certain list of people, the error can accumulate and distort the real values. And how then is it correct to determine the age? - +**MySQL** -There is a built-in function for this - `TIMESTAMPDIFF`, +There is a built-in function for this - `TIMESTAMPDIFF`, which takes as its first argument the unit in which to return the difference between two time values. -```sql-executable +```sql SELECT TIMESTAMPDIFF(YEAR, '2003-07-03 14:10:26', NOW()); ``` - +**PostgreSQL** - - -For this purpose, the `EXTRACT` function is used together with the `AGE` function, +For this purpose, the `EXTRACT` function is used together with the `AGE` function, which calculates the exact interval between two dates. -```sql-executable +```sql SELECT EXTRACT(YEAR FROM AGE(NOW(), TIMESTAMP '2003-07-03 14:10:26')); ``` - - diff --git a/course/module-5/work-with-number-data-type/article.md b/course/module-5/work-with-number-data-type/article.md index d4d06b4..89551f9 100644 --- a/course/module-5/work-with-number-data-type/article.md +++ b/course/module-5/work-with-number-data-type/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Numeric data type in SQL: mathematical functions, rounding, ROUND, TRUNCATE" - description: "Working with numbers in SQL: mathematical functions ROUND, TRUNCATE, CEILING, FLOOR, ABS, SIGN. Number rounding, precision control in MySQL and PostgreSQL." + title: "Numeric data type in SQL: mathematical functions, rounding, ROUND, TRUNCATE" + description: "Working with numbers in SQL: mathematical functions ROUND, TRUNCATE, CEILING, FLOOR, ABS, SIGN. Number rounding, precision control in MySQL and PostgreSQL." --- # Numeric data type in SQL @@ -11,132 +11,154 @@ generate it by calculation. When calculating, you can use all standard arithmetic operations (`+`, `-`, `*`, `/` and others) and change the priorities of calculations using brackets. -```sql-executable +```sql SELECT 2 * ((22 - 16) / (2 + 1)) AS calc_example; ``` +| calc_example | +| ------------ | +| 4 | + ## Math functions For most mathematical calculations, such as getting the power of a number or getting the square root, in SQL there are built-in numeric functions. Here are some examples of these functions: - - -| Function name | Description | -| :------------------------------------------------------------------ | ---------------------------------------------------------- | -| `POW(num, power)` | Calculates a number to the specified power | -| `SQRT(num)` | Calculates the square root of a number | -| `LOG(base, num)` | Calculates the logarithm of a number to the specified base | -| `EXP(num)` | Calculates enum | -| `SIN(num)` | Calculates the sine of a number | -| `COS(num)` | Calculates the cosine of a number | -| `TAN(num)` | Calculates the tangent of a number | +**MySQL** -A list of all numeric functions, their descriptions and examples can be found in the handbook. +| Function name | Description | +| :-------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | +| `POW(num, power)` | Calculates a number to the specified power | +| `SQRT(num)` | Calculates the square root of a number | +| `LOG(base, num)` | Calculates the logarithm of a number to the specified base | +| `EXP(num)` | Calculates enum | +| `SIN(num)` | Calculates the sine of a number | +| `COS(num)` | Calculates the cosine of a number | +| `TAN(num)` | Calculates the tangent of a number | - +A list of all numeric functions, their descriptions and examples can be found in the handbook. - +**PostgreSQL** -| Function name | Description | -| :--------------------------------------------------------------------------- | ---------------------------------------------------------- | -| `POWER(num, power)` | Calculates a number to the specified power | -| `SQRT(num)` | Calculates the square root of a number | -| `LOG(base, num)` | Calculates the logarithm of a number to the specified base | -| `EXP(num)` | Calculates enum | -| `SIN(num)` | Calculates the sine of a number | -| `COS(num)` | Calculates the cosine of a number | -| `TAN(num)` | Calculates the tangent of a number | +| Function name | Description | +| :----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | +| `POWER(num, power)` | Calculates a number to the specified power | +| `SQRT(num)` | Calculates the square root of a number | +| `LOG(base, num)` | Calculates the logarithm of a number to the specified base | +| `EXP(num)` | Calculates enum | +| `SIN(num)` | Calculates the sine of a number | +| `COS(num)` | Calculates the cosine of a number | +| `TAN(num)` | Calculates the tangent of a number | -A list of all numeric functions, their descriptions and examples can be found in the handbook. - - +A list of all numeric functions, their descriptions and examples can be found in the handbook. ## Round numbers When working with floating point numbers, it is not always necessary to store or display numbers with full precision. So, monetary transactions can be stored with an accuracy of up to 6 decimal places, and displayed up to 2, with an accuracy of kopecks. - +**MySQL** SQL provides the following 4 functions for rounding numeric data: `CEIL`, `FLOOR`, `ROUND`, `TRUNCATE`. The functions `CEIL`, `FLOOR` are aimed at rounding a number to the nearest integer up and down, respectively. -```sql-executable +```sql SELECT CEILING(69.69) AS ceiling, FLOOR(69.69) AS floor; ``` - - - +**PostgreSQL** SQL provides the following 4 functions for rounding numeric data: `CEIL`, `FLOOR`, `ROUND`, `TRUNC`. The functions `CEIL`, `FLOOR` are aimed at rounding a number to the nearest integer up and down, respectively. -```sql-executable +```sql SELECT CEIL(69.69) AS ceiling, FLOOR(69.69) AS floor; ``` - +| ceiling | floor | +| ------- | ----- | +| 70 | 69 | To round to the nearest integer, there is a `ROUND` function, which rounds any number whose decimal part is greater than or equal to 0.5. side, otherwise less. -```sql-executable +```sql SELECT ROUND(69.499), ROUND(69.5), ROUND(69.501); ``` +| ROUND(69.499) | ROUND(69.5) | ROUND(69.501) | +| ------------- | ----------- | ------------- | +| 69 | 70 | 70 | + The `ROUND` function also allows you to round a number to some fraction of decimal places. To do this, the function takes an optional second argument indicating the number of decimal places to leave. -```sql-executable +```sql SELECT ROUND(69.7171,1), ROUND(69.7171,2), ROUND(69.7171,3); ``` +| ROUND(69.7171,1) | ROUND(69.7171,2) | ROUND(69.7171,3) | +| ---------------- | ---------------- | ---------------- | +| 69.7 | 69.72 | 69.717 | + The second argument to the `ROUND` function can also take negative values. In this case, the digits to the left of the decimal point of the number become equal to zero by the number specified in the argument, and the fractional part is cut off. -```sql-executable +```sql SELECT ROUND(1691.7,-1), ROUND(1691.7,-2), ROUND(1691.7,-3); ``` - +| ROUND(1691.7,-1) | ROUND(1691.7,-2) | ROUND(1691.7,-3) | +| ---------------- | ---------------- | ---------------- | +| 1690 | 1700 | 2000 | + +**MySQL** The `TRUNCATE` function is similar to the `ROUND` function, it is also capable of taking an optional 2nd parameter, only instead of rounding it simply discards unnecessary numbers. -```sql-executable +```sql SELECT TRUNCATE(69.7979,1), TRUNCATE(69.7979,2), TRUNCATE(69.7979,3); ``` +| TRUNCATE(69.7979,1) | TRUNCATE(69.7979,2) | TRUNCATE(69.7979,3) | +| ------------------- | ------------------- | ------------------- | +| 69.7 | 69.79 | 69.797 | + What will the following expression return? -```sql-executable +```sql SELECT TRUNCATE(69.7979, -1); ``` - - - +**PostgreSQL** The `TRUNC` function is similar to the `ROUND` function, it is also capable of taking an optional 2nd parameter, only instead of rounding it simply discards unnecessary numbers. -```sql-executable +```sql SELECT TRUNC(69.7979,1), TRUNC(69.7979,2), TRUNC(69.7979,3); ``` +| TRUNC(69.7979,1) | TRUNC(69.7979,2) | TRUNC(69.7979,3) | +| ---------------- | ---------------- | ---------------- | +| 69.7 | 69.79 | 69.797 | + What will the following expression return? -```sql-executable +```sql SELECT TRUNC(69.7979, -1); ``` - +1. 69.7 — If the function takes a negative value as the second argument, then the digits to the left of the decimal point of the number become equal to zero by the number specified in the argument, and the fractional part is truncated. + +2. 69 — If the function takes a negative value as the second argument, then the digits to the left of the decimal point of the number become equal to zero by the number specified in the argument, and the fractional part is truncated. + +3. **Correct answer:** 60 — Good job 🤩, you are absolutely right! ## Working with signed numbers @@ -144,12 +166,20 @@ When working with numeric data that may contain negative values, the `SIGN` and The `SIGN` function returns `-1` if the number is negative, `0` if the number is zero, and `1` if the number is positive. -```sql-executable +```sql SELECT SIGN(-69), SIGN(0), SIGN(69); ``` +| SIGN(-69) | SIGN(0) | SIGN(69) | +| --------- | ------- | -------- | +| -1 | 0 | 1 | + The `ABS` function returns the absolute value of a number. -```sql-executable +```sql SELECT ABS(-69), ABS(0), ABS(69); ``` + +| ABS(-69) | ABS(0) | ABS(69) | +| -------- | ------ | ------- | +| 69 | 0 | 69 | diff --git a/course/module-6/constraints/article.md b/course/module-6/constraints/article.md index a1daa54..a9df351 100644 --- a/course/module-6/constraints/article.md +++ b/course/module-6/constraints/article.md @@ -1,7 +1,7 @@ --- meta: - title: "SQL Constraints: MySQL and PostgreSQL" - description: "A comprehensive guide to SQL constraints in MySQL and PostgreSQL, explaining how they ensure data correctness and integrity in database tables. Learn about different types of constraints including PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK, and DEFAULT." + title: "SQL Constraints: MySQL and PostgreSQL" + description: "A comprehensive guide to SQL constraints in MySQL and PostgreSQL, explaining how they ensure data correctness and integrity in database tables. Learn about different types of constraints including PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK, and DEFAULT." --- # Column Constraints in SQL @@ -32,7 +32,7 @@ Let's look at each type in more detail. A primary key is a column or combination of columns that uniquely identifies each row in a table. It cannot contain NULL values and must be unique. A table can have only one primary key. - +**MySQL** ```sql CREATE TABLE Users ( @@ -59,9 +59,7 @@ When attempting to add a record with an already existing primary key or with a N Error(1062) 23000: "Duplicate entry '1' for key 'users.PRIMARY'" ``` - - - +**PostgreSQL** ```sql CREATE TABLE Users ( @@ -89,8 +87,6 @@ ERROR: duplicate key value violates unique constraint "users_pkey" DETAIL: Key (id)=(1) already exists. ``` - - ## FOREIGN KEY A foreign key is a column or group of columns in one table that references the primary key of another table. It ensures referential integrity of data, guaranteeing that values in the foreign key column correspond to values from the primary key column of the related table. @@ -161,7 +157,7 @@ In this example, the `username` and `email` fields are required, while `bio` can ## CHECK - +**MySQL** The CHECK constraint allows you to define a condition that values in a column must satisfy. This helps enforce business rules and prevent incorrect data entry. @@ -189,9 +185,7 @@ CREATE TABLE Employees ( ); ``` - - - +**PostgreSQL** The CHECK constraint allows you to define a condition that values in a column must satisfy. This helps enforce business rules and prevent incorrect data entry. @@ -229,13 +223,11 @@ CREATE TABLE Users ( ); ``` - - ## DEFAULT The DEFAULT constraint sets a value that will be used if no value is specified for this column when adding a new record. - +**MySQL** ```sql CREATE TABLE Orders ( @@ -249,9 +241,7 @@ CREATE TABLE Orders ( In this example, if no order date is specified, the current date will be used, and the status will default to "Pending". - - - +**PostgreSQL** ```sql CREATE TABLE Orders ( @@ -277,11 +267,9 @@ CREATE TABLE Users ( ); ``` - - ## Adding and Removing Constraints - +**MySQL** Constraints can be added not only when creating a table but also when modifying it: @@ -339,9 +327,7 @@ ALTER TABLE Orders ALTER COLUMN status DROP DEFAULT; ``` - - - +**PostgreSQL** Constraints can be added not only when creating a table but also when modifying it: @@ -399,8 +385,6 @@ ALTER TABLE Orders ALTER COLUMN status DROP DEFAULT; ``` - - ## Best Practices for Using Constraints 🚀 When designing a database, follow these recommendations: @@ -422,3 +406,11 @@ When designing a database, follow these recommendations: ## Test Your Knowledge About SQL Constraints: Which of the following SQL constraints CANNOT contain NULL values? + +1. UNIQUE — The UNIQUE constraint allows NULL values, although usually only one NULL value in a column. + +2. CHECK — The CHECK constraint only checks conditions for non-empty values; NULL values are usually bypassed by the check. + +3. **Correct answer:** PRIMARY KEY — A primary key cannot contain NULL values as it must uniquely identify each row in a table. + +4. FOREIGN KEY — A foreign key can contain NULL values unless specified otherwise, indicating no relationship with another table. diff --git a/course/module-6/create-database/article.md b/course/module-6/create-database/article.md index 9570351..9a53ae2 100644 --- a/course/module-6/create-database/article.md +++ b/course/module-6/create-database/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Creating and deleting databases: MySQL and PostgreSQL" - description: "SQL syntax for creating and dropping databases in MySQL and PostgreSQL: CREATE DATABASE, DROP DATABASE, IF EXISTS, and IF NOT EXISTS." + title: "Creating and deleting databases: MySQL and PostgreSQL" + description: "SQL syntax for creating and dropping databases in MySQL and PostgreSQL: CREATE DATABASE, DROP DATABASE, IF EXISTS, and IF NOT EXISTS." --- # Creating and deleting databases @@ -16,9 +16,9 @@ Database creation has the following syntax: CREATE DATABASE database_name; ``` -### MySQL +**MySQL** -In MySQL, database names usually use letters, numbers, and the characters "\_" and "$". The maximum name length is 64 characters. +Database names usually use letters, numbers, and the characters "\_" and "$". The maximum name length is 64 characters. You can control the creation of the database using the `SHOW DATABASES` operator. @@ -26,11 +26,20 @@ You can control the creation of the database using the `SHOW DATABASES` operator SHOW DATABASES; ``` +| Database | +| ------------------ | +| user_table_1 | +| user_table_2 | +| information_schema | +| mysql | +| performance_schema | +| sys | + > Note that the `SHOW DATABASES` operator, in addition to user databases, also displays service databases: information_schema, mysql, performance_schema, sys. -### PostgreSQL +**PostgreSQL** -In PostgreSQL, if a database name is written without double quotes, it must start with a letter or the "\_" character. After that, you can use letters, numbers, as well as the "\_" and "$" characters. The maximum name length is 63 characters. +If a database name is written without double quotes, it must start with a letter or the "\_" character. After that, you can use letters, numbers, as well as the "\_" and "$" characters. The maximum name length is 63 characters. You can control the creation of the database using an SQL query: @@ -38,6 +47,12 @@ You can control the creation of the database using an SQL query: SELECT datname FROM pg_database WHERE datistemplate = false; ``` +| datname | +| --------------- | +| user_database_1 | +| user_database_2 | +| postgres | + > Note that in addition to user databases, PostgreSQL also contains service databases: postgres, template0, template1. ## Deleting database @@ -48,31 +63,35 @@ Deleting a database is done using the `DROP DATABASE` operator: DROP DATABASE database_name; ``` -> PostgreSQL: you cannot drop a database if the current session is connected to it. The command will also fail if other active sessions are connected to that database. +**PostgreSQL** -## IF EXISTS and IF NOT EXISTS +> You cannot drop a database if the current session is connected to it. The command will also fail if other active sessions are connected to that database. -### MySQL +**MySQL** + +## IF EXISTS and IF NOT EXISTS When creating or deleting a database, an error may occur. For example, the database may already exist or, on the contrary, may not exist yet. In such cases, the `IF EXISTS` and `IF NOT EXISTS` constructions are used. -If we want to create a database only on the condition that it does not exist yet, then we use the following syntax: +That is, if we want to create a database only on the condition that it does not exist yet, then we use following syntax: ```sql CREATE DATABASE IF NOT EXISTS database_name; ``` -If we want to delete the database only if it exists, then we use the following syntax: +If we want to delete the database only if it exists, then we use following syntax: ```sql DROP DATABASE IF EXISTS database_name; ``` -### PostgreSQL +**PostgreSQL** + +## IF EXISTS When deleting a database, an error may occur if such a database does not exist. In this case, you can use the `IF EXISTS` construction. -In PostgreSQL, you can use the `IF EXISTS` construction when deleting a database: +When deleting a database, you can use the `IF EXISTS` construction: ```sql DROP DATABASE IF EXISTS database_name; diff --git a/course/module-6/create-table/article.md b/course/module-6/create-table/article.md index 7678f58..8e97cf4 100644 --- a/course/module-6/create-table/article.md +++ b/course/module-6/create-table/article.md @@ -1,14 +1,14 @@ --- meta: - title: 'Creating and deleting tables: MySQL and PostgreSQL' - description: 'SQL create and delete tables in MySQL and PostgreSQL. Table description operators.' + title: "Creating and deleting tables: MySQL and PostgreSQL" + description: "SQL create and delete tables in MySQL and PostgreSQL. Table description operators." --- # Creating and deleting tables ## Creating a table -### MySQL +**MySQL** Before creating the table, you need to select the database to which the table will be written. This is done using the `USE` statement: @@ -27,7 +27,9 @@ CREATE TABLE [IF NOT EXISTS] table_name ( ); ``` -For example, let's create a table of users: +For example, let's create a table of users. + +**MySQL** ```sql CREATE TABLE Users ( @@ -39,20 +41,7 @@ CREATE TABLE Users ( `INTEGER`, `VARCHAR(255)` - data types: numeric and string, respectively. More details about them can be found in the following articles. -### PostgreSQL - -The `CREATE TABLE` statement is used to create the table. Its simplest use is as follows: - -```sql -CREATE TABLE [IF NOT EXISTS] table_name ( - column_1 data type, - [column_2 data type,] - ... - [column_n data type,] -); -``` - -For example, let's create a table of users: +**PostgreSQL** ```sql CREATE TABLE Users ( @@ -66,280 +55,328 @@ CREATE TABLE Users ( ## Additional column definition options -The definition of columns in a table shown above is simplified. In addition to the name of the column and its type, it is sometimes necessary to add the following optional parameters: +The above definition of columns in a table is simplified. In addition to the name of the column and its type, +it is sometimes necessary to add the following optional parameters to the definition: -- `PRIMARY KEY` specifies a column or set of columns as the primary key. -- `UNIQUE` indicates that the values in this column for all records must be different from each other. -- `NOT NULL` indicates that the values in this column must be different from `NULL`. -- `DEFAULT` specifies the default value. +- `PRIMARY KEY` -### MySQL + Specifies a column or set of columns as the primary key. -You can also use the `AUTO_INCREMENT` parameter. It indicates that the value of this column will be automatically increased when new records are added to the table. Each table has a maximum of one `AUTO_INCREMENT` column. It is worth noting that this parameter can only be applied to integer and floating-point types. +**MySQL** -For our table of users, you can specify the following parameters: +- `AUTO_INCREMENT` -```sql -CREATE TABLE Users ( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18 -); -``` + Indicates that the value of this column will be automatically increased when new records are added to the table. Each table has a maximum of one `AUTO_INCREMENT` column. + It is worth noting that this parameter can only be applied to integer and floating point types. -In this example: +**PostgreSQL** -- `id` is a numeric field that is the primary key with auto-increment. -- `name` is a string field with a maximum length of 255 characters and is required. -- `age` is a numeric field with a default value of 18. +- `SERIAL` or `GENERATED ALWAYS AS IDENTITY` -### PostgreSQL + Indicates that the value of this column will be automatically increased when new records are added to the table. `SERIAL` is a shorthand for creating an auto-incrementing field. -You can also use `SERIAL` or `GENERATED ALWAYS AS IDENTITY`. These constructions indicate that the value of this column will be automatically increased when new records are added to the table. `SERIAL` is a shorthand for creating an auto-incrementing field. +* `UNIQUE` -For our table of users, you can specify the following parameters: + Indicates that the values in this column for all records must be different from each other. -```sql -CREATE TABLE Users ( - id SERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18 -); -``` +* `NOT NULL` -In this example: + Indicates that the values in this column must be different from `NULL`. -- `id` is a `SERIAL` field (auto-incrementing integer) that is the primary key. -- `name` is a string field with a maximum length of 255 characters and is required. -- `age` is a numeric field with a default value of 18. +* `DEFAULT` -## CURRENT_TIMESTAMP as a default value + Specifies the default value. -`CURRENT_TIMESTAMP` is useful when you want the database to automatically store the row creation time. For example, it can be used together with the `TIMESTAMP` type. +**MySQL** + +This parameter does not apply to the `BLOB`, `TEXT`, `GEOMETRY` and `JSON` types. -### MySQL +For our table of users, you can specify the following parameters: + +**MySQL** ```sql CREATE TABLE Users ( id INTEGER PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + age INTEGER NOT NULL DEFAULT 18 ); ``` -### PostgreSQL +**PostgreSQL** ```sql CREATE TABLE Users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + age INTEGER NOT NULL DEFAULT 18 ); ``` -## Description of the table - -### MySQL +So, in this example: -To view the description of the created table, you can use the `DESCRIBE` statement. +**MySQL** -```sql -DESCRIBE Users; -``` - -### PostgreSQL +- `id` - a numeric field that is the primary key with auto-increment; -To view the description of the created table, you can use an SQL query to the information schema: - -```sql -SELECT column_name, data_type, is_nullable, column_default -FROM information_schema.columns -WHERE table_schema = current_schema() AND table_name = 'users'; -``` +**PostgreSQL** -## Additional table definition options +- `id` - a SERIAL type field (auto-incrementing integer), which is the primary key; -In addition to the column definitions, when creating a table you can specify additional table parameters. +* `name` - a string type field with a maximum length of 255 characters, which is mandatory; +* `age` - a numeric field with a default value of 18. -### MySQL +## CURRENT_TIMESTAMP as a default value -#### Primary key +`CURRENT_TIMESTAMP` is useful when you want the database to automatically store the row creation time. For example, it can be used together with the `TIMESTAMP` type. -If you did not define the primary key using column parameters, you can do it with table parameters by adding `PRIMARY KEY (, )` after the list of columns: +**MySQL** ```sql CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - PRIMARY KEY (id) -); -``` - -#### Foreign keys - -Suppose we want to store data about the company our users work for. Let's create a small table `Companies` in which we will store a unique identifier and the name of the company: - -```sql -CREATE TABLE Companies ( - id INTEGER, + id INTEGER PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, - PRIMARY KEY (id) + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` -Next, you need to add the `company` field to the `Users` table, the workplace of our user, which will refer to the record in the `Companies` table. The full query for creating the table will look like this: +**PostgreSQL** ```sql CREATE TABLE Users ( - id INTEGER, + id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id) + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` -A foreign key is used to ensure that the `company` column contains an identifier that exists in the `Companies` table when new entries are added to the `Users` table. It has the following syntax: +## Description of the table -```sql -FOREIGN KEY (, ) -REFERENCES (, ) -[ON DELETE reference_option] -[ON UPDATE reference_option] -``` +**MySQL** -The full query for creating a table with a foreign key will be as follows: +To view the description of the created table, you can use the operator `DESCRIBE`. ```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) -); +DESCRIBE Users; ``` -If you have foreign keys, you can determine the behavior of the current record when changing or deleting the record to which it refers: +| Field | Type | Null | Key | Default | Extra | +| ----- | ------------ | ---- | --- | ------- | -------------- | +| id | int | NO | PRI | NULL | auto_increment | +| name | varchar(255) | NO | | NULL | | +| age | int | NO | | 18 | | -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) - ON DELETE RESTRICT ON UPDATE CASCADE -); -``` +**PostgreSQL** -`ON DELETE RESTRICT` means that if you try to delete a company that has data in the `Users` table, the database will not let you do it: +To view the description of the created table, you can use an SQL query to the information schema: ```sql -Cannot delete or update a parent row: a foreign key constraint fails +SELECT column_name, data_type, is_nullable, column_default +FROM information_schema.columns +WHERE table_schema = current_schema() AND table_name = lower('Users'); ``` -If `ON DELETE CASCADE` was specified, then when deleting the company all users referring to this company would also be deleted. +| column_name | data_type | is_nullable | column_default | +| ----------- | ----------------- | ----------- | --------------------------------- | +| id | integer | NO | nextval('users_id_seq'::regclass) | +| name | character varying | NO | null | +| age | integer | NO | 18 | -There is one more option: `ON DELETE SET NULL`. When it is used, the database will write `NULL` as the value of the `company` field for all users who worked at the deleted company. - -`ON UPDATE CASCADE` means that if a company changes its identifier, then all users (`Users`) will receive the new identifier in the `company` field. - -### PostgreSQL - -#### Primary key +## Additional table definition options -If you did not define the primary key using column parameters, you can do it with table parameters by adding `PRIMARY KEY (, )` after the list of columns: +In addition to the description of the columns, when creating a table, you can additionally specify the following parameters: + +**MySQL** + +- Primary key. -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - PRIMARY KEY (id) -); -``` + If you have not defined the primary key using the column parameters, then you can do this using additional table parameters by adding the entry `PRIMARY KEY (, )` after enumerating the columns: -#### Foreign keys + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + PRIMARY KEY (id) + ); + ``` -Suppose we want to store data about the company our users work for. Let's create a small table `Companies` in which we will store a unique identifier and the name of the company: +**PostgreSQL** -```sql -CREATE TABLE Companies ( - id INTEGER, - name VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -); -``` +- Primary key. -Next, you need to add the `company` field to the `Users` table, the workplace of our user, which will refer to the record in the `Companies` table. The full query for creating the table will look like this: + If you have not defined the primary key using the column parameters, then you can do this using additional table parameters by adding the entry `PRIMARY KEY (, )` after enumerating the columns: -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id) -); -``` + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + PRIMARY KEY (id) + ); + ``` + +**MySQL** -A foreign key is used to ensure that the `company` column contains an identifier that exists in the `Companies` table when new entries are added to the `Users` table. It has the following syntax: +- Foreign keys. -```sql -FOREIGN KEY (, ) -REFERENCES (, ) -[ON DELETE reference_option] -[ON UPDATE reference_option] -``` + Suppose we want to store data about the company our users work for. Let's create a small table `Companies` in which we will store a unique identifier and the name of the company: -The full query for creating a table with a foreign key will be as follows: + ```sql + CREATE TABLE Companies ( + id INTEGER, + name VARCHAR(255) NOT NULL, + PRIMARY KEY (id) + ); + ``` -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) -); -``` + Next, you need to add the `company` field to the `Users` table – the place of work of our user, which will refer to the entry in the `Companies` table. The full query for creating a table will look like this: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id) + ); + ``` + + A foreign key is used to ensure that the company column contains an identifier that exists in the `Companies` table when new entries are added to the `Users` table. + It has the following syntax: + + ```sql + FOREIGN KEY (, ) + REFERENCES (, ) + [ON DELETE reference_option] + [ON UPDATE reference_option] + ``` + + The full query for creating a table with a foreign key will be as follows: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ); + ``` + + If you have foreign keys, you can determine the behavior of the current record when changing or deleting the record to which it refers. + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ON DELETE RESTRICT ON UPDATE CASCADE + ); + ``` + + `ON DELETE RESTRICT` means that if you try to delete a company that has data in the Users table, the database won't let you do this: + + ```sql + Cannot delete or update a parent row: a foreign key constraint fails + ``` + + If `ON DELETE CASCADE` was specified, then when deleting the company, all users would be deleted, referring to this company. + + There is one more option - `ON DELETE SET NULL`. When used, the database will write `NULL` as the value of the company field for all users who worked at the remote company. + + `ON UPDATE CASCADE` means that if a company changes its ID, then all Users will get a new ID in the company field. + +**PostgreSQL** + +- Foreign keys. + + Suppose we want to store data about the company our users work for. Let's create a small table `Companies` in which we will store a unique identifier and the name of the company: + + ```sql + CREATE TABLE Companies ( + id INTEGER, + name VARCHAR(255) NOT NULL, + PRIMARY KEY (id) + ); + ``` + + Next, you need to add the `company` field to the `Users` table – the place of work of our user, which will refer to the entry in the `Companies` table. The full query for creating a table will look like this: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id) + ); + ``` + + A foreign key is used to ensure that the company column contains an identifier that exists in the `Companies` table when new entries are added to the `Users` table. + It has the following syntax: + + ```sql + FOREIGN KEY (, ) + REFERENCES (, ) + [ON DELETE reference_option] + [ON UPDATE reference_option] + ``` + + The full query for creating a table with a foreign key will be as follows: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ); + ``` + + If you have foreign keys, you can determine the behavior of the current record when changing or deleting the record to which it refers. + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ON DELETE RESTRICT ON UPDATE CASCADE + ); + ``` + + `ON DELETE RESTRICT` means that if you try to delete a company that has data in the Users table, the database won't let you do this: + + ```sql + ERROR: update or delete on table "companies" violates foreign key constraint "users_company_fkey" on table "users" + DETAIL: Key (id)=(1) is still referenced from table "users". + ``` + + If `ON DELETE CASCADE` was specified, then when deleting the company, all users would be deleted, referring to this company. + + There is one more option - `ON DELETE SET NULL`. When used, the database will write `NULL` as the value of the company field for all users who worked at the remote company. -If you have foreign keys, you can determine the behavior of the current record when changing or deleting the record to which it refers: + `ON UPDATE CASCADE` means that if a company changes its ID, then all Users will get a new ID in the company field. -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) - ON DELETE RESTRICT ON UPDATE CASCADE -); -``` +## Deleting a table -`ON DELETE RESTRICT` means that if you try to delete a company that has data in the `Users` table, the database will not let you do it: +Deleting a table is done using the `DROP TABLE` operator. ```sql -ERROR: update or delete on table "companies" violates foreign key constraint "users_company_fkey" on table "users" -DETAIL: Key (id)=(1) is still referenced from table "users". +DROP TABLE [IF EXISTS] table_name; ``` -If `ON DELETE CASCADE` was specified, then when deleting the company all users referring to this company would also be deleted. - -There is one more option: `ON DELETE SET NULL`. When it is used, the database will write `NULL` as the value of the `company` field for all users who worked at the deleted company. - -`ON UPDATE CASCADE` means that if a company changes its identifier, then all users (`Users`) will receive the new identifier in the `company` field. - -## Deleting a table +## Interactive exercise -Deleting a table is done using the `DROP TABLE` statement. +Now that you've learned the basics of creating tables, try to reinforce the material with an interactive task: -```sql -DROP TABLE [IF EXISTS] table_name; -``` +The interactive demonstration is available [in the SQL Academy lesson](https://sql-academy.org/en/guide/create-table). diff --git a/course/module-6/datetime-data-type/article.md b/course/module-6/datetime-data-type/article.md index bbf56d0..7f78248 100644 --- a/course/module-6/datetime-data-type/article.md +++ b/course/module-6/datetime-data-type/article.md @@ -1,12 +1,12 @@ --- meta: - title: "Date and time in SQL: MySQL and PostgreSQL" - description: "Functions for working with dates and times in MySQL and PostgreSQL. DATE, TIME, DATETIME, TIMESTAMP data types and their differences." + title: "Date and time in SQL: MySQL and PostgreSQL" + description: "Functions for working with dates and times in MySQL and PostgreSQL. DATE, TIME, DATETIME, TIMESTAMP data types and their differences." --- # Date and Time data types - +**MySQL** MySQL has several data types for working with dates and times: `DATE`, `TIME`, `DATETIME` and `TIMESTAMP`. @@ -17,9 +17,7 @@ MySQL has several data types for working with dates and times: `DATE`, `TIME`, ` | `DATETIME` | Stores a date and time value as YYYY-MM-DD HH:MM:SS.
For example, 2022-12-05 10:37:22 | from 1000-01-01 00:00:00 to 9999-12-31 23:59:59 | 8 bytes | | `TIMESTAMP` | Stores a date and time value as YYYY-MM-DD HH:MM:SS.
For example, 2022-12-05 10:37:22 | from 1970-01-01 00:00:01 to 2038-01-19 03:14:07 | 4 bytes | -
- - +**PostgreSQL** PostgreSQL has several data types for working with dates and times: `DATE`, `TIME`, `TIMESTAMP`, `TIMESTAMPTZ` and `INTERVAL`. @@ -31,9 +29,7 @@ PostgreSQL has several data types for working with dates and times: `DATE`, `TIM | `TIMESTAMPTZ` | Stores date and time value with time zone.
For example, 2022-12-05 10:37:22+03 | from 4713 BC to 294276 AD | 8 bytes | | `INTERVAL` | Stores time intervals.
For example, 1 year 2 months 3 days 4 hours | from -178000000 years to 178000000 years | 16 bytes | -
- - +**MySQL** ## Difference between TIMESTAMP and DATETIME @@ -43,8 +39,8 @@ But there are a number of significant differences between them that determine wh ## DATETIME Stores values in the range 1000-01-01 00:00:00 to 9999-12-31 23:59:59 and occupies 8 bytes. -This data type does not depend on the time zone, installed in MySQL. It is always displayed exactly like this, in in which it was installed and in which it is stored in the database. -That is, at change the time zone, the time display will not change. +This data type does not depend on the time zone set in MySQL. It is always displayed exactly as it was entered and as it is stored in the database. +That is, changing the time zone will not change how the time is displayed. ```sql CREATE TABLE datetime_table (datetime_field DATETIME); @@ -54,11 +50,15 @@ SET @@session.time_zone="+03:00"; -- change timezone in MySQL SELECT * FROM datetime_table; ``` +| datetime_field | +| ------------------- | +| 2022-06-16 16:37:23 | + ## TIMESTAMP Stores how many seconds have passed since 1970-01-01 00:00:00 in the zero time zone and occupies 4 bytes. When making selections, it is displayed based on the current time zone. -The time zone can be set in the operating room settings. system where MySQL is running, in the global MySQL settings or in a specific session. +The time zone can be set in the operating system where MySQL is running, in the global MySQL settings, or in a specific session. In the database, when a `TIMESTAMP` record is created, the value is stored in the zero time zone. ```sql @@ -69,12 +69,14 @@ SET @@session.time_zone="+03:00"; -- change timezone in MySQL SELECT * FROM timestamp_table; ``` -It is also worth remembering that `TIMESTAMP` is essentially limited in the range of possible values from 1970-01-01 00:00:01 to 2038-01-19 03:14:07, -which limits its use. So, this data type is not suitable for storing users dates of birth. +| timestamp_field | +| ------------------- | +| 2022-06-16 19:37:23 | - +It is also worth remembering that `TIMESTAMP` is essentially limited in the range of possible values from 1970-01-01 00:00:01 to 2038-01-19 03:14:07, +which limits its use. So this data type is not suitable for storing users' dates of birth. - +**PostgreSQL** ## Difference between TIMESTAMP and TIMESTAMPTZ @@ -120,20 +122,18 @@ SELECT '2 weeks'::INTERVAL; SELECT '90 minutes'::INTERVAL; ``` - - ## Ways to set values - +**MySQL** The `DATETIME`, `DATE`, and `TIMESTAMP` values can be set in one of the following ways: - As a string in the format YYYY-MM-DD HH:MM:SS or in the format YY-MM-DD HH:MM:SS for date and time - As a string in YYYY-MM-DD format or in YY-MM-DD format to indicate dates only -When writing a date, you can use any punctuation mark in as a separator between parts of sections of a date or time. Also it is possible to set the date without a separator character at all, together. +When writing a date, you can use any punctuation mark as a separator between the parts of a date or time. You can also write the date with no separator at all, as one continuous string. -```sql-executable +```sql CREATE TABLE date_table (datetime TIMESTAMP); INSERT INTO date_table VALUES("2022-06-16 16:37:23"); INSERT INTO date_table VALUES("22.05.31 8+15+04"); @@ -143,9 +143,15 @@ INSERT INTO date_table VALUES("2021-02-12"); SELECT * FROM date_table; ``` - +| datetime | +| ------------------- | +| 2022-06-16 16:37:23 | +| 2022-05-31 08:15:04 | +| 2014-02-22 16:37:22 | +| 2022-06-16 16:37:23 | +| 2021-02-12 00:00:00 | - +**PostgreSQL** Date and time values can be set in various formats: @@ -154,7 +160,7 @@ Date and time values can be set in various formats: - Date only: 'YYYY-MM-DD' - Time only: 'HH:MM:SS' -```sql-executable +```sql CREATE TABLE date_table ( date_field DATE, time_field TIME, @@ -173,5 +179,3 @@ SELECT * FROM date_table; ``` PostgreSQL strictly follows the ISO 8601 standard and prefers to use standard date formats. - - diff --git a/course/module-6/indexes/article.md b/course/module-6/indexes/article.md index e65a811..6478fcb 100644 --- a/course/module-6/indexes/article.md +++ b/course/module-6/indexes/article.md @@ -1,7 +1,7 @@ --- meta: - title: "SQL Indexes: speeding up data search in MySQL and PostgreSQL" - description: "A comprehensive guide to SQL indexes, explaining how they simplify and speed up data search in database tables in MySQL and PostgreSQL. Learn how to create, manage, and optimize indexes to improve the performance of your queries." + title: "SQL Indexes: speeding up data search in MySQL and PostgreSQL" + description: "A comprehensive guide to SQL indexes, explaining how they simplify and speed up data search in database tables in MySQL and PostgreSQL. Learn how to create, manage, and optimize indexes to improve the performance of your queries." --- # SQL Indexes @@ -40,7 +40,7 @@ Returning to the `Users` table, you can add an index to the `email` column to speed up any queries that work with the value of this column. - +**MySQL** Here's how you can add such an index to a MySQL database: @@ -62,6 +62,11 @@ for a specific table, as shown in the example below: SHOW INDEX FROM Users; ``` +| Table | Non_unique | Key_name | Seq_in_index | Column_name | +| ----- | ---------- | --------- | ------------ | ----------- | +| users | 0 | PRIMARY | 1 | id | +| users | 1 | idx_email | 1 | email | + The output shows that there are 2 indexes in the `Users` table: one for the `id` column named `PRIMARY` and another for the `email` column that we just defined. @@ -72,9 +77,7 @@ This is a special type of index used with the primary key constraint, which ensu that each value in the column or group of columns designated as the table's primary key is unique and cannot be `NULL`. - - - +**PostgreSQL** Here's how you can add such an index to a PostgreSQL database: @@ -98,6 +101,11 @@ FROM pg_indexes WHERE tablename = 'users'; ``` +| indexname | indexdef | +| ---------- | --------------------------------------------------------------- | +| users_pkey | CREATE UNIQUE INDEX users_pkey ON public.users USING btree (id) | +| idx_email | CREATE INDEX idx_email ON public.users USING btree (email) | + PostgreSQL automatically creates an index for the primary key column, which in this case is `id`. This is a special type of index used with the primary key constraint, which ensures that each value in the column or group of columns designated as the table's primary key @@ -111,11 +119,9 @@ PostgreSQL supports various index types: - **GiST** — for geometric data and full-text search - **BRIN** — for very large tables with natural sorting - - ## Dropping an Index - +**MySQL** If after creating an index you decide that the index is no longer needed, you can remove it as follows: @@ -124,9 +130,7 @@ remove it as follows: DROP INDEX idx_email ON Users; ``` - - - +**PostgreSQL** If after creating an index you decide that the index is no longer needed, you can remove it as follows: @@ -135,8 +139,6 @@ remove it as follows: DROP INDEX idx_email; ``` - - ## Unique Indexes When designing databases, it's important to determine which columns can have duplicate values @@ -163,7 +165,7 @@ CREATE UNIQUE INDEX idx_email ON Users (email); ``` - +**MySQL** With the index present, you will receive an error message if you attempt to add a new customer with an already existing email address: @@ -171,9 +173,7 @@ With the index present, you will receive an error message if you attempt to add Error(1062) 23000: "Duplicate entry 'duplicate@gmail.com' for key 'users.idx_email'" ``` - - - +**PostgreSQL** With the index present, you will receive an error message if you attempt to add a new customer with an already existing email address: @@ -182,8 +182,6 @@ ERROR: duplicate key value violates unique constraint "idx_email" DETAIL: Key (email)=(duplicate@gmail.com) already exists. ``` - - Creating unique indexes for the column or columns defined as the primary key is redundant, as the database management system automatically ensures the uniqueness of the primary key values. However, placing several unique indexes in one table is permissible and may be sensible @@ -217,7 +215,7 @@ Indexes are often used by the database server for efficiently finding the necess and then for retrieving additional data from related tables upon user request. Take, for example, the query: -```sql-executable-Schedule +```sql SELECT id, first_name, last_name FROM Student WHERE first_name LIKE 'A%' AND last_name LIKE 'L%' @@ -232,7 +230,7 @@ In response to such a query, the server can choose one of several approaches: The last method appears to be the most efficient, as it allows all necessary rows to be found in one pass, avoiding revisiting the table. - +**MySQL** But how to determine which method the MySQL query optimizer will choose? This can be done using the `EXPLAIN` command, which shows how the server plans @@ -246,13 +244,15 @@ EXPLAIN AND last_name LIKE 'L%'; ``` +| id | select_type | table | partitions | possible_keys | key | +| --- | ----------- | ------- | ---------- | --------------------------- | ------------- | +| 1 | SIMPLE | Student | null | idx_full_name,idx_last_name | idx_full_name | + Analyzing the results, it can be seen that the `possible_keys` column lists potentially applicable indexes `idx_last_name` or `idx_full_name`, and the `key` column indicates that the `idx_full_name` index was chosen. - - - +**PostgreSQL** But how to determine which method the PostgreSQL query optimizer will choose? This can be done using the `EXPLAIN` command, which shows how the database plans @@ -266,6 +266,12 @@ EXPLAIN AND last_name LIKE 'L%'; ``` +| QUERY PLAN | +| --------------------------------------------------------------------------- | +| Index Scan using idx_full_name on student (cost=0.42..8.44 rows=1 width=68) | +| Index Cond: ((last_name >= 'L'::text) AND (last_name \< 'M'::text)) | +| Filter: ((first_name \~\~ 'A%'::text) AND (last_name \~\~ 'L%'::text)) | + You can also use `EXPLAIN ANALYZE` to get real execution statistics: ```sql @@ -276,11 +282,17 @@ EXPLAIN ANALYZE AND last_name LIKE 'L%'; ``` +| QUERY PLAN | +| --------------------------------------------------------------------------------------------------------------------- | +| Index Scan using idx_full_name on student (cost=0.42..8.44 rows=1 width=68) (actual time=0.025..0.027 rows=1 loops=1) | +| Index Cond: ((last_name >= 'L'::text) AND (last_name \< 'M'::text)) | +| Filter: ((first_name \~\~ 'A%'::text) AND (last_name \~\~ 'L%'::text)) | +| Planning Time: 0.156 ms | +| Execution Time: 0.048 ms | + Analyzing the `EXPLAIN` results, you can see which access method the optimizer chose — full table scan (Seq Scan) or index scan (Index Scan). - - ## The Flip Side of Indexes If indexes are so effective, one might ask: why not just index everything? 🧐 @@ -307,3 +319,11 @@ as necessary. **Let's check how well we've understood the topic:** Which statement best explains why you should not index every column in a database table? + +1. Indexes increase the speed of all operations in the database, including inserting, updating, and deleting data. — While indexes can indeed speed up read query executions, they can slow down insert, update, and delete operations, as they require additional updates to the index structures. + +2. Indexes do not require additional disk space and therefore can be created without any drawbacks. — Indexes take up additional disk space, which is one of the reasons why not every column should be indiscriminately indexed. + +3. Indexes reduce the need for query optimization, as they automatically optimize all queries. — Although indexes can significantly improve the performance of some queries, they do not replace the need for careful query optimization and database schema design. + +4. **Correct answer:** Indexes speed up read operations but can slow down write operations, as each index needs to be updated when data changes. — This statement accurately reflects the trade-off associated with using indexes. They indeed speed up reading at the expense of potentially slowing down write operations, making it important to balance the number of indexes and their impact on the overall system performance. diff --git a/course/module-6/number-data-type/article.md b/course/module-6/number-data-type/article.md index eb0d783..060756b 100644 --- a/course/module-6/number-data-type/article.md +++ b/course/module-6/number-data-type/article.md @@ -1,27 +1,27 @@ --- meta: - title: "Numeric data type in SQL: MySQL and PostgreSQL" - description: "Working with numbers in MySQL and PostgreSQL. Basic numeric data types: INTEGER, DECIMAL, FLOAT and others." + title: "Numeric data type in SQL: MySQL and PostgreSQL" + description: "Working with numbers in MySQL and PostgreSQL. Basic numeric data types: INTEGER, DECIMAL, FLOAT and others." --- # Numeric data type Numerical data are divided into exact and approximate, integer and real. Bit values are a separate category. - +**MySQL** ## Exact integers | Type | Memory size | Range | | :-------------------------------------- | :---------- | :------------------------------------------------------------------------------------------------------------------ | | `TINYINT` | 1 byte | from -128 to 127 (from -27 to 27-1)
from 0 to 255 (from 0 to 28-1) | -| `SMALLINT` | 2 byte | from -32768 to 32767 (from -215 to 215-1)
from 0 to 65535 (from 0 to 216-1) | -| `MEDIUMINT` | 3 byte | from -223 to 223-1
from 0 to 224-1 | -| `INT`
`INTEGER`
(aliases) | 4 byte | from -231 to 231-1
from 0 to 232-1 | -| `BIGINT` | 8 byte | from -263 to 263-1
from 0 to 264-1 | +| `SMALLINT` | 2 bytes | from -32768 to 32767 (from -215 to 215-1)
from 0 to 65535 (from 0 to 216-1) | +| `MEDIUMINT` | 3 bytes | from -223 to 223-1
from 0 to 224-1 | +| `INT`
`INTEGER`
(aliases) | 4 bytes | from -231 to 231-1
from 0 to 232-1 | +| `BIGINT` | 8 bytes | from -263 to 263-1
from 0 to 264-1 | -Integers can be declared with the keyword `UNSIGNED`. In this case, the elements of this column it will not be possible to assign negative values, and the valid range, -which takes on the type doubles. So, type `TINYINT` can take values from -128 to 127, and `TINYINT UNSIGNED` — from 0 to 255. +Integers can be declared with the `UNSIGNED` keyword. In that case the column can no longer hold negative values, and its valid range doubles. +So `TINYINT` accepts values from -128 to 127, while `TINYINT UNSIGNED` accepts values from 0 to 255. ## Exact real numbers @@ -29,7 +29,7 @@ which takes on the type doubles. So, type `TINYINT` can take values from -128 to | :---------------------------------------------------- | :---------------------------- | | `DEC[(M,D)]`
`DECIMAL[(M,D)]`
(aliases) | Depends on M and D parameters | -Type `DECIMAL` stores exact real values data. It is used when accuracy is critical. For example, when storing financial data. +The `DECIMAL` type stores exact real numbers. It is used when accuracy is critical — for example, when storing financial data. Usage example: @@ -40,40 +40,37 @@ CREATE TABLE Users ( ); ``` -This example declares that the `salary` column will store numbers, having a maximum of 5 digits, 2 of which are reserved for decimal part. -That is, this column will store values in the range from -999.99 to 999.99. +This example declares that the `salary` column stores numbers with a maximum of 5 digits, 2 of which are reserved for the decimal part. +So the column holds values in the range from -999.99 to 999.99. -The syntax `DECIMAL` is equivalent to `DECIMAL(M)` and `DECIMAL(M,0)`. By default, the parameter `M` is 10. +The `DECIMAL` syntax is equivalent to `DECIMAL(M)` and `DECIMAL(M,0)`. By default, the `M` parameter is 10. -The whole part and the part after the point are stored as 2 separate integers. On Based on this fact, -the amount of memory consumed can be easily calculated. So for `DECIMAL(5,2)` the integer part contains -3 digits and takes 2 byte, part after the point have 2 digits - 1 byte is enough. Total for storage will be spent 3 byte. +The integer part and the fractional part are stored as two separate integers, which makes the memory footprint easy to calculate. +For `DECIMAL(5,2)`, the integer part has 3 digits and takes 2 bytes, while the fractional part has 2 digits and needs just 1 byte — 3 bytes in total. ## Bit numbers -| Type | Memory size | Range | -| :--------------------------------------- | :---------- | :------------------------------------------ | -| `BIT[(M)]` | M bit | From 1 to 64 bit, depend on the M parameter | -| `BOOL`
`BOOLEAN`
(aliases) | 1 bit | Or 0, or 1 | +| Type | Memory size | Range | +| :--------------------------------------- | :---------- | :---------------------------------------------- | +| `BIT[(M)]` | M bit | From 1 to 64 bits, depending on the M parameter | +| `BOOL`
`BOOLEAN`
(aliases) | 1 bit | Either 0 or 1 | -Type `BIT(M)` stores a sequence of bits a given length. By default, the length is 8 bit. -If assigned the value in a column of this type uses less than M bit, then zeros are padded on the left. -For example, when trying to write the value `b'101'` to `BIT(6)` will eventually be stored `b'000101'`. +The `BIT(M)` type stores a bit sequence of a given length. By default, the length is 8 bits. +If the value assigned to such a column uses fewer than M bits, it is padded with zeros on the left. +For example, writing `b'101'` to a `BIT(6)` column ends up stored as `b'000101'`. ## Approximate numbers | Type | Memory size | Range | | :------------------------------------------------------ | :---------- | :-------------------------------------------------------------------------------- | -| `FLOAT[(M, D)]` | 4 byte | Minimum value ±1.17·10-39
Maximum value ±3.4·1038 | -| `REAL[(M, D)]`
`DOUBLE[(M, D)]`
(aliases) | 8 byte | Minimum value ±2.22·10-308
Maximum value ±1.79·10308 | +| `FLOAT[(M, D)]` | 4 bytes | Minimum value ±1.17·10-39
Maximum value ±3.4·1038 | +| `REAL[(M, D)]`
`DOUBLE[(M, D)]`
(aliases) | 8 bytes | Minimum value ±2.22·10-308
Maximum value ±1.79·10308 | -Numeric floating point data types can also have a parameter `UNSIGNED`. -As with integer types, this attribute prevents negative storage in the marked column values, but, -unlike integer types, the maximum interval for column values remains the same. +Floating-point numeric types can also take the `UNSIGNED` attribute. +As with integer types, it prevents negative values in the column, but — unlike integer types — +the maximum range of column values stays the same. -
- - +**PostgreSQL** ## Integer numbers @@ -99,7 +96,7 @@ The `SERIAL` types are pseudo-types for creating auto-incrementing columns. `SER | :---------------------------------------------------------------------------------- | :----------- | :-------------------------------------------------------------------- | | `DECIMAL[(precision, scale)]`
`NUMERIC[(precision, scale)]`
(aliases) | User-defined | Up to 131072 digits before decimal point and up to 16383 digits after | -Type `NUMERIC` stores exact real values data. It is used when accuracy is critical. For example, when storing financial data. +The `NUMERIC` type stores exact real numbers. It is used when accuracy is critical — for example, when storing financial data. Usage example: @@ -110,8 +107,8 @@ CREATE TABLE Users ( ); ``` -This example declares that the `salary` column will store numbers having a maximum of 10 digits, 2 of which are reserved for the decimal part. -That is, this column will store values in the range from -99999999.99 to 99999999.99. +This example declares that the `salary` column stores numbers with a maximum of 10 digits, 2 of which are reserved for the decimal part. +So the column holds values in the range from -99999999.99 to 99999999.99. ## Approximate numbers @@ -121,5 +118,3 @@ That is, this column will store values in the range from -99999999.99 to 9999999 | `DOUBLE PRECISION` | 8 bytes | 15 digits | from 1E-307 to 1E+308 | Floating point types are used for approximate calculations. PostgreSQL also supports special values: `Infinity`, `-Infinity` and `NaN` (not a number). - -
diff --git a/course/module-6/string-data-type/article.md b/course/module-6/string-data-type/article.md index 5cb2d03..4839697 100644 --- a/course/module-6/string-data-type/article.md +++ b/course/module-6/string-data-type/article.md @@ -1,14 +1,14 @@ --- meta: - title: "String data type in SQL: MySQL and PostgreSQL" - description: "Working with strings in MySQL and PostgreSQL. Basic data types for text information." + title: "String data type in SQL: MySQL and PostgreSQL" + description: "Working with strings in MySQL and PostgreSQL. Basic data types for text information." --- # String data type The string data type is the most commonly used data type. Thanks to this, both text and various binary data (for example, pictures) are stored in the database. - +**MySQL** In MySQL, it is represented by the following types: @@ -50,9 +50,7 @@ The difference between them is that the sorts and comparisons of stored data for | `MEDIUMTEXT` | Maximum length 16,777,215 | | `LONGTEXT` | Maximum length 4,294,967,295 | - - - +**PostgreSQL** In PostgreSQL, it is represented by the following types: @@ -65,5 +63,3 @@ In PostgreSQL, it is represented by the following types: | `TEXT` | Contains text strings of unlimited variable length. | Practically unlimited length (up to 1 GB) | It's important to note that in PostgreSQL, the `TEXT` type is preferable to use instead of `VARCHAR` without length limitation, as they have the same performance. - - diff --git a/course/module-6/table-data-type/article.md b/course/module-6/table-data-type/article.md index 2ddd5e1..61b5894 100644 --- a/course/module-6/table-data-type/article.md +++ b/course/module-6/table-data-type/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Data types for table columns' - description: 'Data types for table columns in SQL' + title: "Data types for table columns" + description: "Data types for table columns in SQL" --- # Data types for table columns diff --git a/course/module-6/view/article.md b/course/module-6/view/article.md index 64899f8..b94724e 100644 --- a/course/module-6/view/article.md +++ b/course/module-6/view/article.md @@ -1,7 +1,7 @@ --- meta: - title: "VIEW in SQL: MySQL and PostgreSQL" - description: "Syntax for creating views in MySQL and PostgreSQL, description of how views work and why they are needed." + title: "VIEW in SQL: MySQL and PostgreSQL" + description: "Syntax for creating views in MySQL and PostgreSQL, description of how views work and why they are needed." --- # Views @@ -30,7 +30,7 @@ that uses this table. Views do not cache query results during operation. As a simple example, suppose you want to partially hide email addresses in the user table (`Users`). - +Airbnb database ER diagram: [open on SQL Academy](https://sql-academy.org/en/guide/view). This can be useful, for example, if your company's policy does not allow everyone to use confidential user information. @@ -38,7 +38,7 @@ Therefore, instead of allowing direct access to the user table (`Users`), you de a view named `ViewUsers` and require everyone to use it to access user data. - +**MySQL** Here is an example of defining this view: @@ -50,9 +50,7 @@ CREATE VIEW ViewUsers AS FROM Users; ``` - - - +**PostgreSQL** Here is an example of defining this view: @@ -64,15 +62,49 @@ CREATE VIEW ViewUsers AS FROM Users; ``` - - The view in an SQL query appears and is used like a regular table. ```sql SELECT * FROM ViewUsers; ``` - +| id | name | email | +| --- | -------------------- | -------------- | +| 1 | Bruce Willis | ba\*\*\*\*.com | +| 2 | George Clooney | te\*\*\*\*.com | +| 3 | Kevin Costner | me\*\*\*\*.com | +| 4 | Donald Sutherland | ra\*\*\*\*.net | +| 5 | Jennifer Lopez | ba\*\*\*\*.com | +| 6 | Ray Liotta | jd\*\*\*\*.net | +| 7 | Samuel L. Jackson | mo\*\*\*\*.com | +| 8 | Nikole Kidman | ok\*\*\*\*.com | +| 9 | Alan Rickman | ka\*\*\*\*.net | +| 10 | Kurt Russell | ga\*\*\*\*.com | +| 11 | Harrison Ford | ko\*\*\*\*.com | +| 12 | Russell Crowe | gl\*\*\*\*.net | +| 13 | Steve Martin | ne\*\*\*\*.com | +| 14 | Michael Caine | dm\*\*\*\*.com | +| 15 | Angelina Jolie | ch\*\*\*\*.net | +| 16 | Mel Gibson | ro\*\*\*\*o.ca | +| 17 | Michael Douglas | ti\*\*\*\*.com | +| 18 | John Travolta | wa\*\*\*\*.com | +| 19 | Sylvester Stallone | ko\*\*\*\*.com | +| 20 | Tommy Lee Jones | sz\*\*\*\*.com | +| 21 | Catherine Zeta-Jones | fl\*\*\*\*.com | +| 22 | Antonio Banderas | sa\*\*\*\*.net | +| 23 | Kim Basinger | ja\*\*\*\*.net | +| 24 | Sam Neill | cl\*\*\*\*.com | +| 25 | Hideo Kojima | ad\*\*\*\*.org | +| 26 | ClINT Eastwood | fr\*\*\*\*.net | +| 27 | Brad Pitt | ke\*\*\*\*.net | +| 28 | Johnny Depp | cg\*\*\*\*o.ca | +| 29 | Pierce Brosnan | tr\*\*\*\*.com | +| 30 | Sean Connery | js\*\*\*\*.com | +| 31 | Bruce Willis | ke\*\*\*\*.com | +| 32 | Mullah Omar | jg\*\*\*\*.com | +| 33 | Vasanta Roberta | ro\*\*\*\*.com | + +**MySQL** If you want to find out which columns are available in the view, you can use the `DESCRIBE` statement. @@ -80,9 +112,13 @@ If you want to find out which columns are available in the view, you can use the DESCRIBE ViewUsers; ``` - +| Field | Type | Null | Key | Default | Extra | +| ----- | ----------- | ---- | --- | ------- | ----- | +| id | int | NO | | \ | | +| name | varchar(32) | NO | | \ | | +| email | varchar(38) | YES | | \ | | - +**PostgreSQL** If you want to find out which columns are available in the view, you can use a query to `information_schema`: @@ -92,11 +128,9 @@ FROM information_schema.columns WHERE table_name = 'viewusers'; ``` - - ## General syntax of a view - +**MySQL** ```sql CREATE [OR REPLACE] @@ -108,9 +142,7 @@ AS select_expression name already exists, the old view will be deleted and a new one will be created. Otherwise, if you try to create a view with an existing name, an error will occur. - - - +**PostgreSQL** ```sql CREATE [OR REPLACE] VIEW view_name [(view_column_names)] @@ -121,8 +153,6 @@ AS select_expression name already exists, the old view will be deleted and a new one will be created. Otherwise, if you try to create a view with an existing name, an error will occur. - - ## Why are views needed ### Simplifying complex queries @@ -132,21 +162,17 @@ They can hide the complexity of data structures and provide a simplified interfa ### Improving performance - +**MySQL** Creating views that encapsulate complex queries can help optimize the execution of these queries. This can lead to faster query execution and overall improvement in database performance. - - - +**PostgreSQL** Creating views that encapsulate complex queries can help optimize the execution of these queries. PostgreSQL supports materialized views (`MATERIALIZED VIEW`) that physically store query results and are periodically updated, which can significantly improve performance for complex queries. - - ### Ensuring security Views can be used to ensure the security of confidential data. @@ -159,3 +185,11 @@ This helps ensure that only authorized users have access to confidential data. Views are an important tool in SQL that allows for simplifying complex queries, standardizing data access, improving performance, and ensuring data security Let's check how well you understood the topic: choose the correct statement for the question "What is a view in a database?" + +1. **Correct answer:** A virtual table that does not store data but retrieves it from other tables when accessed. — A view in a database is indeed a virtual table that does not store data itself but retrieves it from other tables when accessed. + +2. A physical table that permanently stores data. — No, a view is not a physical table that permanently stores data. It is a virtual table that retrieves data from other tables when accessed. Views do not store data on their own but provide access to data already stored in other tables. + +3. An interface for direct user access to the database. — No, a view is not an interface for direct user access to the database. It hides implementation details and provides a simplified interface for data access. Users interact with the view, not the database directly. + +4. A temporary table used for data manipulation. — No, a view is not a temporary table used for data manipulation. It is a virtual table that retrieves data from other tables when accessed. Views are not used for modifying data but for providing convenient access to it. diff --git a/interviewQuestions/1/en.mdx b/interviewQuestions/1/en.mdx index 6db8590..845f978 100644 --- a/interviewQuestions/1/en.mdx +++ b/interviewQuestions/1/en.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'What is SQL and What is it Used For?' - description: 'SQL is a language for working with relational databases that allows creating tables, managing data, and performing key operations with it.' + title: "What is SQL and What is it Used For?" + description: "SQL is a language for working with relational databases that allows creating tables, managing data, and performing key operations with it." --- > SQL (Structured Query Language) is the standard language for interacting with relational databases. > It is used to define, manage, and retrieve data from databases. > With SQL, you can perform the following operations: -- Create new databases and tables. -- Insert new data into tables. -- Read data using queries. -- Update existing data. -- Delete data. -- Manage access and permissions. +- Create new databases and tables. +- Insert new data into tables. +- Read data using queries. +- Update existing data. +- Delete data. +- Manage access and permissions. diff --git a/interviewQuestions/10/en.mdx b/interviewQuestions/10/en.mdx index bfc437c..a727255 100644 --- a/interviewQuestions/10/en.mdx +++ b/interviewQuestions/10/en.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'What are the key differences between DELETE and TRUNCATE?' - description: 'DELETE removes individual records with a WHERE condition, while TRUNCATE removes all records from a table with no possibility of recovery. Learn the key differences between these commands.' + title: "What are the key differences between DELETE and TRUNCATE?" + description: "DELETE removes individual records with a WHERE condition, while TRUNCATE removes all records from a table with no possibility of recovery. Learn the key differences between these commands." --- ## DELETE: -- Removes selected records from a table. -- A `WHERE` condition can be used to delete specific records. -- The operation is logged row by row in the transaction log. -- `ON DELETE` triggers are activated. -- Slower compared to `TRUNCATE`. +- Removes selected records from a table. +- A `WHERE` condition can be used to delete specific records. +- The operation is logged row by row in the transaction log. +- `ON DELETE` triggers are activated. +- Slower compared to `TRUNCATE`. Example: @@ -20,14 +20,16 @@ DELETE FROM employees WHERE salary < 30000; ## TRUNCATE: -- Removes all records from a table with no possibility of recovery via `ROLLBACK` (in most DBMS). -- Cannot use `WHERE`. -- Faster since it is not logged row by row. -- Resets identity values (if auto-increment is used). -- Triggers are not activated. +- Removes all records from a table with no possibility of recovery via `ROLLBACK` (in most DBMS). +- Cannot use `WHERE`. +- Faster since it is not logged row by row. +- Resets identity values (if auto-increment is used). +- Triggers are not activated. Example: ```sql TRUNCATE TABLE employees; ``` + +For a deeper dive with examples, see the article [“TRUNCATE vs DELETE vs DROP: The Difference”](https://sql-academy.org/en/blog/sql-truncate-delete-drop). diff --git a/interviewQuestions/11/en.mdx b/interviewQuestions/11/en.mdx index 9ffe2d8..0683256 100644 --- a/interviewQuestions/11/en.mdx +++ b/interviewQuestions/11/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'What is a transaction and what are the ACID properties of a transaction?' - description: 'A transaction in SQL is a sequence of operations that has ACID properties: atomicity, consistency, isolation, and durability. Learn their significance.' + title: "What is a transaction and what are the ACID properties of a transaction?" + description: "A transaction in SQL is a sequence of operations that has ACID properties: atomicity, consistency, isolation, and durability. Learn their significance." --- > **A Transaction** is a sequence of operations performed as a single logical unit, which must be fully completed or fully rolled back. @@ -10,20 +10,22 @@ meta: **Atomicity:** -- A transaction is fully completed or not executed at all. -- If a failure occurs, all changes are rolled back. +- A transaction is fully completed or not executed at all. +- If a failure occurs, all changes are rolled back. **Consistency:** -- A transaction transitions the database from one consistent state to another. -- All database rules and constraints are maintained. +- A transaction transitions the database from one consistent state to another. +- All database rules and constraints are maintained. **Isolation:** -- The results of a transaction are invisible to other transactions until it is completed. -- Prevents interference between concurrent transactions. +- The results of a transaction are invisible to other transactions until it is completed. +- Prevents interference between concurrent transactions. **Durability:** -- Once a transaction is successfully completed, its results are permanently saved, even in the event of system failures. -- Changes are written to persistent storage. +- Once a transaction is successfully completed, its results are permanently saved, even in the event of system failures. +- Changes are written to persistent storage. + +For a deeper dive with examples, see the article [“What Is ACID: The 4 Transaction Properties Explained”](https://sql-academy.org/en/blog/sql-acid). diff --git a/interviewQuestions/12/en.mdx b/interviewQuestions/12/en.mdx index 98a91e5..09bc451 100644 --- a/interviewQuestions/12/en.mdx +++ b/interviewQuestions/12/en.mdx @@ -1,22 +1,22 @@ --- meta: - title: 'What are triggers in SQL?' - description: 'Triggers in SQL are procedures that are automatically executed during INSERT, UPDATE, or DELETE operations. Learn about types of triggers and their use in databases.' + title: "What are triggers in SQL?" + description: "Triggers in SQL are procedures that are automatically executed during INSERT, UPDATE, or DELETE operations. Learn about types of triggers and their use in databases." --- > **A Trigger** r is a stored procedure that is automatically executed when a specific event occurs in the database, such as an `INSERT`, `UPDATE`, or `DELETE` on a particular table. ## Types of Triggers: -- DML Triggers: Respond to `INSERT`, `UPDATE`, or `DELETE` operations. -- DDL Triggers: Respond to `CREATE`, `ALTER`, or `DROP` operations. -- Row-level or Statement-level Triggers. +- DML Triggers: Respond to `INSERT`, `UPDATE`, or `DELETE` operations. +- DDL Triggers: Respond to `CREATE`, `ALTER`, or `DROP` operations. +- Row-level or Statement-level Triggers. ## Advantages of triggers: -- Automates checks and constraints. -- Logs changes. -- Maintains data integrity. +- Automates checks and constraints. +- Logs changes. +- Maintains data integrity. ## Example of creating a trigger: diff --git a/interviewQuestions/13/en.mdx b/interviewQuestions/13/en.mdx index 4c8abb9..2ef9bb1 100644 --- a/interviewQuestions/13/en.mdx +++ b/interviewQuestions/13/en.mdx @@ -1,17 +1,17 @@ --- meta: - title: 'Explain what a VIEW is and its benefits' - description: 'A VIEW in SQL is a virtual table based on a query. Learn how views simplify queries, enhance security, and support data integrity.' + title: "Explain what a VIEW is and its benefits" + description: "A VIEW in SQL is a virtual table based on a query. Learn how views simplify queries, enhance security, and support data integrity." --- > **A VIEW** is a virtual table based on the result of an SQL query. A view does not store data itself but provides a specific way to view data from one or more tables. ## Benefits of a VIEW: -- **Simplifies complex queries**: Allows saving a complex query and using it as a simple table. -- **Security**: Grants users access only to specific data, hiding the rest. -- **Updatability**: In some cases, data can be updated through the view. -- **Maintains data integrity**: Can combine data from multiple tables in a specific way. +- **Simplifies complex queries**: Allows saving a complex query and using it as a simple table. +- **Security**: Grants users access only to specific data, hiding the rest. +- **Updatability**: In some cases, data can be updated through the view. +- **Maintains data integrity**: Can combine data from multiple tables in a specific way. ## Example of creating a VIEW: diff --git a/interviewQuestions/14/en.mdx b/interviewQuestions/14/en.mdx index 931d4a7..606bd2b 100644 --- a/interviewQuestions/14/en.mdx +++ b/interviewQuestions/14/en.mdx @@ -1,13 +1,13 @@ --- meta: - title: 'How to use the LIKE operator and what is it used for?' - description: 'The LIKE operator in SQL is used to search for strings based on a pattern using the symbols % and _. Learn how to apply LIKE for filtering data.' + title: "How to use the LIKE operator and what is it used for?" + description: "The LIKE operator in SQL is used to search for strings based on a pattern using the symbols % and _. Learn how to apply LIKE for filtering data." --- The `LIKE` operator is used in `WHERE` clauses to search for rows that match a specific pattern. Wildcards are used in the patterns: -- `%` — matches any sequence of characters (including an empty sequence). -- `_` — matches any single character. +- `%` — matches any sequence of characters (including an empty sequence). +- `_` — matches any single character. ## Examples of usage: diff --git a/interviewQuestions/15/en.mdx b/interviewQuestions/15/en.mdx index 5ca6d8e..74a2ab3 100644 --- a/interviewQuestions/15/en.mdx +++ b/interviewQuestions/15/en.mdx @@ -1,18 +1,18 @@ --- meta: - title: 'What are aggregate functions? Provide examples' - description: 'Aggregate functions in SQL compute values for a set of rows. Learn how to use COUNT, SUM, AVG, MAX, and MIN for data analysis.' + title: "What are aggregate functions? Provide examples" + description: "Aggregate functions in SQL compute values for a set of rows. Learn how to use COUNT, SUM, AVG, MAX, and MIN for data analysis." --- Aggregate functions perform calculations on a set of values and return a single value. They are often used in combination with the `GROUP BY` clause. ## Key Aggregate Functions -- `COUNT()` — counts the number of rows. -- `SUM()` — calculates the sum of values. -- `AVG()` — calculates the average value. -- `MAX()` — finds the maximum value. -- `MIN()` — finds the minimum value. +- `COUNT()` — counts the number of rows. +- `SUM()` — calculates the sum of values. +- `AVG()` — calculates the average value. +- `MAX()` — finds the maximum value. +- `MIN()` — finds the minimum value. ## Examples of usage diff --git a/interviewQuestions/16/en.mdx b/interviewQuestions/16/en.mdx index 39ad381..1ce90da 100644 --- a/interviewQuestions/16/en.mdx +++ b/interviewQuestions/16/en.mdx @@ -1,13 +1,13 @@ --- meta: - title: 'Explain the difference between UNION and UNION ALL' - description: 'UNION in SQL combines query results while removing duplicates, UNION ALL retains duplicates and performs faster. Learn the key differences.' + title: "Explain the difference between UNION and UNION ALL" + description: "UNION in SQL combines query results while removing duplicates, UNION ALL retains duplicates and performs faster. Learn the key differences." --- ## UNION: -- Combines the results of two or more `SELECT` queries. -- Removes duplicates from the combined result. +- Combines the results of two or more `SELECT` queries. +- Removes duplicates from the combined result. Syntax @@ -19,9 +19,9 @@ SELECT column_list FROM table2; ## UNION ALL: -- Combines the results of two or more SELECT queries. -- Retains duplicates in the combined result. -- Performs faster as it doesn’t perform the additional operation of removing duplicates. +- Combines the results of two or more SELECT queries. +- Retains duplicates in the combined result. +- Performs faster as it doesn’t perform the additional operation of removing duplicates. Syntax diff --git a/interviewQuestions/17/en.mdx b/interviewQuestions/17/en.mdx index 5d21208..8036ba3 100644 --- a/interviewQuestions/17/en.mdx +++ b/interviewQuestions/17/en.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'What is a stored procedure and how does it differ from a function?' - description: 'A stored procedure executes a set of commands in SQL, while a function returns a value and can be used in queries. Learn the key differences between them.' + title: "What is a stored procedure and how does it differ from a function?" + description: "A stored procedure executes a set of commands in SQL, while a function returns a value and can be used in queries. Learn the key differences between them." --- ## Stored Procedure: -- A set of SQL commands stored on the server for reuse. -- Can perform `SELECT`, `INSERT`, `UPDATE`, `DELETE` operations. -- May return multiple result sets or return nothing. -- Can have input and output parameters. -- Cannot be called within an SQL query. +- A set of SQL commands stored on the server for reuse. +- Can perform `SELECT`, `INSERT`, `UPDATE`, `DELETE` operations. +- May return multiple result sets or return nothing. +- Can have input and output parameters. +- Cannot be called within an SQL query. Example of a stored procedure: @@ -29,10 +29,10 @@ CALL GetEmployeeByID(1); ## Function: -- Returns a single value (scalar function) or a table (table-valued function). -- Can be used in SQL expressions (e.g., in SELECT or WHERE clauses). -- Must return a value. -- Typically used for calculations and returns a deterministic result. +- Returns a single value (scalar function) or a table (table-valued function). +- Can be used in SQL expressions (e.g., in SELECT or WHERE clauses). +- Must return a value. +- Typically used for calculations and returns a deterministic result. Example of a function: diff --git a/interviewQuestions/18/en.mdx b/interviewQuestions/18/en.mdx index 68319bc..98f6605 100644 --- a/interviewQuestions/18/en.mdx +++ b/interviewQuestions/18/en.mdx @@ -1,36 +1,38 @@ --- meta: - title: 'How to optimize SQL query performance?' - description: 'SQL query optimization includes using indexes, avoiding SELECT *, optimizing JOIN and WHERE conditions, limiting results, and analyzing query execution plans.' + title: "How to optimize SQL query performance?" + description: "SQL query optimization includes using indexes, avoiding SELECT *, optimizing JOIN and WHERE conditions, limiting results, and analyzing query execution plans." --- **Use Indexes:** -- Create indexes on columns frequently used in `WHERE`, `JOIN`, and `ORDER BY` clauses. -- Avoid redundant indexes. +- Create indexes on columns frequently used in `WHERE`, `JOIN`, and `ORDER BY` clauses. +- Avoid redundant indexes. **Avoid `SELECT *`:** -- Select only the necessary columns. -- Reduces the amount of data transferred. +- Select only the necessary columns. +- Reduces the amount of data transferred. **Optimize `JOIN` and `WHERE` Conditions:** -- Use equality (=) instead of inequality where possible. -- Avoid functions and calculations on indexed columns in conditions. +- Use equality (=) instead of inequality where possible. +- Avoid functions and calculations on indexed columns in conditions. **Use Result Limits (`LIMIT`):** -- Limit the number of returned rows if you don’t need all the data. +- Limit the number of returned rows if you don’t need all the data. **Avoid Subqueries Where Joins Are Possible::** -- Replace correlated subqueries with `JOIN` or `EXISTS`. +- Replace correlated subqueries with `JOIN` or `EXISTS`. **Cache frequently used data:** -- Use materialized views or caching at the application level. +- Use materialized views or caching at the application level. **Profiling and Query Analysis:** -- Use tools (`EXPLAIN`, `EXPLAIN PLAN`) to analyze query execution plans. +- Use tools (`EXPLAIN`, `EXPLAIN PLAN`) to analyze query execution plans. + +For a deeper dive with examples, see the article [“SQL Query Optimization: 10 Ways to Speed Up a Slow Query”](https://sql-academy.org/en/blog/sql-query-optimization). diff --git a/interviewQuestions/19/en.mdx b/interviewQuestions/19/en.mdx index 3ad7b8b..cf1fb93 100644 --- a/interviewQuestions/19/en.mdx +++ b/interviewQuestions/19/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'What are constraints and what types exist?' - description: 'Constraints in SQL ensure data integrity. Learn about NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK, and DEFAULT for reliable data in tables.' + title: "What are constraints and what types exist?" + description: "Constraints in SQL ensure data integrity. Learn about NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK, and DEFAULT for reliable data in tables." --- **Constraints** ensure data integrity and reliability in a table by defining rules for the data in columns. @@ -10,7 +10,7 @@ Types of constraints: **NOT NULL:** -- Prohibits storing `NULL` values in a column. +- Prohibits storing `NULL` values in a column. Example: @@ -23,7 +23,7 @@ CREATE TABLE products ( **UNIQUE:** -- Ensures uniqueness of values in a column or group of columns. +- Ensures uniqueness of values in a column or group of columns. Example: @@ -36,13 +36,13 @@ CREATE TABLE users ( **PRIMARY KEY:** -- A combination of `NOT NULL` and `UNIQUE`. -- Identifies each record in the table. +- A combination of `NOT NULL` and `UNIQUE`. +- Identifies each record in the table. **FOREIGN KEY:** -- Ensures referential integrity between tables. -- The value must match an existing primary key value in the related table. +- Ensures referential integrity between tables. +- The value must match an existing primary key value in the related table. Example: @@ -56,7 +56,7 @@ CREATE TABLE orders ( **CHECK:** -- Defines a condition that the values in a column must meet. +- Defines a condition that the values in a column must meet. Example: @@ -69,7 +69,7 @@ CREATE TABLE employees ( **DEFAULT:** -- Sets a default value for a column if no value is provided during insertion. +- Sets a default value for a column if no value is provided during insertion. ```sql CREATE TABLE tasks ( diff --git a/interviewQuestions/2/en.mdx b/interviewQuestions/2/en.mdx index 492b84b..751aac7 100644 --- a/interviewQuestions/2/en.mdx +++ b/interviewQuestions/2/en.mdx @@ -1,22 +1,23 @@ --- meta: - title: 'Explain the differences between DDL, DML, and DCL in SQL?' - description: 'Learn the differences between DDL, DML, and DCL in SQL: defining database structure, data manipulation, and access control.' + title: "Explain the differences between DDL, DML, and DCL in SQL?" + seoTitle: "DDL vs DML vs DCL in SQL: The Difference — Interview Answer" + description: "Learn the differences between DDL, DML, and DCL in SQL: defining database structure, data manipulation, and access control." --- SQL commands are divided into three main categories: DDL (Data Definition Language): -- Used for defining the structure of a database (schema). -- Key commands: `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `RENAME`. +- Used for defining the structure of a database (schema). +- Key commands: `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `RENAME`. DML (Data Manipulation Language): -- Used for working with data within tables. -- Key commands: `SELECT`, `INSERT`, `UPDATE`, `DELETE`. +- Used for working with data within tables. +- Key commands: `SELECT`, `INSERT`, `UPDATE`, `DELETE`. DCL (Data Control Language): -- Used for managing database access rights. -- Key commands: `GRANT`, `REVOKE`. +- Used for managing database access rights. +- Key commands: `GRANT`, `REVOKE`. diff --git a/interviewQuestions/20/en.mdx b/interviewQuestions/20/en.mdx index c6eba67..b0494f4 100644 --- a/interviewQuestions/20/en.mdx +++ b/interviewQuestions/20/en.mdx @@ -1,23 +1,23 @@ --- meta: - title: 'What is SQL injection and how to protect against it?' - description: 'SQL injection is a method of attacking databases. Learn how to protect yourself using parameterized queries, ORM, data validation, and access control restrictions.' + title: "What is SQL injection and how to protect against it?" + description: "SQL injection is a method of attacking databases. Learn how to protect yourself using parameterized queries, ORM, data validation, and access control restrictions." --- > **SQL Injection** is a method of attacking a database where an attacker inserts malicious SQL code through input fields, allowing unauthorized SQL queries to be executed. ## Consequences of SQL Injection: -- Data theft. -- Deletion or modification of data. -- Gaining administrative access. +- Data theft. +- Deletion or modification of data. +- Gaining administrative access. ## Methods of protection against SQL injection **1. Parameterized queries (Prepared Statements):** -- Use parameters instead of string concatenation. -- The DBMS automatically escapes special characters. +- Use parameters instead of string concatenation. +- The DBMS automatically escapes special characters. Example (in Java using JDBC): @@ -31,19 +31,19 @@ ResultSet rs = stmt.executeQuery(); **2. Using ORM (Object-Relational Mapping):** -- ORM libraries often include built-in protection mechanisms against SQL injection. +- ORM libraries often include built-in protection mechanisms against SQL injection. **3. Input Validation and Filtering:** -- Validate input data to match the expected format. -- Use validation both on the server and client side. +- Validate input data to match the expected format. +- Use validation both on the server and client side. **4. Restricting access rights:** -- Grant only the minimum necessary privileges to database users. -- Restrict access to system tables and operations. +- Grant only the minimum necessary privileges to database users. +- Restrict access to system tables and operations. **5. Using stored procedures:** -- Encapsulates data logic within a procedure. -- Users have access only to the procedures, not directly to the tables. +- Encapsulates data logic within a procedure. +- Users have access only to the procedures, not directly to the tables. diff --git a/interviewQuestions/21/en.mdx b/interviewQuestions/21/en.mdx index 734d021..6a379e4 100644 --- a/interviewQuestions/21/en.mdx +++ b/interviewQuestions/21/en.mdx @@ -1,20 +1,20 @@ --- meta: - title: 'What is a relational database?' - description: 'A relational database stores data in tables and uses keys to establish relationships between them. Learn about the advantages and characteristics of relational databases.' + title: "What is a relational database?" + description: "A relational database stores data in tables and uses keys to establish relationships between them. Learn about the advantages and characteristics of relational databases." --- > **A relational database** is a database based on the relational model of data. In such a database, data is stored in tables, and relationships between data are defined using keys. ## Key characteristics: -- Tables (relations): Data is organized into tables consisting of rows and columns. -- Rows (records): Each row represents an individual record. -- Columns (attributes): Each column contains data of a specific type. -- Keys: Used to identify records and establish relationships between tables. +- Tables (relations): Data is organized into tables consisting of rows and columns. +- Rows (records): Each row represents an individual record. +- Columns (attributes): Each column contains data of a specific type. +- Keys: Used to identify records and establish relationships between tables. ## Advantages of relational databases: -- Flexibility: New tables and columns can be easily added. -- Data Integrity: Use of constraints to maintain data integrity. -- SQL: A standard language for managing data. +- Flexibility: New tables and columns can be easily added. +- Data Integrity: Use of constraints to maintain data integrity. +- SQL: A standard language for managing data. diff --git a/interviewQuestions/22/en.mdx b/interviewQuestions/22/en.mdx index 8bd7d97..c0ba02f 100644 --- a/interviewQuestions/22/en.mdx +++ b/interviewQuestions/22/en.mdx @@ -1,13 +1,13 @@ --- meta: - title: 'Explain the Difference Between INNER JOIN and OUTER JOIN' - description: 'INNER JOIN returns only matching records from both tables, while OUTER JOIN includes all records, even if no match exists. Learn the key differences.' + title: "Explain the Difference Between INNER JOIN and OUTER JOIN" + description: "INNER JOIN returns only matching records from both tables, while OUTER JOIN includes all records, even if no match exists. Learn the key differences." --- ## INNER JOIN: -- Returns only records that have matching entries in both joined tables. -- If there is no match, the record is not included in the result. +- Returns only records that have matching entries in both joined tables. +- If there is no match, the record is not included in the result. Example: @@ -19,14 +19,14 @@ INNER JOIN departments d ON e.department_id = d.id; ## OUTER JOIN: -- Returns matching records, as well as records from one table that do not have a match in the other table. +- Returns matching records, as well as records from one table that do not have a match in the other table. ### Types of OUTER JOIN: **LEFT OUTER JOIN (LEFT JOIN):** -- Returns all records from the left table and the matching records from the right table. -- If there is no match, the columns from the right table will be `NULL`. +- Returns all records from the left table and the matching records from the right table. +- If there is no match, the columns from the right table will be `NULL`. Example: @@ -38,8 +38,8 @@ LEFT JOIN departments d ON e.department_id = d.id; **RIGHT OUTER JOIN (RIGHT JOIN):** -- Returns all records from the right table and the matching records from the left table. -- If there is no match, the columns from the left table will be `NULL`. +- Returns all records from the right table and the matching records from the left table. +- If there is no match, the columns from the left table will be `NULL`. Example: @@ -51,8 +51,8 @@ RIGHT JOIN departments d ON e.department_id = d.id; **FULL OUTER JOIN (FULL JOIN):** -- Returns all records where there is a match in either of the tables. -- If there is no match, the corresponding columns will be `NULL`. +- Returns all records where there is a match in either of the tables. +- If there is no match, the corresponding columns will be `NULL`. ```sql SELECT * diff --git a/interviewQuestions/23/en.mdx b/interviewQuestions/23/en.mdx index 8c492ae..f0cd82a 100644 --- a/interviewQuestions/23/en.mdx +++ b/interviewQuestions/23/en.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'What is NULL and How to Work with It in SQL?' - description: 'NULL in SQL represents the absence of data. Learn how to work with NULL using the operators IS NULL, IS NOT NULL, and functions like COALESCE, ISNULL, IFNULL.' + title: "What is NULL and How to Work with It in SQL?" + description: "NULL in SQL represents the absence of data. Learn how to work with NULL using the operators IS NULL, IS NOT NULL, and functions like COALESCE, ISNULL, IFNULL." --- > **NULL** is a special value in SQL that represents the absence of data or an unknown value. ## Characteristics of NULL: -- `NULL` is not equivalent to an empty string or zero. -- Operations with `NULL` return `NULL`. -- Comparing `NULL = NULL` returns `FALSE`. +- `NULL` is not equivalent to an empty string or zero. +- Operations with `NULL` return `NULL`. +- Comparing `NULL = NULL` returns `FALSE`. ## Working with NULL @@ -26,29 +26,35 @@ SELECT * FROM employees WHERE birth_date IS NOT NULL; ## Functions for working with NULL -- - **COALESCE** - +- + **COALESCE** + + Returns the first non-`NULL` value from the list. ```sql COALESCE(val1[, val2, ...., val_n]) ``` -- - **ISNULL** - +- + **ISNULL** + + Returns `1` or `0` depending on whether the expression is `NULL`. ```sql ISNULL(value) ``` -- - **IFNULL** - - Returns the first argument if it is not `NULL`. Otherwise, it returns the second argument. +- + **IFNULL** + + + Returns the first argument if it is not `NULL`. Otherwise, it returns the second + argument. ```sql IFNULL(value, alternative_value) ``` + +For a deeper dive with examples, see the article [“SQL COALESCE: Replacing NULL and the NULLIF Combo”](https://sql-academy.org/en/blog/sql-coalesce). diff --git a/interviewQuestions/24/en.mdx b/interviewQuestions/24/en.mdx index c868178..79bbb91 100644 --- a/interviewQuestions/24/en.mdx +++ b/interviewQuestions/24/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How to use the CASE operator in SQL?' - description: 'The CASE operator in SQL is used for conditional logic in queries. Learn how to apply CASE to assign values based on conditions.' + title: "How to use the CASE operator in SQL?" + description: "The CASE operator in SQL is used for conditional logic in queries. Learn how to apply CASE to assign values based on conditions." --- The `CASE` operator is used to implement conditional logic in SQL queries. @@ -18,7 +18,7 @@ END ## Examples -- Assigning categories based on salary: +- Assigning categories based on salary: ```sql SELECT name, salary, diff --git a/interviewQuestions/25/en.mdx b/interviewQuestions/25/en.mdx index 521ad34..acba271 100644 --- a/interviewQuestions/25/en.mdx +++ b/interviewQuestions/25/en.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'Explain Transactional Commands COMMIT and ROLLBACK.' - description: 'COMMIT commits a transaction, making changes permanent, while ROLLBACK undoes changes, returning the database to its original state. Learn how to manage transactions.' + title: "Explain Transactional Commands COMMIT and ROLLBACK." + description: "COMMIT commits a transaction, making changes permanent, while ROLLBACK undoes changes, returning the database to its original state. Learn how to manage transactions." --- ## COMMIT -- Commits the current transaction. -- All changes made during the transaction become permanent and visible to other users. -- After a `COMMIT`, changes cannot be undone. +- Commits the current transaction. +- All changes made during the transaction become permanent and visible to other users. +- After a `COMMIT`, changes cannot be undone. ```sql BEGIN TRANSACTION; @@ -21,9 +21,9 @@ COMMIT; ## ROLLBACK -- Reverts the current transaction. -- All changes made during the transaction are undone. -- The database is returned to the state it was in before the transaction began. +- Reverts the current transaction. +- All changes made during the transaction are undone. +- The database is returned to the state it was in before the transaction began. ```sql BEGIN TRANSACTION; @@ -36,6 +36,6 @@ ROLLBACK; ## Usage in transaction management: -- `BEGIN TRANSACTION` or `START TRANSACTION`: begins a transaction. -- `COMMIT`: commits the transaction. -- `ROLLBACK`: rolls back the transaction. +- `BEGIN TRANSACTION` or `START TRANSACTION`: begins a transaction. +- `COMMIT`: commits the transaction. +- `ROLLBACK`: rolls back the transaction. diff --git a/interviewQuestions/26/en.mdx b/interviewQuestions/26/en.mdx index 5c1b166..c537578 100644 --- a/interviewQuestions/26/en.mdx +++ b/interviewQuestions/26/en.mdx @@ -1,32 +1,32 @@ --- meta: - title: 'Explain the differences between CHAR and VARCHAR' - description: 'CHAR stores fixed-length strings, while VARCHAR stores variable-length strings. Learn how to choose between CHAR and VARCHAR based on data and memory usage.' + title: "Explain the differences between CHAR and VARCHAR" + description: "CHAR stores fixed-length strings, while VARCHAR stores variable-length strings. Learn how to choose between CHAR and VARCHAR based on data and memory usage." --- ## CHAR(n): -- Stores fixed-length strings of length `n`. -- If the entered string is shorter than `n`, it is padded with spaces to reach the length of `n`. -- Used for storing data of uniform length (e.g., country codes, postal codes). +- Stores fixed-length strings of length `n`. +- If the entered string is shorter than `n`, it is padded with spaces to reach the length of `n`. +- Used for storing data of uniform length (e.g., country codes, postal codes). ## VARCHAR(n): -- Stores variable-length strings up to `n` characters. -- Actually occupies as much space as the number of characters in the string plus a small overhead for storing the length. -- Used for storing string data of variable length. +- Stores variable-length strings up to `n` characters. +- Actually occupies as much space as the number of characters in the string plus a small overhead for storing the length. +- Used for storing string data of variable length. ## Key differences: Memory and performance: -- `CHAR` always occupies a fixed amount of memory. -- `VARCHAR` is more memory-efficient but may be slightly slower in access. +- `CHAR` always occupies a fixed amount of memory. +- `VARCHAR` is more memory-efficient but may be slightly slower in access. Usage: -- `CHAR` is suitable for data with predictable length. -- `VARCHAR` is suitable for data with variable length. +- `CHAR` is suitable for data with predictable length. +- `VARCHAR` is suitable for data with variable length. Example: diff --git a/interviewQuestions/27/en.mdx b/interviewQuestions/27/en.mdx index bbed333..3c443f1 100644 --- a/interviewQuestions/27/en.mdx +++ b/interviewQuestions/27/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'What is a temporary table in SQL?' - description: 'A temporary table in SQL exists only for the duration of the session and is automatically deleted after it ends. Learn how to create and use temporary tables.' + title: "What is a temporary table in SQL?" + description: "A temporary table in SQL exists only for the duration of the session and is automatically deleted after it ends. Learn how to create and use temporary tables." --- > **A temporary table** is a table that exists only for the duration of the current session or connection and is automatically deleted when the session ends or the connection is closed. @@ -30,6 +30,6 @@ SELECT * FROM #TempTable; ## Applications of temporary tables -- Storing intermediate results in complex queries. -- Handling large datasets in batch operations. -- Avoiding conflicts when multiple users are working simultaneously. +- Storing intermediate results in complex queries. +- Handling large datasets in batch operations. +- Avoiding conflicts when multiple users are working simultaneously. diff --git a/interviewQuestions/28/en.mdx b/interviewQuestions/28/en.mdx index 9f22f68..86f3afc 100644 --- a/interviewQuestions/28/en.mdx +++ b/interviewQuestions/28/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'What are window functions in SQL?' - description: 'Window functions in SQL allow performing calculations on a set of rows without grouping. Learn how to use SUM, ROW_NUMBER, LAG, and other window functions.' + title: "What are window functions in SQL?" + description: "Window functions in SQL allow performing calculations on a set of rows without grouping. Learn how to use SUM, ROW_NUMBER, LAG, and other window functions." --- > **Window functions** are functions that perform calculations over a set of rows (a window) related to the current row and return a result for each row without grouping the data. @@ -10,23 +10,25 @@ meta: ### Aggregate functions: -- `SUM` — calculates the total sum of values -- `COUNT` — counts the total number of records in a column -- `AVG` — calculates the arithmetic mean -- `MAX` — finds the maximum value -- `MIN` — determines the minimum value +- `SUM` — calculates the total sum of values +- `COUNT` — counts the total number of records in a column +- `AVG` — calculates the arithmetic mean +- `MAX` — finds the maximum value +- `MIN` — determines the minimum value ### Ranking functions: -- `ROW_NUMBER`: assigns a sequential number to a row within the window -- `RANK`: assigns a rank to a row within the window, with gaps when values tie -- `DENSE_RANK`: assigns a rank to a row without gaps +- `ROW_NUMBER`: assigns a sequential number to a row within the window +- `RANK`: assigns a rank to a row within the window, with gaps when values tie +- `DENSE_RANK`: assigns a rank to a row without gaps ### Offset functions: -- `LAG`: returns the value from the previous row -- `LEAD`: returns the value from the next row -- `FIRST_VALUE`: returns the first value in the window -- `LAST_VALUE`: returns the last value in the window +- `LAG`: returns the value from the previous row +- `LEAD`: returns the value from the next row +- `FIRST_VALUE`: returns the first value in the window +- `LAST_VALUE`: returns the last value in the window A detailed explanation of how window functions work can be found in our course. + +For a deeper dive with examples, see the article [“ROW_NUMBER vs RANK vs DENSE_RANK: The Difference in One Example”](https://sql-academy.org/en/blog/row-number-rank-dense-rank). diff --git a/interviewQuestions/29/en.mdx b/interviewQuestions/29/en.mdx index 700e6af..2c995d2 100644 --- a/interviewQuestions/29/en.mdx +++ b/interviewQuestions/29/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Explain the concept of CTE (common table expression)' - description: 'A CTE (common table expression) is a temporary result set that improves the readability and structure of complex SQL queries. Learn how to use CTEs and their advantages.' + title: "Explain the concept of CTE (common table expression)" + description: "A CTE (common table expression) is a temporary result set that improves the readability and structure of complex SQL queries. Learn how to use CTEs and their advantages." --- > **CTE (common table expression)** is a temporary named result set defined in an SQL query using the `WITH` keyword. @@ -21,8 +21,10 @@ SELECT * FROM CTEName; ## Advantages of CTE -- Improves code readability. -- Allows breaking down complex queries into logical parts. -- Supports recursive queries (recursive CTEs). +- Improves code readability. +- Allows breaking down complex queries into logical parts. +- Supports recursive queries (recursive CTEs). A detailed explanation of CTEs can be found in our course. + +For a deeper dive with examples, see the article [“CTE in SQL: What a Common Table Expression Is — with Recursion”](https://sql-academy.org/en/blog/sql-cte). diff --git a/interviewQuestions/3/en.mdx b/interviewQuestions/3/en.mdx index 3ec49c1..aa0c140 100644 --- a/interviewQuestions/3/en.mdx +++ b/interviewQuestions/3/en.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'What is a Primary Key and a Foreign Key?' - description: 'A primary key is a unique identifier for a record, while a foreign key links tables, ensuring data integrity in the database' + title: "What is a Primary Key and a Foreign Key?" + description: "A primary key is a unique identifier for a record, while a foreign key links tables, ensuring data integrity in the database" --- ## Primary Key (PRIMARY KEY): -- A unique identifier for a record in a table. -- Does not allow duplicates or NULL values. -- Can consist of one or more columns (composite key). +- A unique identifier for a record in a table. +- Does not allow duplicates or NULL values. +- Can consist of one or more columns (composite key). ```sql CREATE TABLE students ( @@ -20,9 +20,9 @@ CREATE TABLE students ( ## Foreign Key (FOREIGN KEY) -- A column or set of columns that refer to the primary key of another table. -- Ensures referential integrity between tables. -- Allows linking records from different tables. +- A column or set of columns that refer to the primary key of another table. +- Ensures referential integrity between tables. +- Allows linking records from different tables. ```sql CREATE TABLE enrollments ( diff --git a/interviewQuestions/30/en.mdx b/interviewQuestions/30/en.mdx index ddbc3f3..523c1b4 100644 --- a/interviewQuestions/30/en.mdx +++ b/interviewQuestions/30/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How to delete a table along with its data?' - description: 'The DROP TABLE command in SQL deletes a table along with its data, indexes, and triggers. Learn how to use DROP TABLE and its features.' + title: "How to delete a table along with its data?" + description: "The DROP TABLE command in SQL deletes a table along with its data, indexes, and triggers. Learn how to use DROP TABLE and its features." --- The `DROP TABLE` command is used to delete a table and all its data from the database. @@ -14,5 +14,5 @@ DROP TABLE table_name; ## Features: -- All data, indexes, triggers, and permissions associated with the table are deleted. -- The action is irreversible unless backup or recovery mechanisms are in place. +- All data, indexes, triggers, and permissions associated with the table are deleted. +- The action is irreversible unless backup or recovery mechanisms are in place. diff --git a/interviewQuestions/31/en.mdx b/interviewQuestions/31/en.mdx index 2d4bd41..33b7c15 100644 --- a/interviewQuestions/31/en.mdx +++ b/interviewQuestions/31/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'What is a FOREIGN KEY and how does it ensure data integrity?' - description: 'A FOREIGN KEY in SQL establishes a relationship between tables and ensures data integrity by guaranteeing that foreign keys match existing values.' + title: "What is a FOREIGN KEY and how does it ensure data integrity?" + description: "A FOREIGN KEY in SQL establishes a relationship between tables and ensures data integrity by guaranteeing that foreign keys match existing values." --- > **A FOREIGN KEY** is a constraint that establishes a relationship between a column or set of columns in one table and a column or columns in another table (typically a primary key). @@ -10,11 +10,11 @@ It ensures referential integrity by guaranteeing that values in the foreign key ## How data integrity is ensured: -- **Prevents insertion of invalid data** - It is impossible to insert a value into the foreign key column if that value does not exist in the related table. +- **Prevents insertion of invalid data** + It is impossible to insert a value into the foreign key column if that value does not exist in the related table. -- **Prevents deletion of related records** - It is impossible to delete a record from the parent table if records in the child table reference it, unless additional actions are taken. +- **Prevents deletion of related records** + It is impossible to delete a record from the parent table if records in the child table reference it, unless additional actions are taken. ### Example of a foreign key: diff --git a/interviewQuestions/32/en.mdx b/interviewQuestions/32/en.mdx index b2d28e4..16ac4ab 100644 --- a/interviewQuestions/32/en.mdx +++ b/interviewQuestions/32/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How to add a new column to an existing table' - description: 'The ALTER TABLE command with the ADD operator allows you to add a new column to an existing table. Learn how to add a column with a data type and constraints.' + title: "How to add a new column to an existing table" + description: "The ALTER TABLE command with the ADD operator allows you to add a new column to an existing table. Learn how to add a column with a data type and constraints." --- The `ALTER TABLE` command with the `ADD` operator is used to add a new column to an existing table. @@ -29,6 +29,6 @@ ALTER TABLE employees ADD date_of_birth DATE NOT NULL DEFAULT '1900-01-01'; ``` -**Note** +**Note**\ When adding a column with a `NOT NULL` constraint, if there are already existing rows in the table, you must specify a default value; otherwise, an error will occur. diff --git a/interviewQuestions/33/en.mdx b/interviewQuestions/33/en.mdx index 06bd248..561a93e 100644 --- a/interviewQuestions/33/en.mdx +++ b/interviewQuestions/33/en.mdx @@ -1,15 +1,15 @@ --- meta: - title: 'What is a correlated subquery?' - description: 'A correlated subquery in SQL is executed for each row of the outer query, using its values. Learn how and when to use correlated subqueries.' + title: "What is a correlated subquery?" + description: "A correlated subquery in SQL is executed for each row of the outer query, using its values. Learn how and when to use correlated subqueries." --- > **A correlated subquery** is a subquery that depends on the outer query. It is executed for each row of the outer query, using values from that row. ## Features -- The subquery references columns from the outer query. -- It can be less efficient due to multiple executions. +- The subquery references columns from the outer query. +- It can be less efficient due to multiple executions. ## Example @@ -25,7 +25,7 @@ WHERE e.salary > ( ); ``` -- Here, the subquery calculates the average salary for the department of each employee. -- The main query selects employees whose salary is higher than the department average. +- Here, the subquery calculates the average salary for the department of each employee. +- The main query selects employees whose salary is higher than the department average. More information about correlated subqueries can be found in our course. diff --git a/interviewQuestions/34/en.mdx b/interviewQuestions/34/en.mdx index 622c3b8..d2220c3 100644 --- a/interviewQuestions/34/en.mdx +++ b/interviewQuestions/34/en.mdx @@ -1,15 +1,15 @@ --- meta: - title: 'Explain the difference between DELETE, TRUNCATE, and DROP' - description: 'DELETE removes selected records, TRUNCATE clears the entire table while preserving its structure, and DROP completely deletes the table. Learn the key differences between these commands.' + title: "Explain the difference between DELETE, TRUNCATE, and DROP" + description: "DELETE removes selected records, TRUNCATE clears the entire table while preserving its structure, and DROP completely deletes the table. Learn the key differences between these commands." --- ## DELETE -- Removes selected records from a table. -- A `WHERE` condition can be used to delete specific records. -- The operation is logged in the transaction log row by row. -- `ON DELETE` triggers are activated. +- Removes selected records from a table. +- A `WHERE` condition can be used to delete specific records. +- The operation is logged in the transaction log row by row. +- `ON DELETE` triggers are activated. ### Syntax @@ -19,11 +19,11 @@ DELETE FROM table_name [WHERE condition]; ## TRUNCATE -- Removes all data from the table without the possibility of recovery. -- `WHERE` cannot be used. -- Faster because it does not log the deletion of each row. -- Resets auto-increment identifiers. -- Triggers are not activated. +- Removes all data from the table without the possibility of recovery. +- `WHERE` cannot be used. +- Faster because it does not log the deletion of each row. +- Resets auto-increment identifiers. +- Triggers are not activated. ### Syntax @@ -33,8 +33,8 @@ TRUNCATE TABLE table_name; ## DROP -- Deletes the entire table along with its data, structure, indexes, and constraints. -- The action is irreversible. +- Deletes the entire table along with its data, structure, indexes, and constraints. +- The action is irreversible. ### Syntax @@ -44,6 +44,8 @@ DROP TABLE table_name; ## Choosing between commands -- Use `DELETE` when you need to remove specific records. -- Use `TRUNCATE` to quickly remove all data from the table while keeping its structure. -- Use `DROP` to completely remove the table from the database. +- Use `DELETE` when you need to remove specific records. +- Use `TRUNCATE` to quickly remove all data from the table while keeping its structure. +- Use `DROP` to completely remove the table from the database. + +For a deeper dive with examples, see the article [“TRUNCATE vs DELETE vs DROP: The Difference”](https://sql-academy.org/en/blog/sql-truncate-delete-drop). diff --git a/interviewQuestions/35/en.mdx b/interviewQuestions/35/en.mdx index 83d703a..9a43384 100644 --- a/interviewQuestions/35/en.mdx +++ b/interviewQuestions/35/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'What is a Self-Join and when is it used?' - description: 'A Self-Join in SQL joins a table with itself, useful for handling hierarchies and comparing rows. Learn how and when to use a Self-Join.' + title: "What is a Self-Join and when is it used?" + description: "A Self-Join in SQL joins a table with itself, useful for handling hierarchies and comparing rows. Learn how and when to use a Self-Join." --- > **A Self-Join** is a type of join in SQL where a table is joined with itself. @@ -9,46 +9,21 @@ meta: ## When to use a Self-Join: -- **Hierarchical structures** - For example, in an employee table where each employee may have a manager who is also an employee in the same table. -- **Comparing records** - To find duplicates or compare values between different rows in the same table. +- **Hierarchical structures** + For example, in an employee table where each employee may have a manager who is also an employee in the same table. +- **Comparing records** + To find duplicates or compare values between different rows in the same table. ## Example -export const exampleFields = ['employeeId', 'name', 'managerId']; -export const exampleRows = [ - { - employeeId: 1, - name: 'John', - managerId: null, - }, - { - employeeId: 2, - name: 'Michail', - managerId: 1, - }, - { - employeeId: 3, - name: 'Alisa', - managerId: 1, - }, - { - employeeId: 4, - name: 'Max', - managerId: 2, - }, -]; - Consider the following employee data: - +| employeeId | name | managerId | +| ---------- | ------- | --------- | +| 1 | John | null | +| 2 | Michail | 1 | +| 3 | Alisa | 1 | +| 4 | Max | 2 | To get a list of employees and their managers: diff --git a/interviewQuestions/36/en.mdx b/interviewQuestions/36/en.mdx index 346fde2..40aceac 100644 --- a/interviewQuestions/36/en.mdx +++ b/interviewQuestions/36/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How to perform database backup and recovery' - description: 'Database backup and recovery in MySQL and PostgreSQL using mysqldump and pg_dump utilities. Learn how to safeguard data with regular backups.' + title: "How to perform database backup and recovery" + description: "Database backup and recovery in MySQL and PostgreSQL using mysqldump and pg_dump utilities. Learn how to safeguard data with regular backups." --- Backing up and restoring a database are critical operations to ensure data safety and @@ -21,9 +21,9 @@ Backup using the `mysqldump` utility: mysqldump -u username -p mydatabase > backup.sql ``` -- `username` — the database username. -- `mydatabase` — the name of the database to back up. -- `backup.sql` — the file where the backup will be saved. +- `username` — the database username. +- `mydatabase` — the name of the database to back up. +- `backup.sql` — the file where the backup will be saved. ### PostgreSQL @@ -33,9 +33,9 @@ Backup using the `pg_dump` utility: pg_dump -U username mydatabase > backup.sql ``` -- `-U username` — the database username. -- `mydatabase` — the name of the database. -- `backup.sql` — the output file for the backup. +- `-U username` — the database username. +- `mydatabase` — the name of the database. +- `backup.sql` — the output file for the backup. ## How to restore a database from a backup: @@ -57,11 +57,11 @@ psql -U username mydatabase < backup.sql ## Recommendations -- **Permissions** - Ensure that you have the necessary permissions to perform backup and restore operations. -- **Regularity** - Set up regular automatic backups to minimize the risk of data loss. -- **Backup storage** - Store backups in a secure and reliable location, preferably off the main server. -- **Testing** - Periodically test backups by restoring them to a test server to verify their integrity and functionality. +- **Permissions**\ + Ensure that you have the necessary permissions to perform backup and restore operations. +- **Regularity**\ + Set up regular automatic backups to minimize the risk of data loss. +- **Backup storage**\ + Store backups in a secure and reliable location, preferably off the main server. +- **Testing**\ + Periodically test backups by restoring them to a test server to verify their integrity and functionality. diff --git a/interviewQuestions/37/en.mdx b/interviewQuestions/37/en.mdx index 5ca312f..5b21a25 100644 --- a/interviewQuestions/37/en.mdx +++ b/interviewQuestions/37/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How to implement many-to-many relationships in SQL?' - description: 'Many-to-many relationships in SQL are implemented through a junction table with foreign keys. Learn how to create relationships between tables with examples.' + title: "How to implement many-to-many relationships in SQL?" + description: "Many-to-many relationships in SQL are implemented through a junction table with foreign keys. Learn how to create relationships between tables with examples." --- **A many-to-many** relationship in relational databases occurs when one record in the first table @@ -12,30 +12,30 @@ associative table) that connects the two main tables via foreign keys. ## How to implement many-to-many relationships in SQL -- **Create two main tables**, that need to be linked. -- **Create a junction table**, containing foreign keys that reference the primary keys of both main tables. -- **Define foreign keys and a composite primary key** in the junction table to ensure referential integrity and uniqueness of relationship pairs. +- **Create two main tables**, that need to be linked. +- **Create a junction table**, containing foreign keys that reference the primary keys of both main tables. +- **Define foreign keys and a composite primary key** in the junction table to ensure referential integrity and uniqueness of relationship pairs. ## Example implementation Consider a scenario with `Student` and `Course` tables where one student can enroll in multiple courses, and one course can be taken by multiple students. -- Creating the students table: +- Creating the students table: ```sql CREATE TABLE Student ( StudentID INT PRIMARY KEY, Name VARCHAR(100) ); ``` -- Creating the courses table: +- Creating the courses table: ```sql CREATE TABLE Course ( CourseID INT PRIMARY KEY, Title VARCHAR(100) ); ``` -- Creating a junction table to establish the many-to-many relationship: +- Creating a junction table to establish the many-to-many relationship: ```sql CREATE TABLE StudentCourse ( StudentID INT, @@ -48,6 +48,6 @@ and one course can be taken by multiple students. As a result: -- The **junction table** `StudentCourse` contains pairs of `StudentID` and `CourseID`, representing the relationships between students and courses. -- The **composite primary key** `(StudentID, CourseID)` ensures that each pair is unique, preventing duplicate relationships. -- The **foreign keys** ensure data integrity by referencing the corresponding records in the `Student` and `Course` tables. +- The **junction table** `StudentCourse` contains pairs of `StudentID` and `CourseID`, representing the relationships between students and courses. +- The **composite primary key** `(StudentID, CourseID)` ensures that each pair is unique, preventing duplicate relationships. +- The **foreign keys** ensure data integrity by referencing the corresponding records in the `Student` and `Course` tables. diff --git a/interviewQuestions/38/en.mdx b/interviewQuestions/38/en.mdx index 30e3ad5..00c7db7 100644 --- a/interviewQuestions/38/en.mdx +++ b/interviewQuestions/38/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How do the REVOKE and GRANT commands work?' - description: 'The GRANT and REVOKE commands in SQL manage access rights to database objects. Learn how to grant and revoke user privileges with examples.' + title: "How do the REVOKE and GRANT commands work?" + description: "The GRANT and REVOKE commands in SQL manage access rights to database objects. Learn how to grant and revoke user privileges with examples." --- The `GRANT` and `REVOKE` commands in SQL are used to manage user access rights to database objects. @@ -18,12 +18,12 @@ The `GRANT` command provides users or roles with specific privileges on database GRANT privileges ON object TO user [WITH GRANT OPTION]; ``` -- `privileges`: the actions allowed (e.g., `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `ALL PRIVILEGES`). -- `object`: the database, table, view, procedure, etc. -- `user`: the username or role to which privileges are granted. -- `WITH GRANT OPTION` (optional): allows the recipient of the privileges to grant them to others. +- `privileges`: the actions allowed (e.g., `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `ALL PRIVILEGES`). +- `object`: the database, table, view, procedure, etc. +- `user`: the username or role to which privileges are granted. +- `WITH GRANT OPTION` (optional): allows the recipient of the privileges to grant them to others. -**Example:** +**Example:**\ To grant user `user1` the privilege to select data from the `employees` table: ```sql @@ -40,7 +40,7 @@ The `REVOKE` command removes previously granted privileges from users or roles. REVOKE privileges ON object FROM user; ``` -**Example:** +**Example:**\ To revoke the `SELECT` privilege from user `user1` on the `employees` ```sql diff --git a/interviewQuestions/39/en.mdx b/interviewQuestions/39/en.mdx index c0ef54b..676c3d4 100644 --- a/interviewQuestions/39/en.mdx +++ b/interviewQuestions/39/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Explain the use of hashing functions in SQL' - description: 'Hash functions in SQL convert data into fixed-length strings for security and integrity. Learn how to use hashing for password storage and search optimization.' + title: "Explain the use of hashing functions in SQL" + description: "Hash functions in SQL convert data into fixed-length strings for security and integrity. Learn how to use hashing for password storage and search optimization." --- Hash functions in SQL are used to transform input data of arbitrary length into a fixed-length string. @@ -11,8 +11,8 @@ This transformation is called **hashing**, and it is widely used to ensure secur ### 1. Storing passwords -- Instead of storing passwords in plain text, they are stored as hashes. This increases security since, even if the database is compromised, attackers cannot recover the original passwords. -- Cryptographic hash functions like `SHA-256`, `SHA-512`, and others are commonly used. +- Instead of storing passwords in plain text, they are stored as hashes. This increases security since, even if the database is compromised, attackers cannot recover the original passwords. +- Cryptographic hash functions like `SHA-256`, `SHA-512`, and others are commonly used. ### 2. Data integrity verification @@ -49,8 +49,8 @@ WHERE Username = 'user1' AND PasswordHash = HASHBYTES('SHA2_512', 'password123') ### Choosing a hash function -- Prefer modern and robust algorithms like `SHA-256` or `SHA-512`. -- Avoid using outdated functions like `MD5` or `SHA1` due to known vulnerabilities. +- Prefer modern and robust algorithms like `SHA-256` or `SHA-512`. +- Avoid using outdated functions like `MD5` or `SHA1` due to known vulnerabilities. ### Secure storage diff --git a/interviewQuestions/4/en.mdx b/interviewQuestions/4/en.mdx index cbd35c6..aed33d3 100644 --- a/interviewQuestions/4/en.mdx +++ b/interviewQuestions/4/en.mdx @@ -1,116 +1,52 @@ --- meta: - title: 'Explain the Concept of Normalization and Its Benefits' - description: 'Normalization in SQL reduces data redundancy and improves database integrity. Learn about normal forms and the advantages of this process.' + title: "Explain the Concept of Normalization and Its Benefits" + description: "Normalization in SQL reduces data redundancy and improves database integrity. Learn about normal forms and the advantages of this process." --- > Normalization is the process of organizing the structure of a database to reduce data redundancy and ensure data integrity. ## Main goals of normalization: -- Elimination of Redundancy: Prevents data duplication. -- Improved Data Integrity: Minimizes the chance of data inconsistency. -- Easier Maintenance and Updates: Makes the database structure more flexible and understandable. +- Elimination of Redundancy: Prevents data duplication. +- Improved Data Integrity: Minimizes the chance of data inconsistency. +- Easier Maintenance and Updates: Makes the database structure more flexible and understandable. ## Key normal forms -- First Normal Form (1NF): All columns contain atomic (indivisible) values. -- Second Normal Form (2NF): Satisfies 1NF and all non-key columns depend on the entire primary key. -- Third Normal Form (3NF): Satisfies 2NF and there are no transitive dependencies between non-key columns. +- First Normal Form (1NF): All columns contain atomic (indivisible) values. +- Second Normal Form (2NF): Satisfies 1NF and all non-key columns depend on the entire primary key. +- Third Normal Form (3NF): Satisfies 2NF and there are no transitive dependencies between non-key columns. ## Example **Before normalization:** -export const beforeNormalizationTableFields = [ - 'StudentID', - 'StudentName', - 'CourseID', - 'CourseName', -]; -export const beforeNormalizationTableRows = [ - { - StudentID: '1', - StudentName: 'John', - CourseID: '101', - CourseName: 'Math', - }, - { - StudentID: '1', - StudentName: 'John', - CourseID: '102', - CourseName: 'Music', - }, -]; - - +| StudentID | StudentName | CourseID | CourseName | +| --------- | ----------- | -------- | ---------- | +| 1 | John | 101 | Math | +| 1 | John | 102 | Music | **After normalization:** Students table -export const studentsTableFields = ['StudentID', 'StudentName']; -export const studentsTableRows = [ - { - StudentID: '1', - StudentName: 'John', - }, -]; - - +| StudentID | StudentName | +| --------- | ----------- | +| 1 | John | Courses table -export const coursesTableFields = ['CourseID', 'CourseName']; -export const coursesTableRows = [ - { - CourseID: '101', - CourseName: 'Math', - }, - { - CourseID: '102', - CourseName: 'Music', - }, -]; - - +| CourseID | CourseName | +| -------- | ---------- | +| 101 | Math | +| 102 | Music | Enrollments table -export const enrollmentsTableFields = ['StudentID', 'CourseID']; -export const enrollmentsTableRows = [ - { - StudentID: '1', - CourseID: '101', - }, - { - StudentID: '1', - CourseID: '102', - }, -]; - - +| StudentID | CourseID | +| --------- | -------- | +| 1 | 101 | +| 1 | 102 | + +For a deeper dive with examples, see the article [“Database Normalization: Normal Forms Explained Simply”](https://sql-academy.org/en/blog/database-normalization). diff --git a/interviewQuestions/40/en.mdx b/interviewQuestions/40/en.mdx index 27ea541..eefd37c 100644 --- a/interviewQuestions/40/en.mdx +++ b/interviewQuestions/40/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How does an SQL trigger work?' - description: 'An SQL trigger is a stored procedure that is automatically executed during INSERT, UPDATE, or DELETE events. Learn how to use triggers for logging and maintaining data integrity.' + title: "How does an SQL trigger work?" + description: "An SQL trigger is a stored procedure that is automatically executed during INSERT, UPDATE, or DELETE events. Learn how to use triggers for logging and maintaining data integrity." --- ## What is an SQL trigger @@ -15,12 +15,12 @@ A trigger is automatically activated in response to a specified event (e.g., add ### Types of triggers -- `BEFORE`: Works before the operation is executed. - Used to validate or modify data before it is saved. -- `AFTER`: Works after the operation is executed. - Often used for logging or updating related tables. -- `INSTEAD OF`: Replaces the default behavior of the operation. - Used when you need to override the default action, such as when working with views. +- `BEFORE`: Works before the operation is executed.\ + Used to validate or modify data before it is saved. +- `AFTER`: Works after the operation is executed.\ + Often used for logging or updating related tables. +- `INSTEAD OF`: Replaces the default behavior of the operation.\ + Used when you need to override the default action, such as when working with views. Within a trigger, you can access old and new data values through special pseudo-tables: `OLD` and `NEW`. @@ -68,11 +68,11 @@ DELIMITER ; ## When to use triggers -- **Logging and auditing**: - Automatically logging data changes to track user actions. -- **Maintaining data integrity**: - Enforcing complex business rules that cannot be achieved through constraints. -- **Data synchronization**: - Automatically updating or modifying related tables when data changes. -- **Calculating values**: - Automatically calculating and updating aggregated or derived data. +- **Logging and auditing**:\ + Automatically logging data changes to track user actions. +- **Maintaining data integrity**:\ + Enforcing complex business rules that cannot be achieved through constraints. +- **Data synchronization**:\ + Automatically updating or modifying related tables when data changes. +- **Calculating values**:\ + Automatically calculating and updating aggregated or derived data. diff --git a/interviewQuestions/5/en.mdx b/interviewQuestions/5/en.mdx index 5eada76..2e2a425 100644 --- a/interviewQuestions/5/en.mdx +++ b/interviewQuestions/5/en.mdx @@ -1,24 +1,24 @@ --- meta: - title: 'What is a JOIN and what types of JOINs do you know' - description: 'JOIN in SQL combines data from multiple tables. Learn about types of JOINs: INNER, LEFT, RIGHT, FULL, and CROSS JOIN for efficient database work.' + title: "What is a JOIN and what types of JOINs do you know" + description: "JOIN in SQL combines data from multiple tables. Learn about types of JOINs: INNER, LEFT, RIGHT, FULL, and CROSS JOIN for efficient database work." --- > JOIN is an operation in SQL that allows combining rows from two or more tables based on related columns between them. ## Types of JOINs: -- `INNER JOIN`: - Returns records that have matching values in both tables.. +- `INNER JOIN`:\ + Returns records that have matching values in both tables.. -- `LEFT JOIN (or LEFT OUTER JOIN)`: - Returns all records from the left table and the matching records from the right table. If there is no match, it returns NULL for the right table. +- `LEFT JOIN (or LEFT OUTER JOIN)`:\ + Returns all records from the left table and the matching records from the right table. If there is no match, it returns NULL for the right table. -- `RIGHT JOIN (or RIGHT OUTER JOIN)`: - Returns all records from the right table and the matching records from the left table. If there is no match, it returns NULL for the left table. +- `RIGHT JOIN (or RIGHT OUTER JOIN)`:\ + Returns all records from the right table and the matching records from the left table. If there is no match, it returns NULL for the left table. -- `FULL OUTER JOIN`: - Returns all records where there is a match in one of the tables. +- `FULL OUTER JOIN`:\ + Returns all records where there is a match in one of the tables. -- `CROSS JOIN`: - Performs a Cartesian product of two tables, combining each row of the first table with each row of the second table. +- `CROSS JOIN`:\ + Performs a Cartesian product of two tables, combining each row of the first table with each row of the second table. diff --git a/interviewQuestions/6/en.mdx b/interviewQuestions/6/en.mdx index e2b5567..cd71824 100644 --- a/interviewQuestions/6/en.mdx +++ b/interviewQuestions/6/en.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'What is a Subquery and When is it Used?' - description: 'A subquery in SQL is a nested query used for filtering data, selecting, or creating virtual tables. Learn when and how to apply it.' + title: "What is a Subquery and When is it Used?" + description: "A subquery in SQL is a nested query used for filtering data, selecting, or creating virtual tables. Learn when and how to apply it." --- > **A subquery** is an SQL query nested inside another query. It is used to perform operations whose results are needed for the main query. ## Use cases for subqueries: -- **Data Filtering**: Using the results of a subquery in `WHERE` or `HAVING` conditions. -- **Data Selection**: Using a subquery in the list of selected columns. -- **Creating Virtual Tables**: Using a subquery in the `FROM` clause. +- **Data Filtering**: Using the results of a subquery in `WHERE` or `HAVING` conditions. +- **Data Selection**: Using a subquery in the list of selected columns. +- **Creating Virtual Tables**: Using a subquery in the `FROM` clause. ## Examples diff --git a/interviewQuestions/7/en.mdx b/interviewQuestions/7/en.mdx index 2b0e386..1181d49 100644 --- a/interviewQuestions/7/en.mdx +++ b/interviewQuestions/7/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'How to remove duplicates in the result of an SQL query?' - description: 'Removing duplicates in SQL is done using the DISTINCT keyword. Learn how to use it to retrieve unique records.' + title: "How to remove duplicates in the result of an SQL query?" + description: "Removing duplicates in SQL is done using the DISTINCT keyword. Learn how to use it to retrieve unique records." --- Use the `DISTINCT` keyword in the `SELECT` statement to return only unique records. diff --git a/interviewQuestions/8/en.mdx b/interviewQuestions/8/en.mdx index 4765a83..bf8b9fa 100644 --- a/interviewQuestions/8/en.mdx +++ b/interviewQuestions/8/en.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'Explain the difference between WHERE and HAVING' - description: 'The difference between WHERE and HAVING in SQL: WHERE filters data before grouping, HAVING after. Learn when and how to use these clauses.' + title: "Explain the difference between WHERE and HAVING" + description: "The difference between WHERE and HAVING in SQL: WHERE filters data before grouping, HAVING after. Learn when and how to use these clauses." --- ## WHERE -- Filters rows before data is grouped. -- Cannot use aggregate functions (`SUM()`, `COUNT()`, `AVG()`, etc.). -- Applies to individual records in the table. +- Filters rows before data is grouped. +- Cannot use aggregate functions (`SUM()`, `COUNT()`, `AVG()`, etc.). +- Applies to individual records in the table. Example: @@ -21,9 +21,9 @@ GROUP BY department_id; ## HAVING -- Filters groups of rows after the data is grouped. -- Can use aggregate functions. -- Applies to the results of `GROUP BY`. +- Filters groups of rows after the data is grouped. +- Can use aggregate functions. +- Applies to the results of `GROUP BY`. Example: diff --git a/interviewQuestions/9/en.mdx b/interviewQuestions/9/en.mdx index 0b0be33..6a548a8 100644 --- a/interviewQuestions/9/en.mdx +++ b/interviewQuestions/9/en.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'What is an index and how does it affect performance?' - description: 'An index in SQL improves data retrieval speed but can slow down write operations. Learn how indexes affect performance and their advantages.' + title: "What is an index and how does it affect performance?" + description: "An index in SQL improves data retrieval speed but can slow down write operations. Learn how indexes affect performance and their advantages." --- > **An Index** is a special data structure that improves the speed of data retrieval operations from a table by creating pointers to the data. @@ -10,13 +10,13 @@ Indexes speed up read operations but can slow down write operations (inserts, up ## Advantages of Indexes: -- Faster execution of `SELECT` operations. -- Improved performance when sorting and searching data. +- Faster execution of `SELECT` operations. +- Improved performance when sorting and searching data. ## Disadvantages of Indexes: -- Additional disk space required. -- Slower performance for `INSERT`, `UPDATE`, and `DELETE` operations. +- Additional disk space required. +- Slower performance for `INSERT`, `UPDATE`, and `DELETE` operations. ## Example of creating an index: