[Foutmelding] Verwijderen mislukt: Unknown column 'business_id' in 'where clause'
Hallo allemaal,
Met behulp van ChatGPT ben ik een webapplicatie aan het maken, en bij het verwijderen van een bestaande record waarbij sommige tabellen nu leeg zijn, verschijnt telkens bovenstaande foutmelding.
Helaas kom ik niet verder met ChatGPT en hopelijk kunnen jullie een inzicht geven of een richting geven waar ik het kan gaan zoeken
De code van dashboard pagina, sorry het is een lange pagina:
Met behulp van ChatGPT ben ik een webapplicatie aan het maken, en bij het verwijderen van een bestaande record waarbij sommige tabellen nu leeg zijn, verschijnt telkens bovenstaande foutmelding.
Helaas kom ik niet verder met ChatGPT en hopelijk kunnen jullie een inzicht geven of een richting geven waar ik het kan gaan zoeken
De code van dashboard pagina, sorry het is een lange pagina:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
session_start();
require_once 'includes/config.php';
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
header("Location: index.php");
exit();
}
function getUserStatusBadge($status) {
$badgeConfig = [
'active' => ['success', 'Actief'],
'disabled' => ['danger', 'Uitgeschakeld'],
'onhold' => ['warning', 'Nog niet geactiveerd'],
'inactive' => ['secondary', 'Inactief'],
'archived' => ['dark', 'Gearchiveerd']
];
$config = $badgeConfig[$status] ?? ['secondary', 'Onbekend'];
return '<span class="badge bg-'.$config[0].'">'.$config[1].'</span>';
}
// Functie om te controleren of een kolom bestaat in een tabel
function kolomBestaat($mysqli, $tabel, $kolom) {
$result = $mysqli->query("SHOW COLUMNS FROM `$tabel` LIKE '$kolom'");
return $result && $result->num_rows > 0;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$user_id = intval($_POST['user_id'] ?? 0);
if (isset($_POST['toggle_disable_user'])) {
$new_status = $mysqli->query("SELECT IF(status = 'disabled', 'active', 'disabled') AS new_status FROM users WHERE id = $user_id")->fetch_assoc()['new_status'];
$stmt = $mysqli->prepare("UPDATE users SET status = ? WHERE id = ?");
$stmt->bind_param("si", $new_status, $user_id);
$stmt->execute();
$_SESSION['success'] = "Status gebruiker #$user_id aangepast naar " . ucfirst($new_status);
} elseif (isset($_POST['archive_user'])) {
$mysqli->begin_transaction();
try {
$mysqli->query("UPDATE users SET status = 'archived', deleted_at = NOW() WHERE id = $user_id");
$mysqli->query("UPDATE businesses SET owner_id = NULL WHERE owner_id = $user_id");
$mysqli->commit();
$_SESSION['success'] = "Gebruiker #$user_id gearchiveerd";
} catch (Exception $e) {
$mysqli->rollback();
$_SESSION['error'] = "Archiveren mislukt: " . $e->getMessage();
}
} elseif (isset($_POST['delete_user'])) {
$mysqli->begin_transaction();
try {
error_log("START: Verwijder gebruiker #$user_id");
$businessResult = $mysqli->query("SELECT id FROM businesses WHERE owner_id = $user_id");
while ($business = $businessResult->fetch_assoc()) {
$business_id = $business['id'];
error_log("Gevonden business_id: $business_id");
// Tabel-kolom mapping
$tabelNamen = [
"appointments" => "business_id",
"transactions" => "business_id",
"inventory" => "business_id",
"locations" => "business_id",
"services" => "business_id",
"customers" => "business_id"
];
error_log("
[size=xsmall][i]Toevoeging op 30/07/2025 20:52:37:[/i][/size]
Ik wil foto's van de tabellen laten zien, maar kan blijkbaar geen foto's hier toevoegen?
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
session_start();
require_once 'includes/config.php';
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
header("Location: index.php");
exit();
}
function getUserStatusBadge($status) {
$badgeConfig = [
'active' => ['success', 'Actief'],
'disabled' => ['danger', 'Uitgeschakeld'],
'onhold' => ['warning', 'Nog niet geactiveerd'],
'inactive' => ['secondary', 'Inactief'],
'archived' => ['dark', 'Gearchiveerd']
];
$config = $badgeConfig[$status] ?? ['secondary', 'Onbekend'];
return '<span class="badge bg-'.$config[0].'">'.$config[1].'</span>';
}
// Functie om te controleren of een kolom bestaat in een tabel
function kolomBestaat($mysqli, $tabel, $kolom) {
$result = $mysqli->query("SHOW COLUMNS FROM `$tabel` LIKE '$kolom'");
return $result && $result->num_rows > 0;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$user_id = intval($_POST['user_id'] ?? 0);
if (isset($_POST['toggle_disable_user'])) {
$new_status = $mysqli->query("SELECT IF(status = 'disabled', 'active', 'disabled') AS new_status FROM users WHERE id = $user_id")->fetch_assoc()['new_status'];
$stmt = $mysqli->prepare("UPDATE users SET status = ? WHERE id = ?");
$stmt->bind_param("si", $new_status, $user_id);
$stmt->execute();
$_SESSION['success'] = "Status gebruiker #$user_id aangepast naar " . ucfirst($new_status);
} elseif (isset($_POST['archive_user'])) {
$mysqli->begin_transaction();
try {
$mysqli->query("UPDATE users SET status = 'archived', deleted_at = NOW() WHERE id = $user_id");
$mysqli->query("UPDATE businesses SET owner_id = NULL WHERE owner_id = $user_id");
$mysqli->commit();
$_SESSION['success'] = "Gebruiker #$user_id gearchiveerd";
} catch (Exception $e) {
$mysqli->rollback();
$_SESSION['error'] = "Archiveren mislukt: " . $e->getMessage();
}
} elseif (isset($_POST['delete_user'])) {
$mysqli->begin_transaction();
try {
error_log("START: Verwijder gebruiker #$user_id");
$businessResult = $mysqli->query("SELECT id FROM businesses WHERE owner_id = $user_id");
while ($business = $businessResult->fetch_assoc()) {
$business_id = $business['id'];
error_log("Gevonden business_id: $business_id");
// Tabel-kolom mapping
$tabelNamen = [
"appointments" => "business_id",
"transactions" => "business_id",
"inventory" => "business_id",
"locations" => "business_id",
"services" => "business_id",
"customers" => "business_id"
];
error_log("
[size=xsmall][i]Toevoeging op 30/07/2025 20:52:37:[/i][/size]
Ik wil foto's van de tabellen laten zien, maar kan blijkbaar geen foto's hier toevoegen?
De foutmelding spreekt voor zich:
Er wordt een query gebruikt (uit de context: een delete-query) die een WHERE heeft waarin iets staat als "business_id = 123"
Maar de betreffende tabel heeft geen kolom business_id....
Grappig is wel: dat staat niet in jouw script hierboven.
Er wordt een query gebruikt (uit de context: een delete-query) die een WHERE heeft waarin iets staat als "business_id = 123"
Maar de betreffende tabel heeft geen kolom business_id....
Grappig is wel: dat staat niet in jouw script hierboven.
De betreffende kolom bestaat wel hoor.
Zie hieronder de output van alle tabellen:
SHOW COLUMNS FROM appointments
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
customer_id bigint(20) unsigned NO MUL NULL
staff_id bigint(20) unsigned YES MUL NULL
service_id bigint(20) unsigned NO MUL NULL
date_time timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
status varchar(50) YES confirmed
created_at timestamp NO CURRENT_TIMESTAMP
updated_at timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
deleted_at datetime YES NULL
location_id bigint(20) unsigned YES MUL NULL
business_id bigint(20) unsigned NO MUL NULL
========================================================================
SHOW COLUMNS FROM businesses
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
name varchar(100) NO UNI NULL
business_type enum('kapper','schoonheidssalon') YES kapper
address text YES NULL
created_at datetime YES CURRENT_TIMESTAMP
updated_at datetime YES CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
status enum('active','inactive') YES active
owner_id bigint(20) unsigned NO MUL NULL
deleted_at datetime YES NULL
=======================================================================
SHOW COLUMNS FROM customers
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
name varchar(100) NO NULL
email varchar(100) YES NULL
phone varchar(15) YES NULL
preferences text YES NULL
deleted_at datetime YES NULL
business_id bigint(20) unsigned NO MUL NULL
===========================================================================
SHOW COLUMNS FROM inventory
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
business_id bigint(20) unsigned NO MUL NULL
name varchar(100) NO NULL
quantity int(11) YES 0
price_per_unit decimal(10,2) YES NULL
deleted_at datetime YES NULL
location_id bigint(20) unsigned YES MUL NULL
=========================================================================
SHOW COLUMNS FROM locations
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
business_id bigint(20) unsigned NO MUL NULL
naam varchar(255) NO NULL
adres varchar(255) NO NULL
postcode varchar(20) NO NULL
stad varchar(100) NO NULL
land varchar(100) NO NULL
created_at timestamp NO CURRENT_TIMESTAMP
updated_at timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
deleted_at datetime YES NULL
=================================================================================
SHOW COLUMNS FROM services
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
name varchar(100) NO NULL
duration int(11) NO NULL
price decimal(10,2) NO NULL
deleted_at datetime YES NULL
business_id bigint(20) unsigned NO MUL NULL
================================================================================
SHOW COLUMNS FROM transactions
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
user_id bigint(20) unsigned YES MUL NULL
business_id bigint(20) unsigned NO MUL NULL
customer_id bigint(20) unsigned YES MUL NULL
amount decimal(10,2) NO NULL
discount_percentage decimal(5,2) YES 0.00
final_amount decimal(10,2) NO NULL
payment_method enum('cash','card','online') NO NULL
created_at timestamp NO CURRENT_TIMESTAMP
deleted_at datetime YES NULL
appointment_id bigint(20) unsigned YES MUL NULL
==================================================================================
SHOW COLUMNS FROM users
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
voornaam varchar(100) NO NULL
achternaam varchar(100) NO NULL
email varchar(100) NO UNI NULL
mobielnummer varchar(15) NO UNI NULL
password_hash varchar(255) NO NULL
role enum('admin','owner','employee') NO NULL
created_at timestamp NO CURRENT_TIMESTAMP
updated_at timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
status enum('onhold','active','inactive','archived','disa... NO onhold
verification_status tinyint(1) YES 0
verification_token varchar(255) YES NULL
deleted_at datetime YES NULL
last_login datetime YES MUL NULL
profiel_foto varchar(255) YES NULL
reset_token varchar(255) YES NULL
reset_expires datetime YES NULL
pending_email varchar(100) YES NULL
verification_token_email varchar(255) YES NULL
token_expires_at_email datetime YES NULL
====================================================================================
SHOW COLUMNS FROM user_locations
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
user_id bigint(20) unsigned NO MUL NULL
location_id bigint(20) unsigned YES MUL NULL
Zie hieronder de output van alle tabellen:
SHOW COLUMNS FROM appointments
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
customer_id bigint(20) unsigned NO MUL NULL
staff_id bigint(20) unsigned YES MUL NULL
service_id bigint(20) unsigned NO MUL NULL
date_time timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
status varchar(50) YES confirmed
created_at timestamp NO CURRENT_TIMESTAMP
updated_at timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
deleted_at datetime YES NULL
location_id bigint(20) unsigned YES MUL NULL
business_id bigint(20) unsigned NO MUL NULL
========================================================================
SHOW COLUMNS FROM businesses
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
name varchar(100) NO UNI NULL
business_type enum('kapper','schoonheidssalon') YES kapper
address text YES NULL
created_at datetime YES CURRENT_TIMESTAMP
updated_at datetime YES CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
status enum('active','inactive') YES active
owner_id bigint(20) unsigned NO MUL NULL
deleted_at datetime YES NULL
=======================================================================
SHOW COLUMNS FROM customers
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
name varchar(100) NO NULL
email varchar(100) YES NULL
phone varchar(15) YES NULL
preferences text YES NULL
deleted_at datetime YES NULL
business_id bigint(20) unsigned NO MUL NULL
===========================================================================
SHOW COLUMNS FROM inventory
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
business_id bigint(20) unsigned NO MUL NULL
name varchar(100) NO NULL
quantity int(11) YES 0
price_per_unit decimal(10,2) YES NULL
deleted_at datetime YES NULL
location_id bigint(20) unsigned YES MUL NULL
=========================================================================
SHOW COLUMNS FROM locations
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
business_id bigint(20) unsigned NO MUL NULL
naam varchar(255) NO NULL
adres varchar(255) NO NULL
postcode varchar(20) NO NULL
stad varchar(100) NO NULL
land varchar(100) NO NULL
created_at timestamp NO CURRENT_TIMESTAMP
updated_at timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
deleted_at datetime YES NULL
=================================================================================
SHOW COLUMNS FROM services
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
name varchar(100) NO NULL
duration int(11) NO NULL
price decimal(10,2) NO NULL
deleted_at datetime YES NULL
business_id bigint(20) unsigned NO MUL NULL
================================================================================
SHOW COLUMNS FROM transactions
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
user_id bigint(20) unsigned YES MUL NULL
business_id bigint(20) unsigned NO MUL NULL
customer_id bigint(20) unsigned YES MUL NULL
amount decimal(10,2) NO NULL
discount_percentage decimal(5,2) YES 0.00
final_amount decimal(10,2) NO NULL
payment_method enum('cash','card','online') NO NULL
created_at timestamp NO CURRENT_TIMESTAMP
deleted_at datetime YES NULL
appointment_id bigint(20) unsigned YES MUL NULL
==================================================================================
SHOW COLUMNS FROM users
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
voornaam varchar(100) NO NULL
achternaam varchar(100) NO NULL
email varchar(100) NO UNI NULL
mobielnummer varchar(15) NO UNI NULL
password_hash varchar(255) NO NULL
role enum('admin','owner','employee') NO NULL
created_at timestamp NO CURRENT_TIMESTAMP
updated_at timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
status enum('onhold','active','inactive','archived','disa... NO onhold
verification_status tinyint(1) YES 0
verification_token varchar(255) YES NULL
deleted_at datetime YES NULL
last_login datetime YES MUL NULL
profiel_foto varchar(255) YES NULL
reset_token varchar(255) YES NULL
reset_expires datetime YES NULL
pending_email varchar(100) YES NULL
verification_token_email varchar(255) YES NULL
token_expires_at_email datetime YES NULL
====================================================================================
SHOW COLUMNS FROM user_locations
Field Type Null Key Default Extra
id bigint(20) unsigned NO PRI NULL auto_increment
user_id bigint(20) unsigned NO MUL NULL
location_id bigint(20) unsigned YES MUL NULL
Hoe ziet die query er dan uit? Ik zie die niet in je script staan?
Als ik een goede tip mag geven: Zet nooit je rollen in een sessie, maar haal ze direct op.
Als ik een goede tip mag geven: Zet nooit je rollen in een sessie, maar haal ze direct op.
Gewijzigd op 30/07/2025 22:54:14 door - Ariën -
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
error_log("???? Actieve database: " . $mysqli->query("SELECT DATABASE()")->fetch_row()[0]);
foreach ($tabelNamen as $tabel => $kolom) {
$tabel = trim($tabel);
$kolom = trim($kolom);
// Check of kolom bestaat in de tabel
$result = $mysqli->query("SHOW COLUMNS FROM `$tabel` LIKE '$kolom'");
if ($result && $result->num_rows > 0) {
$query = "DELETE FROM `$tabel` WHERE `$kolom` = $business_id";
error_log("? Uitvoeren query: $query");
if (!$mysqli->query($query)) {
error_log("? MYSQL ERROR bij $tabel: " . $mysqli->error);
}
} else {
error_log("?? Kolom '$kolom' bestaat niet in tabel '$tabel'");
}
}
$mysqli->query("DELETE FROM businesses WHERE id = $business_id");
}
// Overige user-data verwijderen
$mysqli->query("DELETE FROM user_locations WHERE user_id = $user_id");
if (kolomBestaat($mysqli, "appointments", "customer_id") && kolomBestaat($mysqli, "appointments", "staff_id")) {
$mysqli->query("DELETE FROM appointments WHERE customer_id = $user_id OR staff_id = $user_id");
}
if (kolomBestaat($mysqli, "transactions", "user_id")) {
$mysqli->query("DELETE FROM transactions WHERE user_id = $user_id");
}
$mysqli->query("DELETE FROM users WHERE id = $user_id");
$mysqli->commit();
$_SESSION['success'] = "Gebruiker #$user_id en alle gekoppelde gegevens zijn succesvol verwijderd.";
} catch (Exception $e) {
$mysqli->rollback();
error_log("FOUT: " . $e->getMessage());
$_SESSION['error'] = "Verwijderen mislukt: " . $e->getMessage();
}
}
header("Location: dashboard.php");
exit();
}
$query = "SELECT u.*,
(SELECT COUNT(*) FROM businesses b WHERE b.owner_id = u.id) AS business_count
FROM users u
WHERE u.role != 'admin' AND u.status != 'archived'";
$result = $mysqli->query($query);
require_once 'includes/header.php';
?>
foreach ($tabelNamen as $tabel => $kolom) {
$tabel = trim($tabel);
$kolom = trim($kolom);
// Check of kolom bestaat in de tabel
$result = $mysqli->query("SHOW COLUMNS FROM `$tabel` LIKE '$kolom'");
if ($result && $result->num_rows > 0) {
$query = "DELETE FROM `$tabel` WHERE `$kolom` = $business_id";
error_log("? Uitvoeren query: $query");
if (!$mysqli->query($query)) {
error_log("? MYSQL ERROR bij $tabel: " . $mysqli->error);
}
} else {
error_log("?? Kolom '$kolom' bestaat niet in tabel '$tabel'");
}
}
$mysqli->query("DELETE FROM businesses WHERE id = $business_id");
}
// Overige user-data verwijderen
$mysqli->query("DELETE FROM user_locations WHERE user_id = $user_id");
if (kolomBestaat($mysqli, "appointments", "customer_id") && kolomBestaat($mysqli, "appointments", "staff_id")) {
$mysqli->query("DELETE FROM appointments WHERE customer_id = $user_id OR staff_id = $user_id");
}
if (kolomBestaat($mysqli, "transactions", "user_id")) {
$mysqli->query("DELETE FROM transactions WHERE user_id = $user_id");
}
$mysqli->query("DELETE FROM users WHERE id = $user_id");
$mysqli->commit();
$_SESSION['success'] = "Gebruiker #$user_id en alle gekoppelde gegevens zijn succesvol verwijderd.";
} catch (Exception $e) {
$mysqli->rollback();
error_log("FOUT: " . $e->getMessage());
$_SESSION['error'] = "Verwijderen mislukt: " . $e->getMessage();
}
}
header("Location: dashboard.php");
exit();
}
$query = "SELECT u.*,
(SELECT COUNT(*) FROM businesses b WHERE b.owner_id = u.id) AS business_count
FROM users u
WHERE u.role != 'admin' AND u.status != 'archived'";
$result = $mysqli->query($query);
require_once 'includes/header.php';
?>
Probeer ook de query zelf in je foutmelding te zetten.
Maar ik zie een heel rare methode om on the fly uit te vinden of je tabel wel een kolom X bevat, om daarna een delete query uit te voeren.
Ik vind dat je er vanuit mag gaan dat JIJ weet hoe je tabellen uitzien en dat deze dus echt die kolom bevat.
Dat mag je dus gewoon hard in je code zetten.
Als je kolom soms ontbreekt, is er iets anders grondig mis met je data-opbouw.
Maar ik zie een heel rare methode om on the fly uit te vinden of je tabel wel een kolom X bevat, om daarna een delete query uit te voeren.
Ik vind dat je er vanuit mag gaan dat JIJ weet hoe je tabellen uitzien en dat deze dus echt die kolom bevat.
Dat mag je dus gewoon hard in je code zetten.
Als je kolom soms ontbreekt, is er iets anders grondig mis met je data-opbouw.
Ik raad inderdaad eens aan om $query te echo'en.
Je hebt de relaties in de database niet goed ingesteld. Je probeert nu in een while-loop alle records van een bepaalde business-ID te verwijderen.
Die ‘mapping’ van de business-ID in andere tabellen is overbodig als je een ON DELETE CASCADE toevoegt aan tabeldefinities. Je hebt dan nog maar één DELETE-query nodig: die verwijdert vervolgens automatisch alle afhankelijke rijen met dezelfde ID uit andere tabellen.
Zie bijvoorbeeld:
https://www.mysqltutorial.org/mysql-basics/mysql-on-delete-cascade/
ChatGPT begrijpt talen, maar doorziet abstractere logica zoals een genormaliseerd database-ontwerp vaak slecht. Je zult daarvoor echt zelf aan de bak moeten.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// Selecteer `businesses.id`: de kolom `id` in de tabel `businesses`
$businessResult = $mysqli->query("SELECT id FROM businesses WHERE owner_id = $user_id");
while ($business = $businessResult->fetch_assoc()) {
// `$business_id` is één waarde van de kolom `businesses.id`
$business_id = $business['id'];
// Tabel-kolom mapping
$tabelNamen = [
"appointments" => "business_id",
"transactions" => "business_id",
"inventory" => "business_id",
"locations" => "business_id",
"services" => "business_id",
"customers" => "business_id"
];
// etc.
}
?>
// Selecteer `businesses.id`: de kolom `id` in de tabel `businesses`
$businessResult = $mysqli->query("SELECT id FROM businesses WHERE owner_id = $user_id");
while ($business = $businessResult->fetch_assoc()) {
// `$business_id` is één waarde van de kolom `businesses.id`
$business_id = $business['id'];
// Tabel-kolom mapping
$tabelNamen = [
"appointments" => "business_id",
"transactions" => "business_id",
"inventory" => "business_id",
"locations" => "business_id",
"services" => "business_id",
"customers" => "business_id"
];
// etc.
}
?>
Die ‘mapping’ van de business-ID in andere tabellen is overbodig als je een ON DELETE CASCADE toevoegt aan tabeldefinities. Je hebt dan nog maar één DELETE-query nodig: die verwijdert vervolgens automatisch alle afhankelijke rijen met dezelfde ID uit andere tabellen.
Zie bijvoorbeeld:
https://www.mysqltutorial.org/mysql-basics/mysql-on-delete-cascade/
ChatGPT begrijpt talen, maar doorziet abstractere logica zoals een genormaliseerd database-ontwerp vaak slecht. Je zult daarvoor echt zelf aan de bak moeten.
Dankjewel allemaal voor jullie feedback, maar ik snap het niet goed.
Als je kijkt naar mijn database design, dan zie je op 2 tabellen na, een ouder => kinderen constructie.
Ben benieuwd waarom deze constructie niet klopt?
En wat moet ik (laten) veranderen aan de bovenstaande query, zodat het optimaal is/werkt?
Bedankt voor het meedenken
Als je kijkt naar mijn database design, dan zie je op 2 tabellen na, een ouder => kinderen constructie.
Ben benieuwd waarom deze constructie niet klopt?
En wat moet ik (laten) veranderen aan de bovenstaande query, zodat het optimaal is/werkt?
Bedankt voor het meedenken
Bedoel je dat je in al die tabellen een kolom business_id hebt opgenomen?
Of bedoel je, wat Ward bedoelt, dat je ook aan de database verteld hebt dat het nummer dat in die kolom staat verwijst naar het ID in de tabel Businesses?
Als je dat namelijk doet, dan kan zo'n parent niet verwijderd worden zonder dat het kind eerst verwijderd wordt. óf je stelt die on-cascade in, en dan heeft verwijderen van een parent tot gevold dat al zijn kinderen ook verwijderd worden.
Toevoeging op 03/08/2025 22:14:04:
Voorbeeld:
TEXT is trouwens wel erg groot om een adres in op te slaan.
En een INT kan 2,147,483,647 bevatten.
Dat lijkt me meer dan genoeg voor een beetje normale webapp. Maar goed: het is in elk geval voor de FK relaties belangrijk dat het type veld gelijk is voor parent en child.
Of bedoel je, wat Ward bedoelt, dat je ook aan de database verteld hebt dat het nummer dat in die kolom staat verwijst naar het ID in de tabel Businesses?
Als je dat namelijk doet, dan kan zo'n parent niet verwijderd worden zonder dat het kind eerst verwijderd wordt. óf je stelt die on-cascade in, en dan heeft verwijderen van een parent tot gevold dat al zijn kinderen ook verwijderd worden.
Toevoeging op 03/08/2025 22:14:04:
Voorbeeld:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
CREATE TABLE businesses (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL UNIQUE,
business_type ENUM('kapper','schoonheidssalon') DEFAULT 'kapper',
address TEXT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
status ENUM('active','inactive') DEFAULT 'active',
owner_id BIGINT(20) UNSIGNED NOT NULL,
deleted_at DATETIME NULL,
PRIMARY KEY (id)
-- Eventueel FOREIGN KEY (owner_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE services (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
duration INT(11) NOT NULL,
price DECIMAL(10,2) NOT NULL,
deleted_at DATETIME NULL,
business_id BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (id),
CONSTRAINT fk_services_business
FOREIGN KEY (business_id) REFERENCES businesses(id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL UNIQUE,
business_type ENUM('kapper','schoonheidssalon') DEFAULT 'kapper',
address TEXT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
status ENUM('active','inactive') DEFAULT 'active',
owner_id BIGINT(20) UNSIGNED NOT NULL,
deleted_at DATETIME NULL,
PRIMARY KEY (id)
-- Eventueel FOREIGN KEY (owner_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE services (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
duration INT(11) NOT NULL,
price DECIMAL(10,2) NOT NULL,
deleted_at DATETIME NULL,
business_id BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (id),
CONSTRAINT fk_services_business
FOREIGN KEY (business_id) REFERENCES businesses(id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
TEXT is trouwens wel erg groot om een adres in op te slaan.
En een INT kan 2,147,483,647 bevatten.
Dat lijkt me meer dan genoeg voor een beetje normale webapp. Maar goed: het is in elk geval voor de FK relaties belangrijk dat het type veld gelijk is voor parent en child.




