[Foutmelding] Verwijderen mislukt: Unknown column 'business_id' in 'where clause'

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Mohamed nvt

Mohamed nvt

30/07/2025 20:51:21
Quote Anchor link
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:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?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?
 
PHP hulp

PHP hulp

27/05/2026 13:51:26
 
Ivo P

Ivo P

30/07/2025 21:32:59
Quote Anchor link
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.
 
Mohamed nvt

Mohamed nvt

30/07/2025 22:22:17
Quote Anchor link
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
 
- Ariën  -
Beheerder

- Ariën -

30/07/2025 22:52:44
Quote Anchor link
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.
Gewijzigd op 30/07/2025 22:54:14 door - Ariën -
 
Mohamed nvt

Mohamed nvt

30/07/2025 23:12:36
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
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';
?>

 
Ivo P

Ivo P

30/07/2025 23:20:42
Quote Anchor link
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.
 
- Ariën  -
Beheerder

- Ariën -

30/07/2025 23:28:09
Quote Anchor link
Ik raad inderdaad eens aan om $query te echo'en.
 
Ward van der Put
Moderator

Ward van der Put

31/07/2025 07:59:56
Quote Anchor link
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.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
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.
}
?>


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.
 
Mohamed nvt

Mohamed nvt

03/08/2025 21:39:33
Quote Anchor link
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
 
Ivo P

Ivo P

03/08/2025 22:00:21
Quote Anchor link
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
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;


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.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.