Mam klienta tabeli, który przechowuje identyfikator_klienta, adres e-mail i dane referencyjne. Istnieje dodatkowa tabela customer_data, która przechowuje historyczny zapis zmian dokonanych w kliencie, tj. Kiedy następuje zmiana, wstawiany jest nowy wiersz.
Aby wyświetlić informacje o kliencie w tabeli, dwie tabele muszą zostać połączone, jednak tylko najnowszy wiersz z customer_data powinien zostać dołączony do tabeli customer.
To staje się trochę bardziej skomplikowane, ponieważ zapytanie jest podzielone na strony, więc ma limit i przesunięcie.
Jak mogę to zrobić z MySQL? Myślę, że chcę gdzieś umieścić WYRÓŻNIENIE ...
Pytanie w tej chwili wygląda następująco:
SELECT *, CONCAT(title,' ',forename,' ',surname) AS name
FROM customer c
INNER JOIN customer_data d on c.customer_id=d.customer_id
WHERE name LIKE '%Smith%' LIMIT 10, 20
Dodatkowo, czy mam rację sądząc, że mogę w ten sposób używać funkcji CONCAT z LIKE?
(Rozumiem, że INNER JOIN może być niewłaściwym typem JOIN do użycia. Właściwie nie mam pojęcia, jaka jest różnica między różnymi JOINami. Zamierzam się temu teraz przyjrzeć!)
Odpowiedzi:
Możesz spróbować następujących rzeczy:
Zwróć uwagę, że a
JOIN
jest tylko synonimemINNER JOIN
.Przypadek testowy:
Wynik (zapytanie bez
LIMIT
iWHERE
):źródło
Jeśli pracujesz z ciężkimi zapytaniami, lepiej przenieś żądanie dla najnowszego wiersza w klauzuli where. Jest dużo szybszy i wygląda czysto.
źródło
sql_no_cache set
), podczas gdy wyszukiwanie w złączeniu trwało kilka sekund. Wciąż zdumiony, ale mam na myśli, że nie można dyskutować z takimi wynikami.Zakładając, że kolumna z autoinkrementacją
customer_data
ma nazwęId
, możesz wykonać:źródło
Dla każdego, kto musi pracować ze starszą wersją MySQL (starsza niż 5.0 ish), nie możesz wykonywać pod-zapytań dla tego typu zapytań. Oto rozwiązanie, które udało mi się zrobić i wydawało się, że działa świetnie.
Zasadniczo jest to znalezienie maksymalnego identyfikatora tabeli danych, dołączenie jej do klienta, a następnie połączenie tabeli danych z maksymalnym znalezionym identyfikatorem. Powodem tego jest to, że wybranie maksimum grupy nie gwarantuje, że reszta danych będzie zgodna z id, chyba że połączysz ją z powrotem.
Nie testowałem tego na nowszych wersjach MySQL, ale działa na 4.0.30.
źródło
EXPLAIN
oznacza to, że używa tymczasowej tabeli i sortowania plików. DodanieORDER BY NULL
na końcu usuwa sortowanie plików.SELECT *, MAX(firstData.id), MAX(secondData.id) [...]
. Logicznie rzecz biorąc, zmiana naSELECT main.*, firstData2.*, secondData2.*, MAX(firstData.id), MAX(secondData.id), [...]
I była w stanie zrobić to znacznie szybciej. Dzięki temu pierwsze sprzężenia mogą odczytywać tylko z indeksu, zamiast odczytywać wszystkie dane z indeksu podstawowego. Teraz ładne rozwiązanie zajmuje tylko 1,9 razy dłużej niż rozwiązanie oparte na podzapytaniach.Wiem, że to pytanie jest stare, ale przez lata poświęcano mu dużo uwagi i myślę, że brakuje w nim koncepcji, która może pomóc komuś w podobnej sprawie. Dodam to tutaj dla kompletności.
Jeśli nie możesz zmodyfikować oryginalnego schematu bazy danych, oznacza to, że podano wiele dobrych odpowiedzi i rozwiązano problem.
Jeśli jednak możesz zmodyfikować swój schemat, radziłbym dodać do
customer
tabeli poleid
zawierające najnowszycustomer_data
rekord dla tego klienta:Zapytania klientów
Zapytania są tak proste i szybkie, jak to tylko możliwe:
Wadą jest dodatkowa złożoność podczas tworzenia lub aktualizowania klienta.
Aktualizacja klienta
Jeśli chcesz zaktualizować klienta, wstaw nowy rekord do
customer_data
tabeli i zaktualizujcustomer
rekord.Tworzenie klienta
Utworzenie klienta to tylko kwestia wstawienia
customer
wpisu, a następnie uruchomienia tych samych instrukcji:Podsumowując
Dodatkowa złożoność tworzenia / aktualizowania klienta może być przerażająca, ale można ją łatwo zautomatyzować za pomocą wyzwalaczy.
Wreszcie, jeśli używasz ORM, może to być naprawdę łatwe w zarządzaniu. ORM może zająć się wstawieniem wartości, aktualizacją identyfikatorów i automatycznym połączeniem dwóch tabel.
Oto jak wyglądałby Twój zmienny
Customer
model:I Twój niezmienny
CustomerData
model, który zawiera tylko metody pobierające:źródło
myślę, że musisz zmienić c.customer_id na c.id
w przeciwnym razie zaktualizuj strukturę tabeli
źródło
Ty też możesz to zrobić
źródło
Dobrze jest logować rzeczywiste dane do tabeli „ customer_data ”. Dzięki tym danym możesz dowolnie wybierać wszystkie dane z tabeli „customer_data”.
źródło