Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MYSQL] IF NOT EXISTS
Forum PHP.pl > Forum > Bazy danych > MySQL
Tomplus
Witam,

Mam pytanie,

Chciałem skrócić kod i wpadłem na pomysł że to co mogę w paru liniach zrobić w PHP mogę w jednej linii zrobić w MYSQL, ale.... coś nie wychodzi.

Mam nast. zapytanie SQL:
Kod
IF NOT EXISTS
     SELECT `uid`,`link` FROM `link_logs` WHERE `uid` = '67' AND `link` = '0'
  THEN
     INSERT INTO `link_logs` (`uid`, `link`) VALUES ('67', '0')
END IF;


wypróbowałem też zapytanie bez IF:

Kod
INSERT INTO `sm_link_logs` (`uid`, `link`) VALUES ('67', '0')
  WHERE
    NOT EXISTS (
      SELECT `uid`,`link` FROM `sm_link_logs` WHERE `uid` = '67' AND `link` = '0'
    );


Wg. tego co się dowiedziałem to w ten sposób powinno wyglądać zapytanie.
Jednak nie pojawia się żaden błąd MySQL (co sugeruje mi że nie ma błędu parsera w zapytaniu) ale jest błąd logiczny bo mimo że tabela jest pusta, Nie pojawia się nowa liniia.

z założenia jest że jeżeli nie istnieje uid i link o podanych wartościach to ma stworzyć nową wartość w tabeli o takich wartościach.

Wiedzę na ten temat znalazłem tu:
http://forums.mysql.com/read.php?98,33383,33784#msg-33784 oraz
http://lists.mysql.com/replication/220

Prosiłbym o pomoc przy tym zapytaniu.
trafas
Witam,

W mysql EXISTS tak prosto się nie używa.
Generalnie raczej wykorzystywane jest w procedurach.

Dla sprawdzenia czy dany wiersz istnieje w tabeli bez proedury możesz wykonać zapytanie:

  1. SELECT IF(NOT EXISTS
  2. (`uid`,`link` FROM `link_logs` WHERE `uid` = '67' AND `link` = '0'),
  3. 'INSERT', -- wartość jeżeli warunek jest spełniony
  4. 'wiersz istnieje' -- wartość jeżeli warunek jest spełniony
  5. );



W przypadku użycia procedury:


  1. DELIMITER //
  2. CREATE PROCEDURE sprawdz(IN uid_in INT, IN link_in varchar(30))
  3. BEGIN
  4.  
  5. IF NOT EXISTS (SELECT 1 FROM `sm_link_logs` WHERE `uid` = uid_in AND `link` = link_in)
  6. THEN
  7. INSERT INTO `link_logs` (`uid`, `link`) VALUES (uid_in, link_in)
  8. ELSE
  9. SELECT 'rekord już istnieje' AS 'komunikat';
  10. END IF;
  11.  
  12. END //
  13. DELIMITER ;


Wywołanie procedury:

  1. call sprawdz(67,'0')


Pozdrawiam.
Tomplus
oczywiście procedur nie da się wykonać w zapytaniu MySQL w PHP ?

Jednak jak po sprawdzeniu ma wykonać mi INSERT ?

  1. SELECT IF (NOT EXISTS
  2. (`uid`,`link` FROM `link_logs` WHERE `uid` = '67' AND `link` = '0'),
  3. 'INSERT', (INSERT INTO `link_logs` (`uid`, `link`) VALUES ('67', '0'))
  4. );

czy
  1. SELECT IF (NOT EXISTS
  2. (`uid`,`link` FROM `link_logs` WHERE `uid` = '67' AND `link` = '0')
  3. INSERT INTO `link_logs` (`uid`, `link`) VALUES ('67', '0')
  4. );


Obydwa nie działają u mnie.

móglbym to obejść:
najpierw dać zapytanie SELECT, a potem jeżeli false umieścić INSERT w osobnym zapytaniu, ale nie widzę sensu tworzyć kodu ponad potrzebę.


Osobiście szukam jeszcze rozwiązania:
Znalazłem podobny problem na tym forum:
http://forum.php.pl/index.php?showtopic=103731
Acz dziwi mnie rozwiązanie, bo jest polecane zapytanie z użyciem INSERT IGNORE, ale to nie da mi rozwiązania, bo utworzy kolejny wpis, bo prócz uid i link jest jeszcze unikatowa kolumna 'datatime' oraz id
trafas
Pierwszy przykład nie umożliwi Ci wprowadzenia danych. Pokazałem Ci tylko sposób, jak skorzystać z polecenia EXISTS poza procedurą.

Do wprowadzenia zmian możesz użyc funkcji lub procedury.
Z poziomu PHP procedurę wykonujesz zapytaniem:

  1. mysql_query("CALL nazwa_procedury");


funkcję wykonujesz przez wykonaie zapytania:

  1. mysql_query("SELECT nazwa_funkcji");


