Соединение связанных таблиц в 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>
Когда данные разнесены по таблицам, для отчёта
нужны поля с обеих сторон. INNER JOIN
оставляет только строки, где внешний ключ
"dept_id" совпал с "id" отдела.
Создадим отдел Support и двух сотрудников, затем
выполним соединение. В консоли ожидаются две
строки вида "Support | Alice Gray" и
"Support | Ben Holt":
using Microsoft.Data.Sqlite;
string dbPath = "join_staff.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 departments (id INTEGER PRIMARY KEY, title TEXT NOT NULL)";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "CREATE TABLE staff (id INTEGER PRIMARY KEY, dept_id INTEGER NOT NULL, full_name TEXT NOT NULL, FOREIGN KEY (dept_id) REFERENCES departments (id))";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "INSERT INTO departments (title) VALUES ('Support')";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "INSERT INTO staff (dept_id, full_name) VALUES (1, 'Alice Gray'), (1, 'Ben Holt')";
cmd.ExecuteNonQuery();
}
using SqliteCommand q = db.CreateCommand();
q.CommandText = """
SELECT d.title, s.full_name
FROM staff s
INNER JOIN departments d ON s.dept_id = d.id
ORDER BY s.full_name
""";
using SqliteDataReader r = q.ExecuteReader();
while (r.Read())
{
Console.WriteLine(r.GetString(0) + " | " + r.GetString(1));
}
Псевдонимы "s" и "d" сокращают имена
таблиц в SELECT. Фильтр по отделу задают в
WHERE после соединения: сотрудник из
"Archive" не попадёт в вывод, если оставить
только "Support". В консоли останется
"Alice Gray":
using Microsoft.Data.Sqlite;
using SqliteConnection db = new("Data Source=:memory:");
db.Open();
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = """
CREATE TABLE departments (id INTEGER PRIMARY KEY, title TEXT NOT NULL);
CREATE TABLE staff (id INTEGER PRIMARY KEY, dept_id INTEGER NOT NULL, full_name TEXT NOT NULL);
INSERT INTO departments (title) VALUES ('Support'), ('Archive');
INSERT INTO staff (dept_id, full_name) VALUES (1, 'Alice Gray'), (2, 'Cara Mint');
""";
cmd.ExecuteNonQuery();
}
using SqliteCommand q = db.CreateCommand();
q.CommandText = """
SELECT s.full_name
FROM staff s
INNER JOIN departments d ON s.dept_id = d.id
WHERE d.title = 'Support'
""";
using SqliteDataReader r = q.ExecuteReader();
r.Read();
Console.WriteLine(r.GetString(0)); // выведет "Alice Gray"
В базе "join_shifts.db" заведите смену
"Night" и работников "Iva Sol"
и "Ken Orth". Выведите имя работника
и название смены одной строкой на человека.
Создайте "join_fleet.db" с таблицами
"garages" и "vehicles". Выведите
номер машины и код гаража для каждой пары.
В "join_fleet.db" оставьте в выводе
только машины гаража с кодом "G-7".