Macie jakieś sposoby na sprawdzanie przy dodawaniu czy rekord istnieje w bazie ?
Obecnie sprawdzam dwoma zapytaniami do bazy i dosyć długo to trwa.
-
Sprawdzanie po kluczu głównym
-
Sprawdzanie po jakichś indeksowanych polach
-
Unikalny indeks -> dostaniesz constraint violation
-
Można też mieć konstrukty typu INSERT SELECT, gdzie po cichu wstawisz (jak jest spełniony jakiś warunek) albo nie wstawisz (jak warunek nie jest spełniony):
INSERT INTO TABELKA SELECT t2.* FROM TABELKA2 t2 WHERE NOT EXISTS (SELECT 1 FROM TABELKA t1 where t1.klucz=:wybrany_klucz)
-
Na niektórych silnikach można scalić zmiany (MERGE - łączy funkcjonalność INSERT i UPDATE)
-
i 2) powinno szybko się wykonać. Jeśli 'działa wolno', to problem jest gdzie indziej.
Możemy mieć do czynienia z problemem X/Y - co próbujesz osiągnąć?
Do samego INSERT
nie mam zastrzeżeń ale sprawdzanie IF'em
w PHP wydłuża czas dodawania.
Niestety u mnie MERGE
NIE MA.
Próbowałem punktu 4 ale raz działa raz nie.
Nie chcę mieć duplikatów w bazie o tym samym kodzie identyfikacyjnym.
A constraint na odpowiedniej kokumnie? Nie pozwoli Ci wstawiac duplikatow i zwroci blad podczas proby wstawienia takiego rekordu.
Ostra Parówa napisał(a):
Próbowałem punktu 4 ale raz działa raz nie.
Nie ma takiej opcji. Albo działa, albo nie.
Wyrzucało mi błąd:
Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in...
ale to już ogarnięte.
Można dorobić do tego kodu aktualizację rekordu jeśli istnieje ?
@Marcin.Miga: Jaka baza ?
A jednak jak mówiłem raz działa raz nie :/
Otrzymuje kod
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'Lesko'
SQL..
INSERT INTO `tabela` (code, name, city) SELECT * FROM (SELECT :code, :name, :city) AS tmp WHERE NOT EXISTS ( SELECT `code` FROM `tabela` WHERE `code` = :code ) LIMIT 1;
Z tego co zauważyłem to SQL wyrzuca błąd bo name
i city
dostaje tą samą wartość!! ●~*
\(◎o◎)/
WTF ??!!
(~_~)
@yarel: Jak wiąże ? Mam tablicę
$param = [
":name"=> "coś tam",
//itd....
];
i podaję do PDO::execute
Ostra Parówa napisał(a):
@yarel: Jak wiąże ? Mam tablicę
$param = [ ":name"=> "coś tam", //itd.... ];
i podaję do
PDO::execute
I właśnie chodzi o to wiązanie (binding) wartości do zmiennych. Nie wiem jak w PHP, ale mając w czystym JDBC zapytanie typu select :foo, :bar from table where xyz=:foo
, to trzeba dowiązać trzy wartości, a nie dwie. Stąd moje pytanie, jak wygląda kod? Bywa, że błąd tkwi gdzieś w //itd
, a nie samej koncepcji.
Kolejna rzecz, to na pewno powinno być ":name" => "coś tam", a nie 'name' => 'coś tam' ? Chodzi głównie o :
Skoro to MySQL, to możesz zamiast INSERT/MERGE
zrobić REPLACE, albo INSERT ... ON DUPLICATE
@yarel: podaję wszystkie dane w tablicy. Jeśli brakuje jakiegoś parametru to wyrzuca mi błąd:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in
W PHP'ie wygląda to tak
$insert = db::query("INSERT INTO `tabela` (code, name, city) SELECT * FROM (SELECT :code, :name, :city) AS tmp WHERE NOT EXISTS ( SELECT `code` FROM `tabela` WHERE `code` = :code ) LIMIT 1;",[
":code"=>"A",
":name"=>"B",
":city"=>"C",
]);
Funkcja db::query
public static function query($sql,$params = null) {
try {
$queryOut = self::$db->prepare($sql);
$queryOut->execute($params);
} catch (PDOException $e) {
die("ERROR: ".$e->getCode()."");
}
return $queryOut;
}
Toteż @yarel ci odpowiedział, że brakuje ci jednego parametru. PDO jest o tyle głupie, że nie potrafi tego samego parametru dwa razy podstawić...
Zrób tak:
$insert = db::query("INSERT INTO `tabela` (code, name, city) SELECT * FROM (SELECT :code, :name, :city) AS tmp WHERE NOT EXISTS ( SELECT `code` FROM `tabela` WHERE `code` = :code1 ) LIMIT 1;",[
":code"=>"A",
":name"=>"B",
":city"=>"C",
":code1"=>"A",
]);
Ostra Parówa napisał(a):
@yarel: podaję wszystkie dane w tablicy. Jeśli brakuje jakiegoś parametru to wyrzuca mi błąd:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in
W PHP'ie wygląda to tak
$insert = db::query("INSERT INTO `tabela` (code, name, city) SELECT * FROM (SELECT :code, :name, :city) AS tmp WHERE NOT EXISTS ( SELECT `code` FROM `tabela` WHERE `code` = :code ) LIMIT 1;",[ ":code"=>"A", ":name"=>"B", ":city"=>"C", ]);
Funkcja
db::query
public static function query($sql,$params = null) { try { $queryOut = self::$db->prepare($sql); $queryOut->execute($params); } catch (PDOException $e) { die("ERROR: ".$e->getCode().""); } return $queryOut; }
- Co to znaczy raz działa, raz nie?
- Co uzyskasz/zwracasz z funkcji query() jeśli ten insert wykona się prawidłowo? Zastanawia mnie zwracanie queryOut, a nie queryOut->execute()
@Marcin.Miga: Czytaj dokładnie.
Ostra Parówa napisał(a):
Z tego co zauważyłem to SQL wyrzuca błąd bo
name
icity
dostaje tą samą wartość
@yarel: Jak wyżej jeśli :name
i :city
mają tą samą wartość do wyrzuca mi taki błąd:
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name '....'
A jeśli są różne to działa prawidłowo.
Dlatego raz działa raz nie.
$insert = db::query(...);
if($insert->rowCount() >= 1) {
// Komunikat jeśli rekord został dodany poprawnie
} else {
// Komunikat jeśli nie został dodany do bazy
}
Jeszcze jedna rzecz przychodzi mi do głowy. W zapytaniu aliasuj nazwy kolumn: (SELECT :code as code, :name as name, :city as city)
Sory zapomniałem dopisać..
Testowałem sposób @Marcin.Miga i otrzymuję błąd
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name '....
Natomiast Twój pomysł z aliasami to strzał w dziesiątkę.
Wcześniej wczytywało z 10 sek a teraz od strzała.
Testowałem z podstawianiem tego samego parametru dwa razy i spokojnie działa bez konieczności dodawania :code1