insert_id
If we perform an INSERT or UPDATE on a table with an AUTO_INCREMENT field, we can get the ID of the last inserted/updated record immediately: $last_id = $conn->insert_id;
Mijn testcode wordt dan :
$db = openDB(); // OO-functie de db-connectie afhandelt, werkt foutloos
if ($pid === 9999) $p = $db->query($qInsert); // zonder pid
else $p = $db->query($qUpdate); // met de optie WHERE pid='$pid'
$pid = $db->insert_id; // ZOU in allebei de gevallen de laatste AI-waarde moeten geven ?
$db->close();
print $pid; // geeft 0 dus waarschijnlijk NULL
Heeft iemand enig idee wat ik fout doe?
Laat de daadwerkelijke code eens zien.
if (isset($_POST['opslaan'])) {
$id = $_SESSION['id'];
$aanspreek = $_POST['aanspreek'];
$voornaam = ucfirst($_POST['voornaam']);
$voorletters = strtoupper($_POST['voorletters']);
$tussenvoeg = strtolower($_POST['tussenvoeg']);
$achternaam = ucfirst($_POST['achternaam']);
$straat = ucwords($_POST['straat']);
$postcode = strtoupper($_POST['postcode']);
$plaats = strtoupper($_POST['plaats']);
$telefoon = $_POST['telefoon'];
$mobiel = $_POST['mobiel'];
$email = $_POST['email'];
$gebdat = $_POST['gebdat'];
$categorie = ucfirst($_POST['categorie']);
$opmerking = $_POST['opmerking'];
$qInsert = " insert into naw
( aanspreek, voornaam, voorletters, tussenvoeg,
achternaam, straat, postcode, plaats, telefoon, mobiel,
email, gebdat, categorie, opmerking ) values
( '$aanspreek', '$voornaam', '$voorletters',
'$tussenvoeg', '$achternaam', '$straat', '$postcode',
'$plaats', '$telefoon', $mobiel', '$email', '$gebdat',
'$categorie', '$opmerking' ) ";
$qUpdate = " update naw set
aanspreek='$aanspreek', voornaam='$voornaam', voorletters='$voorletters',
tussenvoeg='$tussenvoeg', achternaam='$achternaam', straat='$straat',
postcode='$postcode', plaats='$plaats', telefoon='$telefoon',
mobiel='$mobiel', email='$email', gebdat='$gebdat',
categorie='$categorie', opmerking='$opmerking'
where id='$id' ";
$db = openDB();
if ($id === 9999)
$p = $db->query($qInsert);
else
$p = $db->query($qUpdate);
$id = $db->insert_id;
$db->close();
print $id;
}
Doe eens een echo $_SESSION['id'];
print $id = 0
print $_SESSION['id'] = 1037 (bestaand record)
Het bestaande record wordt ook netjes gewijzigd.
Dus MySQLI lijkt verder foutloos verlopen.
09999
print $id = 0
print $_SESSION['id'] = 9999 (aanduiding voor nieuw record dat nog een AI moet krijgen)
Gewijzigd op 18/09/2016 20:18:04 door Paul Ulje
Quote:
The mysqli_insert_id() function returns the ID generated by a query on a table with a column having the AUTO_INCREMENT attribute. If the last query wasn't an INSERT or UPDATE statement or if the modified table does not have a column with the AUTO_INCREMENT attribute, this function will return zero.
01069Gewoon nul
09999Gewoon nul
De kolom id heeft wel degelijk een A_I status en is primaire sleutel.
Zou het helpen om bij het opslaan wél de id dan wel een explicite NULL mee te geven?
Update: nee, dat maakt niets uit.
Overigens is deze code, op het insert_id en OO verandering na, al meer dan 15 jaar tot volle tevredenheid in gebruik. De reden om insert_id toe te voegen is om de gelegenheid te hebben onvolledige records in te voegen. Voorheen zocht ik de laaste gewoon opnieuw op met SELECT op 'voornaam' 'achternaam' en 'plaats'.
Gewijzigd op 18/09/2016 20:47:01 door Paul Ulje
Zeker de INSERT zou het insert_id moeten teruggeven.
Normaliter zoek ik al gauw een omweg als ik een probleem niet snap.
Maar die zag ik nu even niet voor de hand liggen.
Wat ik me nu net bedenk is het volgende:
function getMaxAI() {
$db = openDB();
$p = $db->query(" select * from naw order by id desc ");
$row = $p->fetch_row(); // dat is het record met 9999
$row = $p->fetch_row();
$id=$row[0];
$db->close();
return $id;
}
En het werkt!
Nogmaals erg bedankt!
Gewijzigd op 18/09/2016 21:23:24 door Paul Ulje
Ehm nee, niet doen. Je kan er niet vanuit gaan dat je dan het juiste id krijgt. De enige correcte manier na een insert is insert_id gebruiken, en bij een update weet je deze al.
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
$db = openDB(); // OO-functie de db-connectie afhandelt, werkt foutloos
if ($pid === 9999) {
$p = $db->query($qInsert); // zonder pid
$pid = $db->insert_id; // ZOU in allebei de gevallen de laatste AI-waarde moeten geven ?
}
else $p = $db->query($qUpdate); // met de optie WHERE pid='$pid'
$db->close();
print $pid; // geeft 0 dus waarschijnlijk NULL
if ($pid === 9999) {
$p = $db->query($qInsert); // zonder pid
$pid = $db->insert_id; // ZOU in allebei de gevallen de laatste AI-waarde moeten geven ?
}
else $p = $db->query($qUpdate); // met de optie WHERE pid='$pid'
$db->close();
print $pid; // geeft 0 dus waarschijnlijk NULL
Volgens mij werkt insert_id niet bij een update omdat daarbij de update al bestaat.
Waarom dan niet $id = null
Ben van Velzen op 18/09/2016 21:25:00:
Ehm nee, niet doen. Je kan er niet vanuit gaan dat je dan het juiste id krijgt. De enige correcte manier na een insert is insert_id gebruiken, en bij een update weet je deze al.
Helemaal mee eens. Als het misgaat is dit bovendien een draak van een bug om op te sporen. Het kan misgaan als twee verschillende clients tegelijkertijd een record invoegen. In plaats van het id van het record dat je zelf invoegde, kun je dan het id van de andere client krijgen. Veel plezier met het uitzoeken waarom meneer Jansen ineens van Lelystad naar Delfzijl is verhuisd. ;-)
Wat je wel zou kunnen doen is een SELECT LAST_INSERT_ID(). Die geeft het id van het laatst ingevoegde id voor de betreffende db-connectie en heeft dus geen last van concurrent inserts.
Paul Ulje op 18/09/2016 19:44:07:
if ($pid === 9999)
Paul Ulje op 18/09/2016 20:15:52:
09999
Paul Ulje op 18/09/2016 20:43:03:
09999Gewoon nul
09999 !== 9999
Gewijzigd op 19/09/2016 02:25:27 door Ward van der Put
De functie getMaxID() is een OMWEG voor het FALENDE insert_id, de oorzaak van deze draad.
De door MySQL doorgenummerde A_I nummers komen in een veld genaamd ID.
- Wanneer een nieuw record wordt ingevoegd komt er dus een nieuw ID. Dát nummer wil ik weten.
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
<?php
function getMaxAI() {
$db = openDB();
$p = $db->query(" select * from naw order by id desc ");
$row = $p->fetch_row();
$id=$row[0];
$db->close();
return $id;
}
?>
function getMaxAI() {
$db = openDB();
$p = $db->query(" select * from naw order by id desc ");
$row = $p->fetch_row();
$id=$row[0];
$db->close();
return $id;
}
?>
En dat werkt naar volle tevredenheid.
Toevoeging op 19/09/2016 14:23:29:
Ivo P op 19/09/2016 00:22:18:
Je weet dat na 9998 inserts er een record gaat komen met id 9999?
Waarom dan niet $id = null
Waarom dan niet $id = null
:-) Ja, dat is een restant uit de jaren 70-80 toen '9' en '99' e.d. standaard de 'afsluit' codes waren. Let wel, er waren nog geen knoppen, geen muis, alleen een toetsenbord. Ik zal het veranderen.... Bedankt!
Ward:
Graag voortaan bij code de [code][/code]-tags gebruiken.
Hier kun je meer lezen over de mogelijke opmaakcodes.
Alvast bedankt!
Hier kun je meer lezen over de mogelijke opmaakcodes.
Alvast bedankt!
Gewijzigd op 19/09/2016 15:22:10 door Ward van der Put
1. Client A haalt de hoogste id op.
2. Client B voegt een record toe en verhoogt de id.
3. Client A werkt met een verouderde hoogste id.
Verder vraagt je query nu de gehele tabel op. Dit kun je beperken tot de id van de laatste record:
Gewijzigd op 19/09/2016 15:26:58 door Ward van der Put
En dat terwijl de oorzaak gewoon ergens foutief gebruik is. Zoals gezegd: je gebruikt insert_id vlak na je INSERT query, bij UPDATE e.d. weet je het ID al, dus heb je dit niet nodig. Daarnaast zijn er *geen* omwegen voor insert_id, ja, hooguit binnen een transactie je complete table locken, inserten en *dan* opvragen. Maakt je applicatie wel retetraag uiteraard omdat je dan alle andere toegangen tot de table verbiedt. Kort gezegd: wat je doet werkt niet en kan ook niet werken.
getMaxID() lijkt mij niet de juiste weg. Jouw database heeft zelf oneindig veel betere functionaliteit om zelf te bepalen welk auto-increment id deze moet toewijzen aan een nieuw record.
En wat @Ward zegt: op het moment dat twee verschillende gebruikers "tegelijkertijd" iets met getMaxID() doen ben je nat. Tenzij je doet wat @Ben voorstelt: iets met transacties, maar dat is voortborduren op een verkeerde ontwerpbeslissing.
Uiteraard maak ik graag gebruik van MySql A_I en dat werkt probleemloos.
Mijn programma is een eeuwenoud privé programma, waarschijnlijk heb ik het oorspronkelijk in dBase en vervolgens in Clipper gemaakt. Na de omzetting in PHP, vermoedelijk om PHP 'te proeven' jarenlang over het Web ongestoord gebruikt.
Nu wil ik alleen direct na het TOEgevoegen het 'id'-nummer dat automagisch is toegevoegd gebruiken (uitlezen, niet toevoegen). En dat lukt me niet met insert_id.
Dan maar eromheen.
Er is (bijna) altijd een omweg.
In dit geval eigenlijk heel eenvoudig.
(Vroeguh, toen er nog geen DB voor de voor-PC was, moesten we altijd zelf een 'nummertjesapparaat' bouwen).
Maar terecht gezegd: niet elegant.
En elegantie (Pascal!) is voor mij belangrijk. :-(
In de beginjaren van IBM/MSDos deed ik overigens weinig anders dan omwegen verzinnen voor de gebreken.
Een ieder hartelijk bedankt voor de goede raad en steun!
Ik voel me helemaal thuis in dit forum.
Nu snel een nieuw PHP probleem zoeken.... :-)
Paul Ulje op 21/09/2016 15:08:59:
Dan maar eromheen.
Er is (bijna) altijd een omweg.
In dit geval eigenlijk heel eenvoudig.
Er is (bijna) altijd een omweg.
In dit geval eigenlijk heel eenvoudig.
Inderdaad eenvoudig: SELECT LAST_INSERT_ID(). Maar absoluut niet "select * [...] order by id desc" want vroeg of laat ga je daarmee een keer de bietenbrug op. En het erge is dat je dat vaak nog niet eens merkt tot het te laat is om de boel te herstellen. Het enige wat je dan nog kan doen is je hele database weggooien en overnieuw beginnen.
Gewijzigd op 21/09/2016 15:51:23 door Willem vp
Er is bijna altijd een omweg, correct. Maar die omweg hangt wel af van je begrip van waar je mee werkt. Een oplossing zoals je probeerde duidt duidelijk op een onbegrip, gezien de race conditions die je daar altijd mee veroorzaakt. Je kunt dan de omweg van Willem beter gebruiken, of zoals eerder gezegd je code herzien zodat je alleen het id uit de database vraagt bij een insert.