Запись без пары в выборке в 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 отбрасывает категорию
без товаров. LEFT JOIN сохраняет все строки
левой таблицы "categories", а для пустой
полки поле "sku" будет NULL.
После заполнения таблиц выполним
LEFT JOIN и выведем метку категории с
артикулом или словом "no sku". Для
"Empty shelf" проверка IsDBNull
на колонке артикула даст true. В консоли
будут строки "Tools | T-100" и
"Empty shelf | no sku":
using Microsoft.Data.Sqlite;
string dbPath = "left_catalog.db";
if (File.Exists(dbPath))
{
File.Delete(dbPath);
}
using SqliteConnection db = new($"Data Source={dbPath}");
db.Open();
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = """
CREATE TABLE categories (id INTEGER PRIMARY KEY, label TEXT NOT NULL);
CREATE TABLE products (id INTEGER PRIMARY KEY, category_id INTEGER, sku TEXT,
FOREIGN KEY (category_id) REFERENCES categories (id));
INSERT INTO categories (label) VALUES ('Tools'), ('Empty shelf');
INSERT INTO products (category_id, sku) VALUES (1, 'T-100');
""";
cmd.ExecuteNonQuery();
}
using SqliteCommand q = db.CreateCommand();
q.CommandText = """
SELECT c.label, p.sku
FROM categories c
LEFT JOIN products p ON p.category_id = c.id
ORDER BY c.id
""";
using SqliteDataReader r = q.ExecuteReader();
while (r.Read())
{
string label = r.GetString(0);
string sku = r.IsDBNull(1) ? "no sku" : r.GetString(1);
Console.WriteLine(label + " | " + sku);
}
Строка категории "Empty shelf" всё равно попадает в результат. Отдельный запрос с условием WHERE p.id IS NULL оставляет только пустые полки:
using Microsoft.Data.Sqlite;
using SqliteConnection db = new("Data Source=:memory:");
db.Open();
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = """
CREATE TABLE categories (id INTEGER PRIMARY KEY, label TEXT NOT NULL);
CREATE TABLE products (id INTEGER PRIMARY KEY, category_id INTEGER, sku TEXT);
INSERT INTO categories (label) VALUES ('Tools'), ('Empty shelf');
INSERT INTO products (category_id, sku) VALUES (1, 'T-100');
""";
cmd.ExecuteNonQuery();
}
using SqliteCommand q = db.CreateCommand();
q.CommandText = """
SELECT c.label
FROM categories c
LEFT JOIN products p ON p.category_id = c.id
WHERE p.id IS NULL
""";
using SqliteDataReader r = q.ExecuteReader();
r.Read();
Console.WriteLine(r.GetString(0)); // выведет "Empty shelf"
Создайте "left_routes.db" с маршрутами
и остановками. Маршрут "North line"
оставьте без остановок. Выведите его название
и текст "none", если остановки нет.
Создайте "left_teams.db" с таблицами
"teams" и "members". Добавьте
команду "Solo" без участников и выведите
её название вместе с "no member".