Получение данных из связанных таблиц в C#
Примеры раздела используют SQLite через пакет в файле проекта:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.14" />
</ItemGroup>
</Project>
Запрос, который достанет всех юзеров вместе с их
городами, строят на команде
LEFT JOIN.
Ее синтаксис выглядит следующим образом:
SELECT поля FROM имя_таблицы
LEFT JOIN имя_связанной_таблицы ON условие_связи
WHERE условие_выборки
Разберем отдельные части синтаксиса этой команды.
Поля
В соединении * возвращает колонки всех
таблиц, а не только первой. Короткая запись
выглядит так:
SELECT *
Те же колонки записывают явно, поставив перед
* имя каждой таблицы:
SELECT users.*, cities.*
Либо перечисляют нужные поля с указанием имени таблицы перед ними:
SELECT users.name, cities.name
Эти два способа имеют проблему. Если поля
в таблицах имеют одинаковые имена, по имени
колонки остается первое поле. При чтении
через GetString по имени второе значение
с тем же именем уже не достать.
Для решения проблемы конфликтные имена
переименовывают через команду AS:
SELECT users.name, cities.name AS city_name
Связь
После команды ON указывают поля из двух
таблиц, по которым осуществляется связь. В этом
случае это поле "id" из таблицы с городами
и поле "city_id" из таблицы с юзерами:
ON cities.id = users.city_id
Запрос
В итоге запрос, который достанет юзеров вместе с их городами, будет выглядеть следующим образом:
SELECT
users.name, cities.name AS city_name
FROM
users
LEFT JOIN cities ON cities.id = users.city_id
Те же таблицы собирают в файле базы и кладут
туда город "city1" и юзера "user1"
со ссылкой на этот город:
using Microsoft.Data.Sqlite;
string dbPath = "gd_users.db";
if (File.Exists(dbPath))
{
File.Delete(dbPath);
}
using SqliteConnection db = new($"Data Source={dbPath}");
db.Open();
using (SqliteCommand pragma = db.CreateCommand())
{
pragma.CommandText = "PRAGMA foreign_keys = ON";
pragma.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "CREATE TABLE cities (id INTEGER PRIMARY KEY, name TEXT)";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, city_id INTEGER, FOREIGN KEY (city_id) REFERENCES cities (id))";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "INSERT INTO cities (name) VALUES ('city1')";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "INSERT INTO users (name, city_id) VALUES ('user1', 1)";
cmd.ExecuteNonQuery();
}
Пусть есть таблица с товарами и таблица с их категориями. Напишите запрос, который достанет названия товаров вместе с их категориями, и выполните его.