Запись без пары в выборке в C++
Родителя без детей отбрасывает INNER JOIN,
если дочерних записей нет.
Все строки левой таблицы оставляет LEFT JOIN,
а поля правой заполняет NULL, если пара не
найдена. Категория без товаров все равно попадает
в результат, а артикул проверяют на пустоту:
#include <iostream>
#include <sqlite3.h>
int main() {
sqlite3* db = nullptr;
if (sqlite3_open("left_catalog.db", &db) != SQLITE_OK) {
std::cerr << sqlite3_errmsg(db) << "\n";
sqlite3_close(db);
return 1;
}
sqlite3_exec(
db, "PRAGMA foreign_keys = ON",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS categories ("
"id INTEGER PRIMARY KEY, label TEXT NOT NULL)",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS products ("
"id INTEGER PRIMARY KEY, category_id INTEGER NOT NULL, "
"sku TEXT NOT NULL, "
"FOREIGN KEY (category_id) REFERENCES categories (id))",
nullptr, nullptr, nullptr
);
sqlite3_stmt* category = nullptr;
sqlite3_prepare_v2(
db, "INSERT INTO categories (label) VALUES (?)",
-1, &category, nullptr
);
sqlite3_bind_text(category, 1, "Tools", -1, SQLITE_STATIC);
sqlite3_step(category);
sqlite3_reset(category);
sqlite3_bind_text(category, 1, "Empty shelf", -1, SQLITE_STATIC);
sqlite3_step(category);
sqlite3_finalize(category);
sqlite3_stmt* product = nullptr;
sqlite3_prepare_v2(
db,
"INSERT INTO products (category_id, sku) VALUES (?, ?)",
-1, &product, nullptr
);
sqlite3_bind_int(product, 1, 1);
sqlite3_bind_text(product, 2, "T-100", -1, SQLITE_STATIC);
sqlite3_step(product);
sqlite3_finalize(product);
sqlite3_stmt* sel = nullptr;
sqlite3_prepare_v2(
db,
"SELECT c.label, p.sku FROM categories c "
"LEFT JOIN products p ON p.category_id = c.id "
"ORDER BY c.id, p.id",
-1, &sel, nullptr
);
while (sqlite3_step(sel) == SQLITE_ROW) {
const char* label = reinterpret_cast<const char*>(
sqlite3_column_text(sel, 0)
);
std::cout << label << "\n";
if (sqlite3_column_type(sel, 1) == SQLITE_NULL) {
std::cout << "no sku\n";
} else {
const char* sku = reinterpret_cast<const char*>(
sqlite3_column_text(sel, 1)
);
std::cout << sku << "\n";
}
}
sqlite3_finalize(sel);
sqlite3_close(db);
return 0;
}
Строка с id 2 дает NULL
в sku. Тип колонки через
sqlite3_column_type подтверждает отсутствие
значения:
#include <iostream>
#include <sqlite3.h>
int main() {
sqlite3* db = nullptr;
if (sqlite3_open("left_null.db", &db) != SQLITE_OK) {
std::cerr << sqlite3_errmsg(db) << "\n";
sqlite3_close(db);
return 1;
}
sqlite3_exec(
db, "PRAGMA foreign_keys = ON",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS categories ("
"id INTEGER PRIMARY KEY, label TEXT NOT NULL)",
nullptr, nullptr, nullptr
);
sqlite3_exec(
db,
"CREATE TABLE IF NOT EXISTS products ("
"id INTEGER PRIMARY KEY, category_id INTEGER NOT NULL, "
"sku TEXT NOT NULL, "
"FOREIGN KEY (category_id) REFERENCES categories (id))",
nullptr, nullptr, nullptr
);
sqlite3_stmt* category = nullptr;
sqlite3_prepare_v2(
db, "INSERT INTO categories (label) VALUES (?)",
-1, &category, nullptr
);
sqlite3_bind_text(category, 1, "Empty shelf", -1, SQLITE_STATIC);
sqlite3_step(category);
sqlite3_finalize(category);
sqlite3_stmt* sel = nullptr;
sqlite3_prepare_v2(
db,
"SELECT c.label, p.sku FROM categories c "
"LEFT JOIN products p ON p.category_id = c.id "
"WHERE c.label = 'Empty shelf'",
-1, &sel, nullptr
);
if (sqlite3_step(sel) == SQLITE_ROW) {
bool empty = sqlite3_column_type(sel, 1) == SQLITE_NULL;
std::cout << (empty ? "true" : "false") << "\n";
}
sqlite3_finalize(sel);
sqlite3_close(db);
return 0;
}
В left_catalog.db добавьте категорию
"Spare" без товаров. Выведите ее
метку и "no sku", если артикул пуст.
Создайте left_teams.db с таблицами
teams и members. Одна команда
без участников должна появиться в выводе с
пустым именем участника.