2010-08-19 3 views
2

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

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

С помощью одного запроса я хотел бы извлечь ВСЕ информацию о пользователе, а также всю информацию о карте только для самой последней карты (поле: ИЗДАНИЕ).

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

ПОЛЬЗОВАТЕЛЕЙ стол

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

КАРТОЧКИ стол

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 ad.

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

+0

Следуйте тегу 'great-n-per-group' для десятков других подобных вопросов по переполнению стека. –

+0

«Что произойдет, если нет КАРТЫ, связанной с пользователем?» Что вы хотите? Либо никакие записи не могут быть возвращены, либо поля записи из таблицы CARDS могут быть установлены в NULL. – strager

+0

Да, мое редактирование не было ясным, извините. Оптимальным было бы получить набор значений NULL для всех столбцов CARDS, если у пользователя еще нет карты. – Danilo

ответ

1

Вариант 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 с предельными

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 
1
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 

) 
+0

Почему объединенный выбор в разделе IN? 'выберите MAX (IDCARD) в качестве группы IDCARD с помощью CARDS.IDOWNER' должно быть достаточно. –

1

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) 
Смежные вопросы