Funkcja do sprawdzenia istnienia wiersza i przy jego braku wpisanie go do bazy:


  1. DELIMITER //
  2. CREATE FUNCTION sprawdz(uid INT, link varchar(30)) RETURNS VARCHAR(50)
  3. BEGIN
  4.  
  5. IF NOT EXISTS (SELECT 1 FROM `sm_link_logs` WHERE `uid` = uid_in AND `link` = link_in)
  6. THEN
  7. INSERT INTO `link_logs` (`uid`, `link`) VALUES (uid_in, link_in);
  8. RETURN 'rekord został dopisany';
  9. ELSE
  10. RETURN 'rekord już istnieje';
  11. END IF;
  12.  
  13. END //
  14. DELIMITER ;


Wykonanie w PHP:

  1. $query = "select sprawdz(67,'0')";
  2. $data = mysql_query($query) or die (mysql_error());
  3. $dane = mysql_fetch_array($data);
  4. echo "Wynik działania funkcji : ".$dane[0];


Pozdrawiam.
Tomplus
Bardzo ładnie, tylko nie działa... :/
Tzn. pewnie działa, tylko nadal nie rozumiem jednego...

Samo wykonanie w PHP jest proste i sam do tego doszedłem, tylko problem tkwi jak mam stworzyć tą procedurę lub funkcję ?
Skąd zapytanie SQL wczyta funkcję sprawdz() ?


  1. $query = "select sprawdz(67,'0')";
  2. $data = mysql_query($query) or die (mysql_error());



Przeszukałem trochę googla i nie znazlłem w jaki sposób mam przechowywać procedury do późniejszego użycia.
Proszę o radę.
trafas
Po wykonaniu kodu tworzącego procedurę czy funkcję trzymane są one w bazie danych.

Jak stworzysz procedurę to póżniej możesz z niej korzystać do woli.

Aby sprawdzić listę procedur/funkcji wykonujesz:

  1. SHOW FUNCTION STATUS
  2. -- lub
  3. SHOW procedure STATUS
Tomplus
Wykonuje więc w moim PHPMyAdmin kod:


  1. DELIMITER //
  2. CREATE FUNCTION sprawdz(uid INT, link TINYINT) RETURNS TINYINT
  3. BEGIN
  4.  
  5. IF NOT EXISTS (SELECT 1 FROM `link_logs` WHERE `uid` = uid_in AND `link` = link_in)
  6. THEN
  7. INSERT INTO `link_logs` (`uid`, `link`) VALUES (uid_in, link_in);
  8. RETURN 'rekord zostal dopisany';
  9. ELSE
  10. RETURN 'rekord juz istnieje';
  11. END IF;
  12.  
  13. END //
  14. DELIMITER ;


W pierwszym zapytaniu, zwraca mi błąd że nie potrafi zrozumieć DELIMITER, usuwam wraz // (bo dowiedziałem się że to działa jak średnik)

Ale po tym też zwraca mi błąd, nie zrozumienia zapytania,
#luq
Cytat(Tomplus @ 13.02.2011, 18:52:45 ) *
W pierwszym zapytaniu, zwraca mi błąd że nie potrafi zrozumieć DELIMITER, usuwam wraz // (bo dowiedziałem się że to działa jak średnik)

Zapisz to w pliku i odpal przez konsole.

Natomiast Tobie najprawdopodobniej chodzi o niepowtarzanie pewnych danych a więc ustaw sobie klucz UNIQUE `uid` i `link`. Wtedy nie ma opcji żebyś miał w bazie dwa rekordy o identycznych wartościach w tych polach.

Tomplus
Nie mam konsoli do MySQL, bo jedyny dostęp do serwera MySQL to PHPMyAdmin, lub polecenia z plików PHP

Natomiast co do porady, to jest nie trafiona. Wartości uid i link się mogą powtórzyć, ale nie mogą się powtórzyć w tej samej kombinacji.

Czyli:
67 0
67 1
13 0
12 1
itp...
Gdybym dał UNIQE to zwracałoby mi błąd za kazdym razem gdy powtórzył się uid, nawet jeżeli jest inny link.
#luq
Cytat(Tomplus @ 13.02.2011, 19:20:48 ) *
Nie mam konsoli do MySQL, bo jedyny dostęp do serwera MySQL to PHPMyAdmin, lub polecenia z plików PHP

A więc exec chodź podejrzewam, że możesz mieć tą funkcje zablokowaną na serwerze.

Cytat
Gdybym dał UNIQE to zwracałoby mi błąd za kazdym razem gdy powtórzył się uid, nawet jeżeli jest inny link.

Jesteś tego pewien? Sprawdzałeś?
Tomplus
Cytat(#luq @ 13.02.2011, 19:29:02 ) *
A więc exec chodź podejrzewam, że możesz mieć tą funkcje zablokowaną na serwerze.

Owszem.

Cytat(#luq @ 13.02.2011, 19:29:02 ) *
Jesteś tego pewien? Sprawdzałeś?

To było sprytne smile.gif
W pierwszej chwili zrozumiałem że należy dać UNIQUE dla uid i link, ale osobno dla kolumn.
ale nie zwróciłem uwagi na to że wartość UNIQUE może być współdzielona.


Dziękuje #luq, może wynik nie jest taki jak zapytałem, ale rozwiązanie jest bardzo dobre.

Dziekuje również trafas'owi, mimo że Twoje rady nie dało się wykorzystać przy moich uprawnieniach.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.