Sprawdzanie czy rekord istnieje w bazie podczas tworzenia

0

Macie jakieś sposoby na sprawdzanie przy dodawaniu czy rekord istnieje w bazie ?
Obecnie sprawdzam dwoma zapytaniami do bazy i dosyć długo to trwa.

1
  1. Sprawdzanie po kluczu głównym

  2. Sprawdzanie po jakichś indeksowanych polach

  3. Unikalny indeks -> dostaniesz constraint violation

  4. 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)

  5. Na niektórych silnikach można scalić zmiany (MERGE - łączy funkcjonalność INSERT i UPDATE)

  6. i 2) powinno szybko się wykonać. Jeśli 'działa wolno', to problem jest gdzie indziej.

0

Możemy mieć do czynienia z problemem X/Y - co próbujesz osiągnąć?

0

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.

1

A constraint na odpowiedniej kokumnie? Nie pozwoli Ci wstawiac duplikatow i zwroci blad podczas proby wstawienia takiego rekordu.

0
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.

0

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 ?

0

@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;
0

Z tego co zauważyłem to SQL wyrzuca błąd bo name i city dostaje tą samą wartość!! ●~* \(◎o◎)/
WTF ??!! (~_~)

0

@yarel: Jak wiąże ? Mam tablicę

$param = [
":name"=> "coś tam",
//itd....
];

i podaję do PDO::execute

0
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 :

2

Skoro to MySQL, to możesz zamiast INSERT/MERGE zrobić REPLACE, albo INSERT ... ON DUPLICATE

0

@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;
  }
1

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",
]);
0
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;
  }
  1. Co to znaczy raz działa, raz nie?
  2. Co uzyskasz/zwracasz z funkcji query() jeśli ten insert wykona się prawidłowo? Zastanawia mnie zwracanie queryOut, a nie queryOut->execute()
0

@Marcin.Miga: Czytaj dokładnie.

Ostra Parówa napisał(a):

Z tego co zauważyłem to SQL wyrzuca błąd bo name i city 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
}
0

Jeszcze jedna rzecz przychodzi mi do głowy. W zapytaniu aliasuj nazwy kolumn: (SELECT :code as code, :name as name, :city as city)

0

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

1 użytkowników online, w tym zalogowanych: 0, gości: 1