2013-10-07 18 views
8

Mam tabelę z kluczem podstawowym z wieloma kolumnami (miasto/stan/data) i wieloma innymi kolumnami danych. Szukam najnowszych danych dla każdego miasta/stanu. Jak zrobić to czysto/sprawnie? Teraz mogę to zrobić wykonując pierwszego zapytania, aby uzyskać listę wszystkich wierszy Próbuję pobrać, a następnie drugiego zapytania z masywnym WHERE:Jak wybrać wiele wierszy według klucza wielokolumnowego w MySQL?

SELECT state, city, max(date) from data GROUP BY city, state; 

+-------+---------------------+------------+ 
| state | city    | MAX(date) | 
+-------+---------------------+------------+ 
| CA | San Francisco  | 2013-09-01 | 
| CA | Los Angeles   | 2013-08-01 | 
| NY | New York   | 2013-10-01 | 
| ... | ... (many rows) ... | ...  | 
+-------+---------------------+------------+ 


SELECT * FROM data WHERE 
    (state = "CA" AND city = "San Francisco" AND date='2013-09-01') OR 
    (state = "CA" AND city = "Los Angeles" AND date='2013-08-01') OR 
    (state = "NY" AND city = "New York" AND date='2013-10-01') OR 
    ... 

To jest naprawdę brzydki i nieefektywne , a jeśli pierwsze zapytanie zwróci wiele wierszy, moje drugie zapytanie może być zbyt długie. Oczywiście jeśli posiadam klucz podstawowy z jedną kolumną, mógłbym użyć podselekcję z IN(), ale nie jest to tutaj możliwe. Jakieś sugestie?

AKTUALIZACJA: Próbowałem sugestii Billa z podselekcją, ale nie używa ona żadnych klawiszy i trwa wiecznie. Jeśli ograniczę podselek tylko do 5 wierszy, powróci on w 0,64 s. Jeśli pozwolę mu zwrócić wszystkie 73 kombinacje miasto/stan, zajmuje to bardzo dużo czasu (zapytanie wciąż działa).

EXPLAIN SELECT * FROM data WHERE (city, state, date) IN (SELECT state, city, MAX(date) FROM data GROUP BY city, state) 
+----+--------------------+-------+-------+---------------+---------+---------+------+-------+-------------+ 
| id | select_type  | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+--------------------+-------+-------+---------------+---------+---------+------+-------+-------------+ 
| 1 | PRIMARY   | data | ALL | NULL   | NULL | NULL | NULL | 13342 | Using where | 
| 2 | DEPENDENT SUBQUERY | data | index | NULL   | PRIMARY | 57  | NULL | 8058 | Using index | 
+----+--------------------+-------+-------+---------------+---------+---------+------+-------+-------------+ 
+1

co jest koniec doprowadzić próbujesz uzyskać – Ibu

Odpowiedz

4

myślę, że to powinno wystarczyć dla Ciebie:

select 
    * 
from 
    data t1 
natural join 
    ( 
     select 
      city, 
      state, 
      max(date) as date 
     from 
      data 
     group by 
      city, 
      state 
    ) t2; 
+0

Tak, to działa idealnie! Nigdy wcześniej nie korzystałem z naturalnego sprzężenia, ale tego właśnie chcę, i to szybko! – Jonathan

+0

@ Jonathan - Cieszę się, że mogę pomóc. W rzeczywistości możesz użyć wewnętrznego sprzężenia tutaj, ale musisz również napisać klauzulę "na" we wszystkich 3 kolumnach, aby uzyskać ten sam efekt co naturalne sprzężenie. Jest o wiele bardziej przejrzysty w ten sposób i może być trochę szybszy, ponieważ w przypadku łączenia naturalnego będzie tylko 1 kopia dla wspólnych kolumn, ale sprzężenie wewnętrzne wygeneruje 2 z nich. –

4

MySQL obsługuje porównań krotka:

SELECT * FROM data WHERE 
(state, city, date) IN (
    ('CA', 'San Francisco', '2013-09-01'), 
    ('CA', 'Los Angeles', '2013-08-01'), 
    ('NY', 'New York', '2013-10-01')); 
+0

Myślę, że był szukanie dynamicznego podejścia, jeśli na stole jest - powiedzmy - kilkaset lub kilka tysięcy miast. –

+0

@Bill: Nie wiedziałem, że MySQL obsługuje porównania krotek, co z pewnością będzie częścią odpowiedzi, ale GottliebNotschnabel ma rację, chcę dynamicznego rozwiązania. Próbuję to zrobić za pomocą podselekcji, ale nie używa ona prawego klawisza. – Jonathan

+0

Próbowałem już wcześniej, wydaje się, że dokona pełnego skanowania tabeli, nawet kryteria pasują do indeksu. – JasonMing

Powiązane problemy