Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ Przedszkole _ [MySQL]Dodawanie rekordu jeżeli nie istnieje

Napisany przez: Dukov 4.11.2018, 13:51:54

Tak jak w temacie, chcę dodać do bazy rekord, jeżeli ten nie istnieje, a jeżeli istnieje zwrócić false, próbowałem już setki rozwiązań z stackoverflow i za każdym razem wywala błąd

  1. SELECT CASE WHEN EXISTS (
  2. SELECT *
  3. FROM users
  4. WHERE login = :login
  5. OR
  6. mail = :mail
  7. )
  8. THEN
  9. INSERT INTO users (login,mail,name,city,avatar,ip_addr,reg_date,last_log_date,active,permissions,famous,rang,banned,warns) VALUES (:login,:mail,:password,0,0,"$ip","$date",0,0,0,0,0,0,0, ))
  10. ELSE
  11. CAST(0 AS BIT) END

albo to:
  1. INSERT INTO users (login,mail,password,name,city,avatar,ip_addr,reg_date,last_log_date,active,permissions,famous,rang,banned,warns) VALUES (:login,:mail,:password,0,0,0,"$ip","$date",0,0,0,0,0,0,0 )
  2. SELECT DISTINCT login
  3. FROM users
  4. WHERE
  5. NOT EXISTS (SELECT 1 FROM users
  6. WHERE login = :login)
  7.  
  8.  
  9.  
  10.  
  11.  

Napisany przez: viking 4.11.2018, 13:59:55

Złap wyjątek dla insert i zamień sobie wtedy odpowiedź na false.

Napisany przez: Dukov 4.11.2018, 14:03:01

A możesz nieco jaśniej? Bazy danych to zdecydowanie nie jest moja mocna strona, zresztą dlatego teraz pisze, żeby podszlifować umiejętności.

Napisany przez: viking 4.11.2018, 14:34:48

  1. try {
  2. zapytanie insert które w przypadku zduplikowania danych (maila lub loginu) zwróci wyjątek
  3. } catch (\PDOException $e) {
  4. return false;
  5. }

Napisany przez: Dukov 4.11.2018, 14:53:54

No dobrze, rozumiem o co chodzi, tylko jak mam zwrócić ten wyjątek. zresztą wolałbym zrobić to w jednym zapytaniu, bo mam obiekt z metodami odnoszącymi się do bazy danych, a w tych metodach chcę tylko dołaczać zapytanie jako file_get_contents, żeby nie było pomieszanych zapytań z PHP, bo będzie to nieczytelne.
Konkretnie mam wysyłany json przez ajax do pliku controller.php, w nim switcha i dołączanie odpowiednicyh plików, jeżeli dane przejdą przez walidacje, to tworzy obiekt wspomnianej bazy danych, a zapytania są w folderze queries.

Napisany przez: viking 4.11.2018, 15:12:20

Sposób dołączania zapytania nie ma żadnego znaczenia. Błędne zapytanie spowodfuje automatyczne rzucenie wyjątku - dla PDO $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Napisany przez: vokiel 4.11.2018, 16:15:45

Nie wystarczy

Kod
INSERT IGNORE ...
?

A jeśli już z łapaniem Exception, to trzeba sprawdzić jaki to jest wyjątek - żeby w ten sam sposób nie obsługiwać wszystkich.

Napisany przez: viking 4.11.2018, 16:19:29

Czyli według Ciebie lepsze będzie zignorowanie? To wygląda na rejestrację. Nie ma znaczenia jaki błąd sypnie baza. Ważny jest efekt końcowy czyli brak rekordu.

Napisany przez: mmmmmmm 5.11.2018, 08:45:00

Wytłumaczę ci najprościej jak się da. Baza danych porównuje zbiory. Zbiór twoich danych wejściowych (daną wejściową jest rekord) ze zbiorem danych z tabeli.
Utwórz sobie taki zbiór i go go porównaj z tabelą. Jesli go nie znajdzie, to wtedy dodaj.
Czyli po kolei
Utworzenie zbioru jednoelementowego:

  1. SELECT :login AS login, :mail AS mail, :password AS pass, :ip AS ip, :DATA AS date

Teraz sprawdzasz, czy danych zbiór istnieje. Warunkiem istnienia jest klucz, czyli w tym przypadku login. Jak najłatwiej sprawdzić? Połączyć lewostronnie po kluczu i sprawdzić, czy w drugiej tabeli znalazł dany rekord.
  1. SELECT * FROM
  2. (SELECT :login AS login, :mail AS mail, :password AS pass, :ip AS ip, :DATA AS date) AS sub
  3. LEFT JOIN
  4. users AS u
  5. ON u.login=sub.login
  6. WHERE
  7. u.login IS NULL

Jeśli zapytanie zwróci ci jakikolwiek rekord (a może zwrócić tylko jeden), to wtedy dodajesz go do `users`. Zapytanie jest o tyle bezpieczne, że możesz je wykonywać ile razy chcesz - rekord doda się tylko raz (bo za każdą następną próbą już będzie)
  1. INSERT INTO users(login, mail, pass, ip, date)
  2. SELECT sub.* FROM
  3. (SELECT :login AS login, :mail AS mail, :password AS pass, :ip AS ip, :DATA AS date) AS sub
  4. LEFT JOIN
  5. users AS u
  6. ON u.login=sub.login
  7. WHERE
  8. u.login IS NULL

Napisany przez: Pyton_000 5.11.2018, 10:44:13

Ło matko.. najlepiej jak by napisać do tego jeszcze jakiś mikroserwis który będzie to sprawdzał...


Do Autora tematu. Załóż 2 indeksy Unique w Bazie na pola `email` i `username` i wykonuj normalny INSERT bez żadnych pierdoł.

W przypadku próbu wrzucenia rekordu nie unikalnego po prostu się nie stworzy a PDO wyrzuci Exceprion który musisz złapać.

Tu masz przykład:

Kod
try {
  $stmt = $db->prepare("INSERT INTO tbl_user (id, name, password, question, answer)    VALUES (NULL, :name, :password, :question, :answer)");
  $stmt->bindValue(":name", $_POST['name']);
  $stmt->bindValue(":password", $_POST['password']);
  $stmt->bindValue(":question", $_POST['question']);
  $stmt->bindValue(":answer", $_POST['answer']);
  $stmt->execute();
  echo "Successfully added the new user " . $_POST['name'];
} catch (PDOException $e) {
  echo "DataBase Error: The user could not be added.<br>".$e->getMessage();
} catch (Exception $e) {
  echo "General Error: The user could not be added.<br>".$e->getMessage();
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)