Логика работы в реляционных СУБД строится на реляционной алгебре. Поэтому в подобных системах добавляют приставку «реляционная». Прикладному программисту необязательно разбираться в этой области алгебры, но знать основы полезно.
В этом уроке мы разберем способы представления данных и расскажем, почему реляционная модель подходит для этого лучше всего.
Способы представления данных
Данные и как они хранятся на диске — две большие разницы. Физическое размещение данных на носителях — возможность конкретных СУБД. И в этом случае они соревнуются, кто быстрее и эффективнее.
Внешнее представление — это то, что видит пользователь. Оно влияет на способ взаимодействия с данными. Поэтому разные способы представления данных называются моделями.
Эти модели не отражают то, что происходит на физическом уровне. Они описывают, как данные структурированы, и как с ними взаимодействовать. Модели данных очень похожи на абстрактные типы данных, которые определяют интерфейс взаимодействия с типом и не определяют его внутреннюю реализацию.
Существует много разных способов представить одни и те же данные. В этом уроке мы разберем три самых популярных:
- Иерархическая модель
- Сетевая модель
- Реляционная модель
Разберем каждый способ подробнее.
Иерархическая модель
В иерархической модели данные представлены в виде дерева, где дочерние элементы находятся в зависимости от родительских:
С помощью иерархической модели можно представить не только университет, но и составляющие бизнеса. К примеру, у сервиса такси есть такие понятия, как пользователь и заказ. У одного пользователя может быть множество заказов. Это сразу определяет структуру дерева:
- Родительский элемент — пользователь
- Дочерние элементы — заказы
Подобным образом структурируются и все остальные части.
Проблемы начинаются, когда у одного дочернего элемента может быть несколько родительских. Представим, что сервис такси добавил такую функцию — можно оплачивать счет совместно. Это значит, что у одного заказа сразу несколько клиентов.
В этом случае иерархическая модель не может предложить хорошего решения данной задачи. Придется создавать параллельные деревья, в которых появится дублирование данных. Эта проблема решается в сетевой модели данных, которую мы разберем далее.
Сетевая модель
Сетевая модель данных расширяет иерархическую и позволяет иметь множество предков. Сетевая модель — это граф, у которого много вершин и соединений между ними:
В сетевой структуре каждый элемент может быть связан с любым другим элементом.
Недостаток сетевой модели данных — высокая сложность и жесткость схемы БД, которая построена на ее основе. Поскольку логика процедуры выборки данных зависит от физической организации этих данных, то эта модель не является полностью независимой от приложения. Если необходимо изменить структуру данных, то нужно изменить и приложение.
Чтобы не столкнуться с еще одной проблемой, программисты используют реляционную модель.
Реляционная модель
Наибольшее распространение получила реляционная модель данных. На ее основе построены реляционные СУБД. В реляционной модели данные — это набор отношений. В алгебре понятие отношение звучит так:
Пусть дана совокупность типов данных T1, T2, ..., Tn, называемых также доменами, необязательно различных. Тогда n-арным отношением R, или отношением R степени n называют подмножество декартовa произведения множеств T1, T2, ..., Tn.
Разберем это определение, чтобы лучше его понять.
Что такое отношение в реляционной модели
У отношения нет физического представления. Реляционная база данных — это попытка отразить реляционную модель, а не ее точная копия.
Реляционная модель опирается на раздел математики теорию множеств, которую нужно знать хотя бы немного. Множество — это совокупность произвольных элементов, которые объединены по некоторому признаку. Например, множество натуральных чисел или множество учеников одного класса. Изучить этот раздел подробнее вы можете в нашем курсе «Теория множеств».
Из любого множества можно выделить подмножество — множество элементов, все элементы которого входят в исходное множество. Подмножество — это часть множества. Например, множество натуральных чисел — это подмножество по отношению к множеству целых чисел, которое в свою очередь — подмножество рациональных чисел. Из этого следует, что натуральные числа — это подмножество рациональных чисел.
Еще одно важное понятие — кортеж. Это упорядоченный набор данных фиксированной длины. Элементами кортежа может быть все что угодно. Это математический способ представить некоторый набор связанных данных.
На основе этих понятий можно сформулировать более понятное определение отношения. Отношение — это множество кортежей, которые называются телом отношения. В нем каждый кортеж соответствует схеме.
Схема — это заголовок отношения. Она описывает общую структуру кортежей, количество элементов внутри них и их типы. Каждый такой элемент называется атрибутом:
Отношение визуально похоже на таблицу, но у него есть существенные отличия:
- Нет двух одинаковых элементов (кортежей)
- Порядок кортежей не определен
- Порядок атрибутов в заголовке не определен
По этой причине таблица непригодна для точного описания отношения. В любой таблице порядок столбцов (атрибуты схемы) и строк (кортеж) строго определен. При этом на практике мы оперируем таблицами и не можем игнорировать их.
Во всех реляционных базах данных столбцы расположены в определенном порядке, и данные тоже добавляются строго определенным образом. Но этот порядок зависит от реализации самой базы данных и не может быть задан, а задается только при выборке.
Реляционная модель — удачный выбор в большинстве ситуаций. У нее нет недостатков, которые есть у других моделей. Но чтобы ее освоить, нужно время, так как придется научиться раскладывать данные по таблицам правильным способом. Чтобы взаимодействовать с данными, которые описаны реляционной моделью, используется реляционная алгебра. Ее элементы мы рассмотрим позже.
Данные, представленные в реляционной модели, нужно привести к нормальной форме — это требования, которым должно удовлетворять отношение для минимизации избыточности данных, потенциально приводящих к логическим ошибкам.
Выводы
В следующих уроках мы познакомимся с тремя нормальными формами, так как они наиболее часто используются в реальной разработке. Причем программисты, которые часто работают с базами данных, даже не помнят теорию, связанную с формами.
Понимая, как структурируются данные в реляционной модели, мозг самостоятельно предлагает правильные решения по тому, как разложить данные.
<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 15:10:53 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="KfXFBC2hVPHGbTjfHjN185iXfkh4RH2sBlNaD_ee1oXGJA4z39_5kXAuHEcSPIWEWJ5T4nBzgw67s8BbpZkx6w";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Реляционная модель данных | Основы реляционных баз данных</title>
<meta name="description" content="Реляционная модель данных / Основы реляционных баз данных: Говорим про фундамент, на котором стоит любая реляционная база данных">
<link rel="canonical" href="https://ru.hexlet.io/courses/rdb-basics/lessons/relations/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Реляционная модель данных">
<meta property="og:title" content="Основы реляционных баз данных">
<meta property="og:description" content="Реляционная модель данных / Основы реляционных баз данных: Говорим про фундамент, на котором стоит любая реляционная база данных">
<meta property="og:url" content="https://ru.hexlet.io/courses/rdb-basics/lessons/relations/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="a0F91ithp3BkkPGyVy5zbzlaLsZCecXmojVRX3kq1ZyEkLbh2R8KENLT1SpbIYMY-VMDbEpOO0Qf1csLKy0y8g" />
<script src="/vite/assets/inertia-INZxX8jp.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-6pOtQ3OW.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T15:10:53.718Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"Qj49HeYkhPvT3HBak0zturpnK-0PXcDenyOxyjajMNqt7_YqFFopm2WfVMKfQx3Nem4GRwdqPnwiwyueZKTXtA","topics":[{"id":28244,"title":"**В вопросе:**\nЧто является результатом операции объединение (union) в теории множеств?\n**Есть такие ответы:**\n**1** - Множество в которое входят элементы исходных множеств\n**2** - Множество элементов которые присутствуют одновременно и в первом и втором множествах\n\nПоясните, пожалуйста, в чем разница между ответом **1** и ответом **2**.\n","plain_title":"В вопросе: Что является результатом операции объединение (union) в теории множеств? Есть такие ответы: 1 - Множество в которое входят элементы исходных множеств 2 - Множество элементов которые присутствуют одновременно и в первом и втором множествах Поясните, пожалуйста, в чем разница между ответом 1 и ответом 2. ","creator":{"public_name":"Lenri Rodionova","id":194087,"is_tutor":false},"comments":[{"creator":{"public_name":"Dmitriy Bataev","id":106130,"is_tutor":false},"id":60743,"body":"Здравствуйте. В первом варианте есть элементы одного из множеств, которые не будут частью другого. Во втором варианте таких элементов быть не может.","topic_id":28244},{"creator":{"public_name":"Lenri Rodionova","id":194087,"is_tutor":false},"id":60895,"body":"Непонятно только, почему сразу не писать:\n1. Объединение множеств.\n2. Пересечение множеств.\nКратко и сразу всё понятно.\n","topic_id":28244}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":44185,"title":"Так и не понимaю, почему не проходит решение, так как в самой таблице все отрабатывает ? Вот [ревью](https://ru.hexlet.io/code_reviews/279818), в чем принципиальное отличие от решения учителя ?","plain_title":"Так и не понимaю, почему не проходит решение, так как в самой таблице все отрабатывает ? Вот ревью (https://ru.hexlet.io/code_reviews/279818), в чем принципиальное отличие от решения учителя ? ","creator":{"public_name":"Андрей Лисецкий","id":173228,"is_tutor":false},"comments":[{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":95646,"body":"**Андрей Лисецкий**, приветствую.\n\nпроверьте имена столбцов ;)","topic_id":44185},{"creator":{"public_name":"Андрей Лисецкий","id":173228,"is_tutor":false},"id":95684,"body":"**Сергей Мелодин**, thanx!","topic_id":44185}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":32303,"title":"Я, как и ещё один дядя в комментах, убил уйму времени, пытаясь в одном запросе сделать и СЕЛЕКТ, и обычный ввод данных ручками... Знатный дрочь, впрочем, на Хекслете, как и в армии, иногда дрочат просто так... Ну чисто по кайфу чтоб было","plain_title":"Я, как и ещё один дядя в комментах, убил уйму времени, пытаясь в одном запросе сделать и СЕЛЕКТ, и обычный ввод данных ручками... Знатный дрочь, впрочем, на Хекслете, как и в армии, иногда дрочат просто так... Ну чисто по кайфу чтоб было ","creator":{"public_name":"Dobro-228","id":188007,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":70132,"body":"Добавил в ридми пример чтобы было понятнее.","topic_id":32303}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":43035,"title":"Добрый день, если это конечно не проверка на внимательность, то не **make reset**, а **make db-reset**\n\nВ упражнениях указано:\n> Не бойтесь сломать что-то в базе, всегда можно восстановиться командой make reset в терминале\n\nлибо поправить make на гите\n","plain_title":"Добрый день, если это конечно не проверка на внимательность, то не make reset, а make db-reset Не бойтесь сломать что-то в базе, всегда можно восстановиться командой make reset в терминале ","creator":{"public_name":"Роман Мелошников","id":282081,"is_tutor":false},"comments":[{"creator":{"public_name":"Роман Мелошников","id":282081,"is_tutor":false},"id":93678,"body":"Понятно, а я в своем терминале проверял на клоне из гита :)","topic_id":43035},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":93677,"body":"Приветствую, Роман!\n\nВ упражнении всё верно указано, нужно выполнить команду `make reset`. Данное правило описано в Makefile в упражнении, вы можете просмотреть его содержимое.","topic_id":43035}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":44462,"title":"А в чем разница между '\\d' и 'dt' ?\n\n```sql\n\\d\n List of relations\n Schema | Name | Type | Owner \n--------+-------+-------+-------\n public | cars | table | lindx\n public | users | table | lindx\n(2 rows)\n```\n```sql\n\\dt\n List of relations\n Schema | Name | Type | Owner \n--------+-------+-------+-------\n public | cars | table | lindx\n public | users | table | lindx\n(2 rows)\n```","plain_title":"А в чем разница между '\\d' и 'dt' ? \\d List of relations Schema | Name | Type | Owner --------+-------+-------+------- public | cars | table | lindx public | users | table | lindx (2 rows) \\dt List of relations Schema | Name | Type | Owner --------+-------+-------+------- public | cars | table | lindx public | users | table | lindx (2 rows) ","creator":{"public_name":"Igor Linder","id":261935,"is_tutor":false},"comments":[{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":96240,"body":"Приветствую, Игорь!\n\nВ psql можно ввести команду `\\?` и просмотреть описание интересующих вас команд:\n\n \\d[S+] list tables, views, and sequences\n \\dt[S+] [PATTERN] list tables\n\nКоманда `\\d` предоставляет более широкие возможности (отображение таблиц, последовательностей, представлений), знакомство с которыми выходит за рамки данного курса. Но при желании вы с ними можете ознакомиться самостоятельно. ","topic_id":44462},{"creator":{"public_name":"Igor Linder","id":261935,"is_tutor":false},"id":96257,"body":"Читать я умею)\n\nСначала по ходу курса когда таблицы были простыми, то было не очень понятно.\n\nПозже стало понятнее когда появились зависимости:\n\n```sql\n\\d\n List of relations\n Schema | Name | Type | Owner \n--------+--------------------+----------+-------\n public | goods | table | lindx\n public | goods_id_seq | sequence | lindx\n public | order_items | table | lindx\n public | order_items_id_seq | sequence | lindx\n public | orders | table | lindx\n public | orders_id_seq | sequence | lindx\n public | users | table | lindx\n public | users_id_seq | sequence | lindx\n(8 rows)\n```\n```sql\n\\dt\n List of relations\n Schema | Name | Type | Owner \n--------+-------------+-------+-------\n public | goods | table | lindx\n public | order_items | table | lindx\n public | orders | table | lindx\n public | users | table | lindx\n(4 rows)\n```","topic_id":44462}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":55140,"title":"Из теории:\n\n> Кортеж — это **упорядоченный** набор данных фиксированной длины.\n\n> Несмотря на визуальную схожесть с таблицей, у отношений есть существенные отличия:\n> **Порядок** атрибутов в заголовке отношения **не определён.**\n\n\nКак я понимаю, порядок в кортеже определяет именно схема (заголовок отношений).\n\nВстречала информацию, что порядок записей не определен (это понятно), но есть определенный порядок столбцов. \n\nТочно ли порядок атрибутов не определен?\nКаким образом тогда устанавливается порядок в кортеже?","plain_title":"Из теории: Кортеж — это упорядоченный набор данных фиксированной длины. Несмотря на визуальную схожесть с таблицей, у отношений есть существенные отличия: Порядок атрибутов в заголовке отношения не определён. Как я понимаю, порядок в кортеже определяет именно схема (заголовок отношений). Встречала информацию, что порядок записей не определен (это понятно), но есть определенный порядок столбцов. Точно ли порядок атрибутов не определен? Каким образом тогда устанавливается порядок в кортеже? ","creator":{"public_name":"Atlatnta Tesla","id":339552,"is_tutor":false},"comments":[{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":117297,"body":"**Atlatnta Tesla**, приветствую!\n\n> Встречала информацию, что порядок записей не определен (это понятно), но есть определенный порядок столбцов. Точно ли порядок атрибутов не определен?\n\nАтрибуты отношений не упорядочены, поскольку по определению схема отношения есть множество пар {имя атрибута, имя домена}. Для ссылки на значение атрибута в кортеже отношения всегда используется имя атрибута. Хотя упорядоченность набора атрибутов отношения явно не требуется, часто в качестве неявного порядка атрибутов используется их порядок в линейной форме определения схемы отношения базы данных. То есть порядок формируется при определении схемы.\n\n> Каким образом тогда устанавливается порядок в кортеже?\n\nОдно и то же отношение может быть представлено разными таблицами, в которых столбцы идут в различном порядке. Иными словами таблицы, отличающиеся только порядком следования\nстолбцов, считаются эквивалентными. Схему отношений можно представить как некий класс, а кортеж как конкретный его экземпляр (инстанс/объект), который внутри содержит порядок соответствующий конкретному представлению (таблице).","topic_id":55140},{"creator":{"public_name":"Atlatnta Tesla","id":339552,"is_tutor":false},"id":117365,"body":"Спасибо!) Отличный и понятный ответ. \n\nНе знала, что такое *имя домена*.\nДля тех, кто тоже не знал:\n\n> Домен в реляционной модели данных — тип данных, то есть множество допустимых значений","topic_id":55140}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":21884,"title":"Немного запутанное упражнение, сказано что имя пользователя взято из другой таблицы, это навело меня на мысль что надо создать внешний ключ, ведь об этом была лекция. При этом пришлось редактировать файл init.sql так как имя там было не уникальным. В итоге все оказалось проще чем я думал.\n\nhttps://ru.hexlet.io/code_reviews/77173","plain_title":"Немного запутанное упражнение, сказано что имя пользователя взято из другой таблицы, это навело меня на мысль что надо создать внешний ключ, ведь об этом была лекция. При этом пришлось редактировать файл init.sql так как имя там было не уникальным. В итоге все оказалось проще чем я думал. https://ru.hexlet.io/code_reviews/77173 ","creator":{"public_name":"Artem Gorbounov","id":153667,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":46568,"body":"Чуть изменил ридми. Вообще в описании дается четкая структура таблицы, в этом курсе нет мест где нужно было бы придумывать и дополнять поля самостоятельно.","topic_id":21884}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":80964,"title":"Здравствуйте!\n\nМое решение https://ru.hexlet.io/code_reviews/837056 прошло на платформе. \n\nНо когда я таким же способом пытаюсь добавить записи в таблицу users через pgAdmin, у меня появляется ошибка:\n\nERROR: null value in column \"username\" of relation \"users\" violates not-null constraint\nDETAIL: Failing row contains (100, null, null, null, null, null, null, arya, null, null).\nSQL state: 23502\n\nПодскажите, в чем дело? ","plain_title":"Здравствуйте! Мое решение https://ru.hexlet.io/code_reviews/837056 прошло на платформе. Но когда я таким же способом пытаюсь добавить записи в таблицу users через pgAdmin, у меня появляется ошибка: ERROR: null value in column \"username\" of relation \"users\" violates not-null constraint DETAIL: Failing row contains (100, null, null, null, null, null, null, arya, null, null). SQL state: 23502 Подскажите, в чем дело? ","creator":{"public_name":"Дмитрий Рудченко","id":499410,"is_tutor":false},"comments":[{"creator":{"public_name":"Дмитрий Рудченко","id":499410,"is_tutor":false},"id":165945,"body":"Спасибо!","topic_id":80964},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":165832,"body":"Приветствую! Ошибка говорит о том, что в поле `username` попытались записать значение `NULL`, тогда как у этой колонки прописано ограничение NOT NULL. Ограничения рассматриваются далее в курсе: https://ru.hexlet.io/courses/rdb-basics/lessons/constraints/theory_unit","topic_id":80964}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":84355,"title":"Может кому то пригодиться, что бы добавить сразу несколько строк в таблицу можно использовать:\nINSERT INTO table1 (a, b, c) VALUES (1, 222, 333), (2, 555, 666), (3, 555, 333);","plain_title":"Может кому то пригодиться, что бы добавить сразу несколько строк в таблицу можно использовать: INSERT INTO table1 (a, b, c) VALUES (1, 222, 333), (2, 555, 666), (3, 555, 333); ","creator":{"public_name":"Никита Шелудяков","id":373922,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":170802,"body":"Приветствую, Никита! Спасибо за подсказку, так действительно можно добавить несколько записей одной командой. Аналогичный пример есть в уроке про вставку и модификацию данных:\n\n```\nINSERT INTO courses (name, slug) VALUES\n ('Bash', 'bash'), ('PHP', 'php'), ('Ruby', 'ruby');\n```","topic_id":84355}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}},{"id":22012,"title":"Я уже подзабыл было это в предыдущих уроках или нет, но значения для `INSERT` можно (и логичнее) перечислять через запятую: `VALUES (a1, a2, a3), (b1, b2, b3)`, соответственно, решение получается короче:\nhttps://ru.hexlet.io/code_reviews/78107\n\nИ ещё, если вставка значения для столбца `created_at` обязательна, то надо сделать тогда его `NOT NULL` и проверять в тесте.","plain_title":"Я уже подзабыл было это в предыдущих уроках или нет, но значения для INSERT можно (и логичнее) перечислять через запятую: VALUES (a1, a2, a3), (b1, b2, b3), соответственно, решение получается короче: https://ru.hexlet.io/code_reviews/78107 И ещё, если вставка значения для столбца created_at обязательна, то надо сделать тогда его NOT NULL и проверять в тесте. ","creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":46857,"body":"> И ещё, если вставка значения для столбца created_at обязательна, то надо сделать тогда его NOT NULL и проверять в тесте.\n\nКурсы это такая штука, где студенты изучают все что нужно постепенно. Ограничения рассматриваются позже.\n\n> Я уже подзабыл было это в предыдущих уроках или нет\n\nТакой вариант не давал, но добавлю.","topic_id":22012}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Реляционная модель данных","entity_url":null,"active":true}}],"lesson":{"exercise":null,"units":[{"id":2628,"name":"theory","url":"/courses/rdb-basics/lessons/relations/theory_unit"},{"id":2800,"name":"quiz","url":"/courses/rdb-basics/lessons/relations/quiz_unit"}],"links":[{"id":422877,"name":"Основы реляционной алгебры","url":"https://habr.com/post/145381/"},{"id":422878,"name":"Реляционная модель данных","url":"https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%BB%D1%8F%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%B0%D1%8F_%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85"}],"ordered_units":[{"id":2628,"name":"theory","url":"/courses/rdb-basics/lessons/relations/theory_unit"},{"id":2800,"name":"quiz","url":"/courses/rdb-basics/lessons/relations/quiz_unit"}],"id":1258,"slug":"relations","state":"approved","name":"Реляционная модель данных","course_order":450,"goal":"Говорим про фундамент, на котором стоит любая реляционная база данных","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Логика работы в реляционных СУБД строится на реляционной алгебре. Поэтому в подобных системах добавляют приставку «реляционная». Прикладному программисту необязательно разбираться в этой области алгебры, но знать основы полезно.\n\nВ этом уроке мы разберем способы представления данных и расскажем, почему реляционная модель подходит для этого лучше всего.\n\n## Способы представления данных\n\nДанные и как они хранятся на диске — две большие разницы. Физическое размещение данных на носителях — возможность конкретных СУБД. И в этом случае они соревнуются, кто быстрее и эффективнее.\n\nВнешнее представление — это то, что видит пользователь. Оно влияет на способ взаимодействия с данными. Поэтому разные способы представления данных называются **моделями**.\n\nЭти модели не отражают то, что происходит на физическом уровне. Они описывают, как данные структурированы, и как с ними взаимодействовать. Модели данных очень похожи на абстрактные типы данных, которые определяют интерфейс взаимодействия с типом и не определяют его внутреннюю реализацию.\n\nСуществует много разных способов представить одни и те же данные. В этом уроке мы разберем три самых популярных:\n\n* Иерархическая модель\n* Сетевая модель\n* Реляционная модель\n\nРазберем каждый способ подробнее.\n\n### Иерархическая модель\n\nВ **иерархической модели** данные представлены в виде дерева, где дочерние элементы находятся в зависимости от родительских:\n\n\n\nС помощью иерархической модели можно представить не только университет, но и составляющие бизнеса. К примеру, у сервиса такси есть такие понятия, как пользователь и заказ. У одного пользователя может быть множество заказов. Это сразу определяет структуру дерева:\n\n* Родительский элемент — пользователь\n* Дочерние элементы — заказы\n\nПодобным образом структурируются и все остальные части.\n\nПроблемы начинаются, когда у одного дочернего элемента может быть несколько родительских. Представим, что сервис такси добавил такую функцию — можно оплачивать счет совместно. Это значит, что у одного заказа сразу несколько клиентов.\n\nВ этом случае иерархическая модель не может предложить хорошего решения данной задачи. Придется создавать параллельные деревья, в которых появится дублирование данных. Эта проблема решается в сетевой модели данных, которую мы разберем далее.\n\n### Сетевая модель\n\n**Сетевая модель** данных расширяет иерархическую и позволяет иметь множество предков. Сетевая модель — это **граф**, у которого много вершин и соединений между ними:\n\n\n\nВ сетевой структуре каждый элемент может быть связан с любым другим элементом.\n\nНедостаток сетевой модели данных — высокая сложность и жесткость схемы БД, которая построена на ее основе. Поскольку логика процедуры выборки данных зависит от физической организации этих данных, то эта модель не является полностью независимой от приложения. Если необходимо изменить структуру данных, то нужно изменить и приложение.\n\nЧтобы не столкнуться с еще одной проблемой, программисты используют реляционную модель.\n\n### Реляционная модель\n\nНаибольшее распространение получила **реляционная модель** данных. На ее основе построены реляционные СУБД. В реляционной модели данные — это набор отношений. В алгебре понятие **отношение** звучит так:\n\n> Пусть дана совокупность типов данных T1, T2, ..., Tn, называемых также доменами, необязательно различных. Тогда n-арным отношением R, или отношением R степени n называют подмножество декартовa произведения множеств T1, T2, ..., Tn.\n\nРазберем это определение, чтобы лучше его понять.\n\n#### Что такое отношение в реляционной модели\n\nУ отношения нет физического представления. Реляционная база данных — это попытка отразить реляционную модель, а не ее точная копия.\n\nРеляционная модель опирается на раздел математики теорию множеств, которую нужно знать хотя бы немного. Множество — это совокупность произвольных элементов, которые объединены по некоторому признаку. Например, множество натуральных чисел или множество учеников одного класса. Изучить этот раздел подробнее вы можете в нашем курсе [«Теория множеств»](https://ru.hexlet.io/courses/set-theory).\n\nИз любого множества можно выделить **подмножество** — множество элементов, все элементы которого входят в исходное множество. Подмножество — это часть множества. Например, множество натуральных чисел — это подмножество по отношению к множеству целых чисел, которое в свою очередь — подмножество рациональных чисел. Из этого следует, что натуральные числа — это подмножество рациональных чисел.\n\nЕще одно важное понятие — **кортеж**. Это упорядоченный набор данных фиксированной длины. Элементами кортежа может быть все что угодно. Это математический способ представить некоторый набор связанных данных.\n\nНа основе этих понятий можно сформулировать более понятное определение отношения. Отношение — это множество кортежей, которые называются **телом отношения**. В нем каждый кортеж соответствует схеме.\n\n**Схема** — это заголовок отношения. Она описывает общую структуру кортежей, количество элементов внутри них и их типы. Каждый такой элемент называется **атрибутом**:\n\n\n\nОтношение визуально похоже на таблицу, но у него есть существенные отличия:\n\n* Нет двух одинаковых элементов (кортежей)\n* Порядок кортежей не определен\n* Порядок атрибутов в заголовке не определен\n\nПо этой причине таблица непригодна для точного описания отношения. В любой таблице порядок столбцов (атрибуты схемы) и строк (кортеж) строго определен. При этом на практике мы оперируем таблицами и не можем игнорировать их.\n\nВо всех реляционных базах данных столбцы расположены в определенном порядке, и данные тоже добавляются строго определенным образом. Но этот порядок зависит от реализации самой базы данных и не может быть задан, а задается только при выборке.\n\nРеляционная модель — удачный выбор в большинстве ситуаций. У нее нет недостатков, которые есть у других моделей. Но чтобы ее освоить, нужно время, так как придется научиться раскладывать данные по таблицам правильным способом. Чтобы взаимодействовать с данными, которые описаны реляционной моделью, используется реляционная алгебра. Ее элементы мы рассмотрим позже.\n\nДанные, представленные в реляционной модели, нужно привести к **нормальной форме** — это требования, которым должно удовлетворять отношение для минимизации избыточности данных, потенциально приводящих к логическим ошибкам.\n\n## Выводы\n\nВ следующих уроках мы познакомимся с тремя нормальными формами, так как они наиболее часто используются в реальной разработке. Причем программисты, которые часто работают с базами данных, даже не помнят теорию, связанную с формами.\n\nПонимая, как структурируются данные в реляционной модели, мозг самостоятельно предлагает правильные решения по тому, как разложить данные.\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":2631,"name":"theory","url":"/courses/rdb-basics/lessons/intro/theory_unit"}],"links":[],"ordered_units":[{"id":2631,"name":"theory","url":"/courses/rdb-basics/lessons/intro/theory_unit"}],"id":1261,"slug":"intro","state":"approved","name":"Введение","course_order":100,"goal":"Знакомимся с курсом","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"\n\nЛюбая нетривиальная программная система состоит минимум из двух компонентов:\n\n* Программного кода, отвечающего за логику работы\n* Хранилища, в котором содержатся данные, необходимые для работы\n\nВозьмем для примера Хекслет. Это большой контентный проект, внутри которого есть данные: например, курсы и их содержимое.\n\nБолее того, довольно много контента создается самими пользователями: они вводят данные при регистрации, создают и заполняют профили, описывают свои решения и переписываются с поддержкой через топики. Все эти данные непрерывно добавляются на сайт и только увеличиваются в объемах.\n\nПри этом данные нужно не только хранить, но и непрерывно считывать и показывать пользователям. Причем иногда в довольно хитрых формах, например: «Показать на странице испытания три последних код-ревью по этому испытанию, исключая код-ревью пользователя, который прямо сейчас смотрит на эту страницу».\n\nПодобные сложные запросы к системе хранения делаются ежесекундно, и многие из них значительно сложнее приведенного примера.\n\nКроме того, пользователи на сайтах работают независимо друг от друга, что создает конкуренцию при обращении к одним и тем же данным. А что, если один пользователь читает данные, которые в это время модифицируются другим пользователем?\n\nЗа реализацию всех этих возможностей отвечают **системы управления базами данных (СУБД)**. Как правило, они отвязаны от того языка программирования, на котором идет разработка. СУБД — это отдельная программа, которая умеет эффективно сохранять и читать то, что ее попросят.\n\nТаких систем существует довольно много, но это не значит, что все они абсолютно разные. Схожие системы делят на классы — множества систем со схожими характеристиками.\n\nЧаще всего используются **реляционные СУБД (РСУБД)** — системы, работа которых основана на **реляционной модели данных**. С технической точки зрения такие базы данных основаны на табличном представлении данных.\n\nДля работы с ними нужно понимать две основные вещи:\n\n* Реляционная модель данных — звучит страшно, но в итоге все сводится к таблицам\n* SQL — специализированный язык для управления базой данных и данными внутри нее\n\nОба пункта практически не зависят от реализации конкретной РСУБД. Изучив одну СУБД, вы крайне легко сможете переключиться на другую. В этом курсе мы рассмотрим популярную СУБД PostgreSQL. Она поставляется со специальной программой *psql*, которая представляет собой интерактивную оболочку — REPL. Через нее можно управлять PostgreSQL и взаимодействовать с базами данных, набирая команды в реальном времени.\n\n## Основные темы курса\n\nВ этом курсе мы затронем такие основные темы:\n\n* Установка и настройка\n* Создание и модификация базы данных (DDL)\n* Наполнение базы данных (DML)\n* Выборка данных (`SELECT`, `WHERE`, `ORDER`, `LIMIT`, `DISTINCT`, `GROUP`, `HAVING`)\n* Агрегирующие функции (`COUNT`)\n* Соединения (`JOIN`, `LEFT JOIN`)\n* Транзакции (уровни изоляции)\n* Реляционная алгебра (основы теории множеств)\n* Ключи (первичные, внешние)\n* Нормализация данных\n* Связи (один-к-одному, один-ко-многим, многие-ко-многим)\n* Производительность (индексы)\n\nВся практика в этом курсе выполняется в нашей среде, но если вы разработчик или вам это необходимо, то настройте базу данных локально для экспериментов. Эффективное обучение невозможно без повторения примеров из уроков в своей среде. Поэтому в начале курса необходимо установить PostgreSQL локально. Сделайте это по [инструкции](https://github.com/Hexlet/ru-instructions/blob/main/postgresql.md).\n"},"id":172,"slug":"rdb-basics","challenges_count":0,"name":"Основы реляционных баз данных","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"free","description":"На этом курсе вы изучите основы реляционных баз данных. Вы узнаете больше об архитектуре СУБД и языке SQL. В итоге вы научитесь создавать таблицы, добавлять, модифицировать и удалять данные. Курс пригодится, если вы решите использовать базу данных в вашем приложении или вам нужно использовать данные из базы в любых других местах. Знания из этого курса помогают выполнять запросы для выборки данных, объединять таблицы и использовать транзакции.","kind":"sandbox","updated_at":"2026-01-20T11:39:09.852Z","language":"sql","duration_cache":25500,"skills":["Создавать полноценные базы данных для приложений на любых языках","Правильно организовывать (нормализовать) архитектуру хранения данных с помощью нормальных форм","Отображать предметную область на таблицы с учетом связей между сущностями (o2o, o2m, m2m)","Выполнять запросы на выборку данных по сложным условиям"],"keywords":["postgresql","транзакции","нормальные формы","СУБД"],"lessons_count":24,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjA4MSwicHVyIjoiYmxvYl9pZCJ9fQ==--18d92b90e9f04ddc693b77ace032c133fb2dfdd5/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJqcGciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--39ba06fa99226096df9fc6bb31f84e1d29ea98e9/image.png"},"recommendedLandings":[],"lessonMemberUnit":null,"accessToLearnUnitExists":true,"accessToCourseExists":true},"url":"/courses/rdb-basics/lessons/relations/theory_unit","version":"0b0c6d4ebbd40fd58630a0dd89cc25544ccdf24e","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Основы реляционных баз данных</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Реляционная модель данных</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Реляционная модель данных","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"Основы реляционных баз данных"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>Логика работы в реляционных СУБД строится на реляционной алгебре. Поэтому в подобных системах добавляют приставку «реляционная». Прикладному программисту необязательно разбираться в этой области алгебры, но знать основы полезно.</p>
<p>В этом уроке мы разберем способы представления данных и расскажем, почему реляционная модель подходит для этого лучше всего.</p>
<h2 id="heading-2-1">Способы представления данных</h2>
<p>Данные и как они хранятся на диске — две большие разницы. Физическое размещение данных на носителях — возможность конкретных СУБД. И в этом случае они соревнуются, кто быстрее и эффективнее.</p>
<p>Внешнее представление — это то, что видит пользователь. Оно влияет на способ взаимодействия с данными. Поэтому разные способы представления данных называются <strong>моделями</strong>.</p>
<p>Эти модели не отражают то, что происходит на физическом уровне. Они описывают, как данные структурированы, и как с ними взаимодействовать. Модели данных очень похожи на абстрактные типы данных, которые определяют интерфейс взаимодействия с типом и не определяют его внутреннюю реализацию.</p>
<p>Существует много разных способов представить одни и те же данные. В этом уроке мы разберем три самых популярных:</p>
<ul>
<li>Иерархическая модель</li>
<li>Сетевая модель</li>
<li>Реляционная модель</li>
</ul>
<p>Разберем каждый способ подробнее.</p>
<h3 id="heading-3-2">Иерархическая модель</h3>
<p>В <strong>иерархической модели</strong> данные представлены в виде дерева, где дочерние элементы находятся в зависимости от родительских:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjA5NCwicHVyIjoiYmxvYl9pZCJ9fQ==--1586346f79f5b6274b2159918e17e606437e0ac8/hierarchical-dbms-model.jpg" alt="Иерархическая модель данных" loading="lazy"/></p>
<p>С помощью иерархической модели можно представить не только университет, но и составляющие бизнеса. К примеру, у сервиса такси есть такие понятия, как пользователь и заказ. У одного пользователя может быть множество заказов. Это сразу определяет структуру дерева:</p>
<ul>
<li>Родительский элемент — пользователь</li>
<li>Дочерние элементы — заказы</li>
</ul>
<p>Подобным образом структурируются и все остальные части.</p>
<p>Проблемы начинаются, когда у одного дочернего элемента может быть несколько родительских. Представим, что сервис такси добавил такую функцию — можно оплачивать счет совместно. Это значит, что у одного заказа сразу несколько клиентов.</p>
<p>В этом случае иерархическая модель не может предложить хорошего решения данной задачи. Придется создавать параллельные деревья, в которых появится дублирование данных. Эта проблема решается в сетевой модели данных, которую мы разберем далее.</p>
<h3 id="heading-3-3">Сетевая модель</h3>
<p><strong>Сетевая модель</strong> данных расширяет иерархическую и позволяет иметь множество предков. Сетевая модель — это <strong>граф</strong>, у которого много вершин и соединений между ними:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjA5NSwicHVyIjoiYmxvYl9pZCJ9fQ==--1d1fcd8ea1e1992dfaaff5142a15f6562abf4eb5/network-data-models.jpg" alt="Сетевая модель данных" loading="lazy"/></p>
<p>В сетевой структуре каждый элемент может быть связан с любым другим элементом.</p>
<p>Недостаток сетевой модели данных — высокая сложность и жесткость схемы БД, которая построена на ее основе. Поскольку логика процедуры выборки данных зависит от физической организации этих данных, то эта модель не является полностью независимой от приложения. Если необходимо изменить структуру данных, то нужно изменить и приложение.</p>
<p>Чтобы не столкнуться с еще одной проблемой, программисты используют реляционную модель.</p>
<h3 id="heading-3-4">Реляционная модель</h3>
<p>Наибольшее распространение получила <strong>реляционная модель</strong> данных. На ее основе построены реляционные СУБД. В реляционной модели данные — это набор отношений. В алгебре понятие <strong>отношение</strong> звучит так:</p>
<blockquote>
<p>Пусть дана совокупность типов данных T1, T2, ..., Tn, называемых также доменами, необязательно различных. Тогда n-арным отношением R, или отношением R степени n называют подмножество декартовa произведения множеств T1, T2, ..., Tn.</p>
</blockquote>
<p>Разберем это определение, чтобы лучше его понять.</p>
<h4 id="heading-4-5">Что такое отношение в реляционной модели</h4>
<p>У отношения нет физического представления. Реляционная база данных — это попытка отразить реляционную модель, а не ее точная копия.</p>
<p>Реляционная модель опирается на раздел математики теорию множеств, которую нужно знать хотя бы немного. Множество — это совокупность произвольных элементов, которые объединены по некоторому признаку. Например, множество натуральных чисел или множество учеников одного класса. Изучить этот раздел подробнее вы можете в нашем курсе <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://ru.hexlet.io/courses/set-theory" rel="noopener noreferrer" target="_blank">«Теория множеств»</a>.</p>
<p>Из любого множества можно выделить <strong>подмножество</strong> — множество элементов, все элементы которого входят в исходное множество. Подмножество — это часть множества. Например, множество натуральных чисел — это подмножество по отношению к множеству целых чисел, которое в свою очередь — подмножество рациональных чисел. Из этого следует, что натуральные числа — это подмножество рациональных чисел.</p>
<p>Еще одно важное понятие — <strong>кортеж</strong>. Это упорядоченный набор данных фиксированной длины. Элементами кортежа может быть все что угодно. Это математический способ представить некоторый набор связанных данных.</p>
<p>На основе этих понятий можно сформулировать более понятное определение отношения. Отношение — это множество кортежей, которые называются <strong>телом отношения</strong>. В нем каждый кортеж соответствует схеме.</p>
<p><strong>Схема</strong> — это заголовок отношения. Она описывает общую структуру кортежей, количество элементов внутри них и их типы. Каждый такой элемент называется <strong>атрибутом</strong>:</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjA5NywicHVyIjoiYmxvYl9pZCJ9fQ==--78df81452fa8179a15ed1273316a0736ec021ab8/relation.jpg" alt="Отношение" loading="lazy"/></p>
<p>Отношение визуально похоже на таблицу, но у него есть существенные отличия:</p>
<ul>
<li>Нет двух одинаковых элементов (кортежей)</li>
<li>Порядок кортежей не определен</li>
<li>Порядок атрибутов в заголовке не определен</li>
</ul>
<p>По этой причине таблица непригодна для точного описания отношения. В любой таблице порядок столбцов (атрибуты схемы) и строк (кортеж) строго определен. При этом на практике мы оперируем таблицами и не можем игнорировать их.</p>
<p>Во всех реляционных базах данных столбцы расположены в определенном порядке, и данные тоже добавляются строго определенным образом. Но этот порядок зависит от реализации самой базы данных и не может быть задан, а задается только при выборке.</p>
<p>Реляционная модель — удачный выбор в большинстве ситуаций. У нее нет недостатков, которые есть у других моделей. Но чтобы ее освоить, нужно время, так как придется научиться раскладывать данные по таблицам правильным способом. Чтобы взаимодействовать с данными, которые описаны реляционной моделью, используется реляционная алгебра. Ее элементы мы рассмотрим позже.</p>
<p>Данные, представленные в реляционной модели, нужно привести к <strong>нормальной форме</strong> — это требования, которым должно удовлетворять отношение для минимизации избыточности данных, потенциально приводящих к логическим ошибкам.</p>
<h2 id="heading-2-6">Выводы</h2>
<p>В следующих уроках мы познакомимся с тремя нормальными формами, так как они наиболее часто используются в реальной разработке. Причем программисты, которые часто работают с базами данных, даже не помнят теорию, связанную с формами.</p>
<p>Понимая, как структурируются данные в реляционной модели, мозг самостоятельно предлагает правильные решения по тому, как разложить данные.</p></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/rdb-basics/lessons/relations/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 24</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/rdb-basics/lessons/relations/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-CdBlNCiQ.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>