Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: ZAJDAN 17. 03. 2019, 14:37:57

Název: PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: ZAJDAN 17. 03. 2019, 14:37:57
Pokouším se v PHP PDO docílit aby se záznam před vložením zkontroloval zda již existuje, ale vkládá se mi i když existuje.
Mám podezdření, že špatně přiřazuji zástupný symbol v sql dotazu. Poradil by někdo?

Kód: [Vybrat]
$InsertArray = $_POST["Insert"];
$InsertDecoded = json_decode($InsertArray, true);

.....shortened
if(isset($_POST['Insert'])){
try     {
        $pdo = new PDO ( $induce, $user, $password, array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
        ));
//FIRSTLY FIND IF EXIST/////////////////////////////////////////////////////////////
        $prepared = $pdo->prepare(" SELECT * FROM kw112019 WHERE Commission = :Commission ");

                //přiřazení proměných do zástupných symbolů
        $prepared->bindParam(':Commission', $InsertDecoded["Commission"], PDO::PARAM_INT);

// zisk výsledků
        $result = $prepared->fetch(PDO::FETCH_NUM);

if ($result > 0) {
$json_array[] = array("Letter"=>"-", "Commission"=>"JIŽ EXISTUJE", "Status"=>"-", "DeliveryDate"=>"-");
$json = json_encode($json_array);
echo $json;
}

else {
//INSERT//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$prepared = $pdo->prepare("INSERT INTO kw112019 (Letter, Commission, Status, DeliveryDate)
                                                               VALUES (:Letter, :Commission, :Status, :DeliveryDate)");
$prepared->execute([
      'Commission' => $InsertDecoded["Commission"],
      'Letter' => $InsertDecoded["Letter"],
      'Status' => $InsertDecoded["Status"],
      'DeliveryDate' => $InsertDecoded["DeliveryDate"],
    ]);
      }
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: ZAJDAN 17. 03. 2019, 16:38:25
Vyřešeno,
zapoměl jsem v Selectu provést execute
$prepared->execute();
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Ondrej Nemecek 17. 03. 2019, 18:04:58
Pokud člověk neví, co je špatně, stačí to obvykle oddebugovat (xdebug) a podívat se, jaké dotazy se posílají do databáze (server umí dotazy logovat, tuším že to umí i pdo). Chybu pak člověk najde snadno sám... :)

Jinak některé databáze umí UPSERT resp. MERGE, tyto příkazy vloží nový záznam nebo jej aktualizují - podle toho zda, zda záznam už existuje.

Pak bych se ještě zamyslel, co se stane pokud bude ten váš vkládací kód spouštěn paralelně - a mezi ověřením existence a vložením se totožný záznam vloží z jiného requestu. Jinými slovy, chtělo by to synchronizovat aplikačně anebo transakcí. Abyste po nasazení nezjistil, že to vkládá nesmyslné údaje (což při testování jedním uživatelem nezjistíte a projeví se to až když je tam těch lidí víc).
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: ZAJDAN 17. 03. 2019, 20:24:08
Pak bych se ještě zamyslel, co se stane pokud bude ten váš vkládací kód spouštěn paralelně - a mezi ověřením existence a vložením se totožný záznam vloží z jiného requestu. Jinými slovy, chtělo by to synchronizovat aplikačně anebo transakcí. Abyste po nasazení nezjistil, že to vkládá nesmyslné údaje (což při testování jedním uživatelem nezjistíte a projeví se to až když je tam těch lidí víc).
díky za tip..rád se propracuju až k tomuto, ale zatím laboruju jen na výukové bázi

Ještě by mne zajímalo pokud mám v Ajaxu dataType: "json",
a v php vracím pomocí echa prostý text, jak s takovýmto response v Ajaxu zacházet v success?
Ajax bude i v response očekávat json?
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Ondrej Nemecek 17. 03. 2019, 22:38:52
Pokud máte datatype json tak z PHP posílejte taky json:

Kód: [Vybrat]
print(json_encode(array("text" => "tohle je ten text")));
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: ZAJDAN 18. 03. 2019, 15:27:34
Pokud máte datatype json tak z PHP posílejte taky json:

