2013-02-22 13 views
10

Mam problem z następującym zapytaniu SQL i MySQLSQL SELECT WHERE NOT IN z zapytaniem samym stole

SELECT 
    id, cpid, label, cpdatetime 
FROM 
    mytable AS a 
WHERE 
    id NOT IN 
    (
    SELECT 
     id 
    FROM 
     mytable AS b 
    WHERE 
     a.label = b.label 
    AND 
     a.cpdatetime > b.cpdatetime 
) 
AND 
    label LIKE 'CB%' 
AND 
    cpid LIKE :cpid 
GROUP BY label 
ORDER BY cpdatetime ASC 

tabela wygląda tak

1 | 170.1 | CB55 | 2013-01-01 00:00:01 
2 | 135.5 | CB55 | 2013-01-01 00:00:02 
3 | 135.6 | CB59 | 2013-01-01 00:00:03 
4 | 135.5 | CM43 | 2013-01-01 00:00:04 
5 | 135.5 | CB46 | 2013-01-01 00:00:05 
6 | 135.7 | CB46 | 2013-01-01 00:00:06 
7 | 170.2 | CB46 | 2013-01-01 00:00:07 

Chciałbym wrócić do mojego zapytania

3 | 135.6 | CB59 
5 | 135.5 | CB46 

Edit

Etykiety to psy/koty, a cpid to tymczasowe rodziny trzymające psy/koty.

Psy/koty przenoszą się z rodziny do rodziny.

Muszę znaleźć psy/koty, którzy byli w: userinput rodziny, ale tylko wtedy, gdy nie były one w innej rodzinie wcześniej

nie może zmienić bazę danych i po prostu trzeba pracować z danymi, ponieważ są one i Nie jestem tym, który napisał schemat aplikacji/bazy danych.

+0

Wystąpiły jakiekolwiek błędy? – Sir

+3

Nie przepraszaj - to dobrze napisane pytanie w porównaniu do innych, w których informacje o nagrodach są dostępne za pomocą śrub z pokrętłem. –

+0

Przepraszam, czy mógłbyś wyjaśnić, dlaczego nie powinien on powrócić do wiersza 1? Czy ': cpid = '13% '' może? –

Odpowiedz

6

Postaraj się unikać skorelowanych kwerendy sub za pomocą LEFT JOIN:

SELECT a.id, a.cpid, a.label, a.cpdatetime 
FROM mytable AS a 
LEFT JOIN mytable AS b ON a.label = b.label AND a.cpdatetime > b.cpdatetime 
WHERE a.label LIKE 'CB%' AND a.cpid LIKE :cpid 
    AND b.label IS NULL 
GROUP BY a.label 
ORDER BY a.cpdatetime ASC 

Fiddle

Jeśli warunek przyłączenia się nie powiedzie, pola drugiej tabeli alias b będzie ustaw na NULL.

Alternatywnie używać non-skorelowany zapytanie Podtyp:

SELECT a.id, a.cpid, a.label, a.cpdatetime 
FROM mytable AS a 
INNER JOIN (
    SELECT label, MIN(cpdatetime) AS cpdatetime 
    FROM mytable 
    WHERE label LIKE 'CB%' 
    GROUP BY label 
) AS b ON a.label = b.label AND a.cpdatetime = b.cpdatetime 
WHERE a.cpid LIKE '135%' 
ORDER BY a.cpdatetime 

pierwsze, znaleźć minimalną cpdatetime dla każdej etykiety, a następnie przystąpić że z pierwszej tabeli, gdzie dodać dodatkowy cpid warunek.

1

Myślę, że tak naprawdę chcesz zrobić - wybierz identyfikatory, które są najwcześniejszymi identyfikatorami dla każdej etykiety, a następnie wybierz z nich rekordy z etykietą 135 cpid i CB.

SELECT 
    A.id, cpid, A.label, cpdatetime 
FROM 
    mytable AS a inner join 
(select id, label from mytable 
    group by label 
    having min(cpdatetime)) as b 
on A.label=B.label and A.id=B.id 
WHERE 
    A.label LIKE 'CB%' 
AND 
    cpid LIKE '135%' 
GROUP BY A.label 
ORDER BY cpdatetime ASC; 

http://sqlfiddle.com/#!2/ccccf/16

+0

Czy 'mając min (cpdatetime)' nigdy nie przyniesie prawdziwości? –

+0

zarówno twoje rozwiązanie, jak i praca Jacka, ale nie jestem pewien, który z nich powinienem uznać za zaakceptowany. Rozumiem, że odpowiedź Jacka jest naprawdę łatwa w porównaniu z twoją @joe, więc nie jestem do końca pewna, wciąż próbuję przeczytać więcej danych wejściowych i kopać w dokumentacji MySQL. – teuna

+0

Hm, przypuszczam, że by tak było, prawda? MySQL pozwala mi tylko oszukiwać z grupą i zwraca wiersz o najniższym numerze, czy nie, zamiast sensownie oceniać to ... westchnienie – Joe