SQL: один ко многим, выберите только один - PullRequest
2 голосов
/ 20 августа 2010

Я пишу небольшой инструмент для управления людьми, зарегистрированными в ассоциации.

У меня есть таблица USERS и таблица CARDS. Каждый пользователь может иметь более одной карты (поскольку срок действия карт истекает).

С помощью одного запроса я хотел бы извлечь ВСЕ пользовательские данные плюс ВСЕ данные карты только для самой последней карты (поле: ISSUEDATE).

Вот очень простой пример:

Таблица ПОЛЬЗОВАТЕЛЕЙ

IDUSER  NAME    SURNAME
------------------------
1       Robert  Hill

Стол CARDS

IDCARD  IDOWNER  ISSUEDATE   DESC 
----------------------------------------
1       1        2010-01-01  'CARD ONE'
2       1        2010-08-18  'CARD TWO'

В основном я хотел бы получить из своего запроса следующие поля:

IDUSER  NAME     SURNAME  IDCARD  IDOWNER  ISSUEDATE   DESC
---------------------------------------------------------------
1       Robert   Hill     2       1        2010-08-18  'CARD TWO'

Я пытался, но я не могу управлять: (

EDIT: Что произойдет, если с пользователем не будет НИКАКОЙ КАРТЫ? (зарегистрирован один пользователь, но ассоциация еще не дала ему ни одной карты). Есть ли способ адаптировать этот запрос, чтобы в любом случае вернуть информацию о пользователе? Идея состоит в том, чтобы получить всю возможную информацию для каждого пользователя. Эта информация позже используется через JSON в приложении ExtJS.

Спасибо за ваши ответы.

Ответы [ 3 ]

1 голос
/ 20 августа 2010
select u.IDUSER, u.NAME, u.SURNAME,
       c.IDCARD, c.IDOWNER, c.ISSUEDATE, c.DESC
from USERS u
join CARDS c on u.IDUSER = c.IDOWNER and c.IDCARD in (
     /* select biggest IDCARD numbers that has same IDOWNER thus eliminating multiple rows and remaining only 1 for each IDOWNER */
     select MAX(IDCARD) as IDCARD
     from USERS join CARDS on USERS.IDUSER = CARDS.IDOWNER
     group by CARDS.IDOWNER

)
1 голос
/ 21 августа 2010

Altho LIMIT обычно не допускается в подзапросах mysql, LIMIT 1 является исключением, поэтому «Выберите только один» идеально подходит для этого случая.

LEFT JOIN гарантирует, что у вас также будут пользователи без данных карты (данные карты будут NULL, вы можете использовать ifnull(desc, 'No Card Issued'), чтобы отобразить это по своему желанию)

и подзапрос гарантирует, что будут выбраны только самые последние данные карты для пользователя.

SELECT * 
  FROM users u 
       LEFT JOIN cards c 
         ON c.idcard = (SELECT idcard 
                          FROM cards c1 
                         WHERE c1.idowner = u.iduser 
                         ORDER BY issuedate DESC 
                         LIMIT 1) 
1 голос
/ 20 августа 2010

Вариант 1 с запросом NOT EXISTS:

select u.IDUSER, u.NAME, u.SURNAME,
       c.IDCARD, c.IDOWNER, c.ISSUEDATE, c.DESC
from USERS u
join CARDS c on u.IDUSER = c.IDOWNER
where not exists (select 1 from CARDS where IDOWDER = u.IDUSER and ISSUEDATE > c.ISSUEDATE)

Вариант 2 с LIMIT

select u.IDUSER, u.NAME, u.SURNAME,
       c.IDCARD, c.IDOWNER, c.ISSUEDATE, c.DESC
from USERS u
join CARDS c on u.IDUSER = c.IDOWNER
order by c.ISSUEDATE desc
LIMIT 1
...