Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Trigger, wyzwalacze
Forum PHP.pl > Forum > Bazy danych > MySQL
Fifi209
Witam, stanąłem przed następującym problemem, przebudowuję stronę kumpla, jego baza danych była bardzo nieoptymalnie zaprojektowana (nadmiarowość danych) etc.
Postawiliśmy ją przeprojektować, co zmusiło mnie do utworzenia nowej o zupełnie innej strukturze.

Projekt to ogólnie fansite, który zajmuje się gromadzeniem danych o graczach.
Usługodawca hostingu, poprosił o zmniejszenie liczby zapytań - stąd nowa baza i pytanie, które chcę zadać.

Przykładowe dwie powiązane tabele:

Players:
id, nick

Online:
id, player_id, time, online

Tabela online przechowuje dzienne zestawienia dla gracza ile godzin był online.
time - data
online - czas w minutach przez jaki grał

Teraz chciałbym za jednym zapytaniem zrobić następujące rzeczy;
  • Sprawdzić czy gracz istnieje w players, jeżeli nie to go dodać i pobrać id
  • Sprawdzić czy w dniu dzisiejszym został dodany rekord, jeżeli tak to dodać czas jeżeli nie to najpierw zrobić insert do tabeli online


I teraz moje pytanie, czy da się to zrobić jednym zapytaniem?
pmir13
Rozumiem że pytasz czy każdą z tych czynności da się zrobić jednym zapytaniem. Bo trudno jest mi sobie wyobrazić zapytanie, które robiłoby to wszystko naraz. Chyba że jest to zapytanie typu wywołanie procedury.

Co do pierwszego - jeżeli w tabeli masz tylko te dwa pola to nie widzę możliwości zrobienia tego w jednym zapytaniu, jeśli jednak byłoby coś więcej to z pewnością dałoby się to zrobić. Na przykład gdyby było dodane pole ostatnio typu datetime można byłoby wykorzystywać:
  1. INSERT INTO players(nick,ostatnio) VALUES('tester',now()) ON duplicate KEY UPDATE ostatnio=now();

Oczywiście by to działało musi być ustawiony klucz primary na id i unique na nick. Wtedy last_insert_id ustawiany jest na id wstawionego rekordu niezależnie od tego czy został wykonany insert czy update. Gdyby jednak nie było pola ostatnio, musielibyśmy stosować albo dwa zapytania - insert+select, albo insert ignore, który nie zwraca last_insert_id w przypadku próby powtórzenia klucza unique, albo obejście składniowe w stylu on duplicate key update id=id, które też by nie zwracało last_insert_id gdyby podany nick już w bazie był, bo żadna realna zmiana w rekordzie by nie zaszła i nic do zmiany byśmy nie mieli. Być może jakiś sposób istnieje by to zmieścić w jednym zapytaniu bez dodatkowego pola i jednocześnie dostać id, ale ja go nie znam.

Co do drugiego to sprawa jest prostsza, bo taką dodatkową kolumną jest czas online, który będziemy zwiększać. Czyli klucz unique na parę ( player_id, dzien ) i jeśli chcemy graczowi tester dodać 30 minut to zapytanie
  1. INSERT INTO online( player_id, dzien, czas_online ) VALUES ( 1, date(now()), 30 ) ON duplicate KEY UPDATE czas_online = czas_online + 30;

Zmieniłem tutaj trochę nazwy kolumn by time nie myliło się z funkcją time, a kolumna online z nazwą tabeli online.
Fifi209
Zrobiłem na funkcjach i działa tak jak chciałem smile.gif
Problem rozwiązany, natchnąłeś mnie procedurami.
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-2024 Invision Power Services, Inc.