Kód: [Vybrat]
print(json_encode(array("text" => "tohle je ten text")));
Díky!
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: BoneFlute 18. 03. 2019, 20:42:49
Ještě by mne zajímalo pokud mám v Ajaxu dataType: "json",
a v php vracím pomocí echa prostý text, jak s takovýmto response v Ajaxu zacházet v success?
Ajax bude i v response očekávat json?
Nebude. Pokud se nebude pokoušet o nějakou automagii. A i kdyby ano, tak si třeba na textu vyláme zuby (pokud se zrovna netrefíte na Null, False, True, možná číslo).

Pokud máte datatype json tak z PHP posílejte taky json:

Kód: [Vybrat]
print(json_encode(array("text" => "tohle je ten text")));

Teoreticky by to nemělo stačit. Ještě je důležité posílat hlavičku:
Kód: [Vybrat]
header("Content-Type: application/json");
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Ondrej Nemecek 18. 03. 2019, 20:58:59
Pokud máte datatype json tak z PHP posílejte taky json:

Kód: [Vybrat]
print(json_encode(array("text" => "tohle je ten text")));

Teoreticky by to nemělo stačit. Ještě je důležité posílat hlavičku:
Kód: [Vybrat]
header("Content-Type: application/json");

To je pravda, dík za doplnění. Ono když se to děje v nějakém frameworku automaticky tak na to člověk časem zapomene  :D

Když něco nefunguje je potřeba se stejně podívat v prohlížeči, jaké tam běhají http dotazy a co píše konzole prohlížeče (vývojové nástroje - F12)...
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Kit 19. 03. 2019, 07:45:41
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: ZAJDAN 19. 03. 2019, 09:18:43
moc díky za rady!
ohledně té duplicity, tady jsem se asi špatně vyjádřil. Já chci jen zamezit aby sloupec neobsahoval dva a více řádků se stejnou hodnotou.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Ondrej Nemecek 19. 03. 2019, 09:31:08
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.

Tak předpokládám, že tam ten index je. Ale zaprvé tam nebudu cpát duplicitní data a generovat zbytečně chyby v databázi (byť bych si je třeba v php odchytil) a zadruhé chci asi nějak zjistit a zobrazit stav transakce - třeba uživateli nebo to někam zalogovat.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Kit 19. 03. 2019, 12:21:34
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.

Tak předpokládám, že tam ten index je. Ale zaprvé tam nebudu cpát duplicitní data a generovat zbytečně chyby v databázi (byť bych si je třeba v php odchytil) a zadruhé chci asi nějak zjistit a zobrazit stav transakce - třeba uživateli nebo to někam zalogovat.

Unikátní index splňuje vše, co je zmíněno.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: ZAJDAN 19. 03. 2019, 14:34:45
Kite...díky..nechám si od zkušených jako Ty rád doporučit správný postup, ale domnívám se, že primární klíč nezajistí aby se do sloupce  nedostal stejný záznam/hodnota. Pokud se mýlím, tak pak nechápu ten princip.

Pravděpodobně máš na mysli, že hodnotu co chci kontrolovat by byla primárním klíčem.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Kit 19. 03. 2019, 15:38:57
Kite...díky..nechám si od zkušených jako Ty rád doporučit správný postup, ale domnívám se, že primární klíč nezajistí aby se do sloupce  nedostal stejný záznam/hodnota. Pokud se mýlím, tak pak nechápu ten princip.

Pravděpodobně máš na mysli, že hodnotu co chci kontrolovat by byla primárním klíčem.

Primární klíč je automaticky unikátním podle definice. Mám na mysli sekundární indexy, které můžeš vytvořit ke kterémukoli sloupci nebo skupině sloupců, u kterých potřebuješ zajistit unikátnost. Zároveň pomáhají při vyhledávání záznamů.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: BoneFlute 19. 03. 2019, 16:09:41
Kite...díky..nechám si od zkušených jako Ty rád doporučit správný postup, ale domnívám se, že primární klíč nezajistí aby se do sloupce  nedostal stejný záznam/hodnota. Pokud se mýlím, tak pak nechápu ten princip.

Pravděpodobně máš na mysli, že hodnotu co chci kontrolovat by byla primárním klíčem.

S oblibou mám složené primární klíče nad více sloupci. Pokud to dává z logiky věci smysl nebo tomu nebrání něco jiného. Pokud to nejde, tak tam přihodím unikátní klíč. Tím mám zajištěno, že mi to bude hlídat databáze - což upřednostňuju.

