MySQL Выберите разные значения в нескольких таблицах - PullRequest
1 голос
/ 06 мая 2010

У меня есть две таблицы:

table_1
uid | xid | name

table_2
uid | elements | time | pkey

Я хочу выбрать несколько строк xid, элементов и времени, где время - это 10 самых маленьких значений, а uid (или xid) различны.

uid, xid in в table_1 уникален, и отношение между uid в table_1 и table_2 одно ко многим ..

Я пробовал что-то подобное, но это не очень хорошо работает:

SELECT table_1.xid, MIN(table_2.time), table_2.elements
FROM table_1, table_2
WHERE table_1.uid= table_2.uid
GROUP BY table_2.uid
LIMIT 10

Давайте поэкспериментируем с данными:

table_1
uid | xid | name
1 | 435 | John
2 | 596 | Jane


table_2
uid | elements | time | pkey
1 | 1 | 567 | 0
2 | 2 | 335 | 1
1 | 1 | 435 | 2
1 | 2 | 456 | 3
2 | 1 | 337 | 4
1 | 1 | 428 | 5

Как бы я выбрал 2 лучших результата для каждого UID? В этом случае:

fid| elements | time
596| 2 | 335
435| 1 | 428

Спасибо !!!

В случае, если люди не понимают, почему решение lexu не работает - оно не привязывается к первичному ключу в таблице 2

Если я изменю вышеуказанные данные на:

table_2
uid | elements | time | pkey
1 | 1 | 567 | 0
2 | 2 | 335 | 1
1 | 1 | 435 | 2
1 | 2 | 456 | 3
2 | 1 | 337 | 4
1 | 2 | 428 | 5

Оставьте table_1 таким же, тогда результат должен быть:

fid| elements | time
596| 2 | 335
435| 2 | 428

но с решением @ lexu результат будет:

fid| elements | time
596| 2 | 335
435| 1 | 428

Тем не менее, спасибо всем за помощь и особенно @eagle!

1 Ответ

1 голос
/ 06 мая 2010

Вот мое решение.Я подумал, что вместо того, чтобы просто дать рабочий запрос, я буду шаг за шагом проходить свой мыслительный процесс и запросы, которые я пробовал на каждом шаге:

Сначала давайте выберем 10 наименьших раз для различных uid:

select uid, min(time)
from table_2
group by uid
order by 2
limit 10

Это дает нам:

uid | time
2 | 335
1 | 428

Это было легко ... к сожалению, это не позволяет нам получить первичный ключ, что будет проблемой, еслидобавлена ​​следующая строка:

table_2
uid | elements | time | pkey
1 | 2 | 428 | 6

В будущих запросах, когда мы попытаемся объединиться на time и uid, мы получим две записи, а не 1. Поэтому нам нужен лучший запрос, которыйвозвращает отличное значение (например, pkey), а не time, которое, как я предполагаю, может быть не различимым ...

Примечание: это было бы намного проще, если бы MySQL имел FIRST() или LAST() агрегатные функции.К сожалению, это не так, поэтому мы должны согласиться на комбинирование подзапроса, order-by, limit.

select
  t2.uid,
  (select pkey from table_2 t3 where t2.uid = t3.uid order by t3.time asc limit 1) as minpkey
from
  (select uid, min(time) from table_2 group by uid order by 2 limit 10) t2

Теперь будут возвращаться результаты, с которыми мы можем работать:

uid | minpkey
1 | 5
2 | 1

Обратите внимание, что 5 был выбран случайным образом, и 6 могли быть выбраны так же легко;все зависит от того, как MySQL решит выбрать его.Но для нас это не имеет значения.

Далее мы хотим показать больше данных (а именно полей xid и elements):

select t1.xid as fid, t5.elements, t5.time
from 
(select
  t2.uid,
  (select pkey from table_2 t3 where t2.uid = t3.uid order by t3.time asc limit 1) as minpkey
from
  (select uid, min(time) from table_2 group by uid order by 2 limit 10) t2
) t4
inner join table_1 t1 on (t4.uid = t1.uid)
inner join table_2 t5 on (t4.minpkey = t5.pkey)

И альт, это должновернуть те же данные, которые вы предоставили в своем примере!Это может быть не очень эффективно, но должно работать!

...