Jestem ciekawy, czy możliwe jest powiązanie tablicy wartości z symbolem zastępczym za pomocą PDO. Przypadek użycia tutaj próbuje przekazać tablicę wartości do użycia z IN()
warunkiem.
Chciałbym móc zrobić coś takiego:
<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>
I poproś o powiązanie PDO i zacytowanie wszystkich wartości w tablicy.
W tej chwili robię:
<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
$val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$in.')'
);
$stmt->execute();
?>
Co na pewno działa, ale zastanawiam się, czy brakuje mi wbudowanego rozwiązania?
Odpowiedzi:
myślę, że soulmerge ma rację. będziesz musiał zbudować ciąg zapytania.
fix: Dan, miałeś rację. naprawiono kod (chociaż go nie testowałem)
edytuj: zarówno Chris (komentarze), jak i ktoś niesłusznie sugerowali, że pętla foreach ...
... może być zbędny, więc
foreach
pętla i pętla$stmt->execute
mogą zostać zastąpione przez ...(ponownie nie testowałem tego)
źródło
$foreach
ibindValue()
nie jest wymagane - wystarczy wykonać z tablicą. Np .:$stmt->execute($ids);
str_repeat('?,', count($array) - 1). '?';
Na coś szybkiego:
źródło
$input_list = substr(str_repeat(',?', count($ids)), 1);
str_repeat('?,', count($ids) - 1) . '?'
. Jedno połączenie funkcji mniej.execute
tablicę identyfikatorówCzy użycie
IN
instrukcji jest tak ważne ? Spróbuj użyćFIND_IN_SET
op.Na przykład w PDO istnieje takie zapytanie
Następnie musisz tylko powiązać tablicę wartości, zaimplantowaną przecinkiem, taką jak ta
i gotowe.
UPD: Jak niektórzy zauważyli w komentarzach do tej odpowiedzi, jest kilka kwestii, które należy wyjaśnić w sposób wyraźny.
FIND_IN_SET
nie używa indeksu w tabeli i wciąż nie jest jeszcze zaimplementowany - zobacz ten rekord w narzędziu do śledzenia błędów MYSQL . Dzięki @BillKarwin za powiadomienie.implode
użyciu symbolu przecinka jako separatora. Dzięki @VaL za notatkę.W porządku, jeśli nie jesteś silnie zależny od indeksów i nie używasz ciągów z przecinkiem do wyszukiwania, moje rozwiązanie będzie znacznie łatwiejsze, prostsze i szybsze niż rozwiązania wymienione powyżej.
źródło
... FIND_IN_SET(description,'simple,search')
będzie działać, aleFIND_IN_SET(description,'first value,text, with coma inside')
zawiedzie. Więc funkcja będzie szukać"first value", "text", "with coma inside"
zamiast pożądanego"first value", "text, with coma inside"
Ponieważ wykonuję wiele zapytań dynamicznych, stworzyłem bardzo prostą funkcję pomocnika.
Użyj tego w ten sposób:
Zwraca ciąg,
:id1,:id2,:id3
a także aktualizuje$bindArray
wiązania, które będą potrzebne, gdy nadejdzie czas uruchomienia zapytania. Łatwy!źródło
Rozwiązanie EvilRygy nie działało dla mnie. W Postgres możesz wykonać inne obejście:
źródło
ERROR: operator does not exist: integer = text
. Musisz przynajmniej dodać jawne casting.bardzo czystym sposobem dla postgres jest użycie tablicy postgres („{}”):
źródło
Oto moje rozwiązanie:
Zwróć uwagę na użycie wartości array_values. To może rozwiązać problemy z kluczowymi zamówieniami.
Łączę tablice identyfikatorów, a następnie usuwam zduplikowane elementy. Miałem coś takiego:
I to się nie udawało.
źródło
$original_array
Dodaj elementy przed oryginalną tablicą:array_unshift($original_array, new_unrelated_item);
Dodaj elementy za oryginalną tablicą:array_push($original_array, new_unrelated_item);
Gdy wartości zostaną powiązane, nowe_ niezwiązane elementy zostaną umieszczone w odpowiednich lokalizacjach. Umożliwia to mieszanie elementów Array i non-array. `Rozszerzyłem PDO, aby zrobić coś podobnego do tego, co sugeruje stefs, a na dłuższą metę było mi łatwiej:
Możesz użyć tego w następujący sposób:
źródło
:array
jest w ciągu zapytania.if (is_array($data))
jeden) jest niepotrzebne, a jednocześnie znacznie dokładniejsze przetwarzanie danych.Patrząc na PDO: Stałe predefiniowane, nie ma PDO :: PARAM_ARRAY, którego byś potrzebował, jak podano na PDOStatement-> bindParam
Więc nie sądzę, że można to osiągnąć.
źródło
Jeśli masz inny parametr, możesz zrobić tak:
źródło
Dla mnie bardziej seksownym rozwiązaniem jest zbudowanie dynamicznej tablicy asocjacyjnej i użycie jej
źródło
Zdaję sobie również sprawę, że ten wątek jest stary, ale miałem unikalny problem polegający na tym, że podczas konwersji niedługo przestarzałego sterownika mysql na sterownik PDO musiałem stworzyć funkcję, która dynamicznie mogłaby budować zarówno normalne parametry, jak i IN z tego samego tablica parametrów. Więc szybko to zbudowałem:
Nadal nie został przetestowany, jednak wydaje się, że logika istnieje.
Mam nadzieję, że pomoże to komuś na tej samej pozycji,
Edycja: Po kilku testach dowiedziałem się:
Kod edytowany do działającej wersji.
źródło
Trochę edycji o kodzie Schnalle
źródło
Z jakiej bazy danych korzystasz? W PostgreSQL lubię używać DOWOLNEJ (tablicy). Aby ponownie użyć swojego przykładu:
Niestety jest to dość nieprzenośne.
W innych bazach danych musisz wymyślić własną magię, o czym wspominali inni. Będziesz chciał umieścić tę logikę w klasie / funkcji, aby oczywiście można ją było ponownie wykorzystać w całym programie. Spójrz na komentarze na
mysql_query
stronie PHP.NET, aby uzyskać więcej przemyśleń na ten temat i przykłady tego scenariusza.źródło
Po przejściu przez ten sam problem poszedłem do prostszego rozwiązania (choć nadal nie jest tak eleganckie, jak
PDO::PARAM_ARRAY
mogłoby być):biorąc pod uwagę tablicę
$ids = array(2, 4, 32)
:... i tak dalej
Więc jeśli używasz tablicy mieszanych wartości, będziesz potrzebować więcej kodu, aby przetestować swoje wartości przed przypisaniem parametru param:
Ale nie przetestowałem tego.
źródło
Jak wiem, nie ma możliwości powiązania tablicy z instrukcją PDO.
Ale istnieją 2 wspólne rozwiązania:
Użyj Pozycyjnych symboli zastępczych (?,?,?,?) Lub Nazwanych symboli zastępczych (: id1,: id2,: id3)
$ whereIn = implode (',', array_fill (0, count ($ ids), '?'));
Cytuj tablicę wcześniej
$ whereIn = tablica_mapy (tablica ($ db, „quote”), $ ids);
Obie opcje są dobre i bezpieczne. Wolę drugi, ponieważ jest krótszy i mogę var_dump parametry, jeśli go potrzebuję. Używając symboli zastępczych, musisz powiązać wartości, a na końcu kod SQL będzie taki sam.
A ostatnim i ważnym dla mnie jest uniknięcie błędu „liczba powiązanych zmiennych nie pasuje do liczby tokenów”
Doctrine to świetny przykład użycia symboli zastępczych, tylko dlatego, że ma wewnętrzną kontrolę nad przychodzącymi parametrami.
źródło
Jeśli kolumna może zawierać tylko liczby całkowite, prawdopodobnie można to zrobić bez symboli zastępczych i po prostu wstawić identyfikatory bezpośrednio do zapytania. Musisz tylko rzutować wszystkie wartości tablicy na liczby całkowite. Lubię to:
Nie powinno to być podatne na iniekcję SQL.
źródło
oto moje rozwiązanie. Rozszerzyłem również klasę PDO:
Oto przykładowe użycie powyższego kodu:
Powiedz mi co myślisz
źródło
BindArrayParam
tablicy asocjacyjnej, ponieważ wydaje się, że ograniczasz to do liczb całkowitych.W PDO nie można użyć takiej tablicy.
Musisz zbudować ciąg z parametrem (lub użyć?) Dla każdej wartości, na przykład:
:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5
Oto przykład:
Jeśli chcesz nadal używać
bindParam
, możesz to zrobić w zamian:Jeśli chcesz użyć
?
symboli zastępczych, możesz to zrobić w następujący sposób:Jeśli nie wiesz, czy
$ids
jest pusty, powinieneś go przetestować i odpowiednio obsłużyć tę sprawę (zwróć pustą tablicę lub zwróć Obiekt Null lub wyrzuć wyjątek, ...).źródło
Posunąłem się nieco dalej, aby przybliżyć odpowiedź do pierwotnego pytania o użycie symboli zastępczych do powiązania parametrów.
Ta odpowiedź będzie musiała utworzyć dwie pętle przez tablicę, która będzie używana w zapytaniu. Ale rozwiązuje to problem posiadania innych symboli zastępczych dla bardziej selektywnych zapytań.
źródło
najpierw ustawiłeś liczbę „?” w zapytaniu, a następnie za pomocą „for” wyślij parametry takie jak to:
źródło