Například můžu mít PK nad všemi čtyřmi sloupci: Letter, Commission, Status, DeliveryDate. Což ale samozřejmě nebude to co chci, protože pak mi tam vleze stejný Letter + Commission díky tomu, že se to bude lišit třeba Statusem.
Takže se zamyslím nad tím, co chci:
Letter může být duplicitní, když se liší Commission, jinak ne. Takže udělám PK Letter + Commission.
Pak nechci duplicity nad Statusem, takže přidám UQ Letter + Commission + Status a UQ Letter + Commission + Status + DeliveryDate.
- Nebo naopak UQ Letter + Commission + Status a UQ Letter + Commission + DeliveryDate.
- Nebo jen UQ Letter + Commission + Status + DeliveryDate.

Všechno záleží na logice těch dat. Ale mělo by to jít vyjádřit tak jak jsem naznačil.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Ondrej Nemecek 19. 03. 2019, 19:17:26
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.

Tak předpokládám, že tam ten index je. Ale zaprvé tam nebudu cpát duplicitní data a generovat zbytečně chyby v databázi (byť bych si je třeba v php odchytil) a zadruhé chci asi nějak zjistit a zobrazit stav transakce - třeba uživateli nebo to někam zalogovat.

Unikátní index splňuje vše, co je zmíněno.

Jak?
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Kit 20. 03. 2019, 07:04:56
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.

Tak předpokládám, že tam ten index je. Ale zaprvé tam nebudu cpát duplicitní data a generovat zbytečně chyby v databázi (byť bych si je třeba v php odchytil) a zadruhé chci asi nějak zjistit a zobrazit stav transakce - třeba uživateli nebo to někam zalogovat.

Unikátní index splňuje vše, co je zmíněno.

Jak?

Tím, že neumožní duplicitní záznam vložit ani externím nástrojem.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Ondrej Nemecek 21. 03. 2019, 00:31:14
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.

Tak předpokládám, že tam ten index je. Ale zaprvé tam nebudu cpát duplicitní data a generovat zbytečně chyby v databázi (byť bych si je třeba v php odchytil) a zadruhé chci asi nějak zjistit a zobrazit stav transakce - třeba uživateli nebo to někam zalogovat.

Unikátní index splňuje vše, co je zmíněno.

Jak?

Tím, že neumožní duplicitní záznam vložit ani externím nástrojem.

Takže tam pak budeš z aplikace insertovat záznamy s existujícím id a je podle tebe vše v pořádku?
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: RastikJ 21. 03. 2019, 08:37:13
Ak spravne nastaveny primary alebo uniqe key, tak vsetko vyriesi toto https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html (https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html)
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Kit 21. 03. 2019, 09:28:46
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.

Tak předpokládám, že tam ten index je. Ale zaprvé tam nebudu cpát duplicitní data a generovat zbytečně chyby v databázi (byť bych si je třeba v php odchytil) a zadruhé chci asi nějak zjistit a zobrazit stav transakce - třeba uživateli nebo to někam zalogovat.

Unikátní index splňuje vše, co je zmíněno.

Jak?

Tím, že neumožní duplicitní záznam vložit ani externím nástrojem.

Takže tam pak budeš z aplikace insertovat záznamy s existujícím id a je podle tebe vše v pořádku?

O vkládání duplicitních ID vůbec není řeč. Přečti si původní dotaz.
Název: Re:PHP PDO - SQL Insert pouze když záznam neexistuje
Přispěvatel: Ondrej Nemecek 21. 03. 2019, 14:04:23
Stačí nastavit v databázi unikátní index a duplicitní záznam se nevloží. Select pak nebude potřebný a atomicita operace bude zajištěna.

Tak předpokládám, že tam ten index je. Ale zaprvé tam nebudu cpát duplicitní data a generovat zbytečně chyby v databázi (byť bych si je třeba v php odchytil) a zadruhé chci asi nějak zjistit a zobrazit stav transakce - třeba uživateli nebo to někam zalogovat.

Unikátní index splňuje vše, co je zmíněno.

Jak?

Tím, že neumožní duplicitní záznam vložit ani externím nástrojem.

Takže tam pak budeš z aplikace insertovat záznamy s existujícím id a je podle tebe vše v pořádku?

O vkládání duplicitních ID vůbec není řeč. Přečti si původní dotaz.

Ok, už to vidím, jemu se ten duplicitní záznam vložil, čímž pádem chápu tvojí reakci. Takže řešení je tam prostě přidat správný unikátní klíč (nejspíš primární) a na straně aplikace použít transakce.