2013-05-23 2 views
0

Упрощенная версия моей проблемы. У меня есть 2 таблицы:Mysql - возвращает строки, которые не имеют связанных записей в другой таблице плюс max, которые имеют записи

набрано:

id code_id score 
1 11  100 
2 12  20 
3 13  40 
4 14  70 
5 15  90 
6 16  10 
7 17  30 
8 18  50 

коды:

id code 
11 
12 
13 
14 
15 
16 BBB 
17 BBB 
18 BBB 

Мне нужно, чтобы произвести запрос Mysql SELECT, который будет возвращать все строки из таблицы Множества, которые не имеют никаких связанных кодов в таблице Кодов плюс только самый высокий балл из строк, которые имеют одинаковые коды в таблице Коды.

Требуемый выход показан ниже. Идентификаторы 1-5 баллов присутствуют, поскольку у них нет связанного кода, но выбран только ID 8, потому что он является самым высоким значением всех баллов с BBB-кодом.

id code_id score 
1 11  100 
2 12  20 
3 13  40 
4 14  70 
5 15  90 
8 18  50 

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

Большое спасибо.

+0

У вас действительно есть код запись 11-15 без значения коды? в этом случае данные делают это более сложным. Без этих данных это может быть проще сделать. – xQbert

ответ

2

Возможно, я что-то упустил с вашими требованиями, но было бы проще использовать UNION ALL между двумя запросами.

Чтобы получить те строки, которые имеют null код в codes таблице вы можете использовать:

select s.id, s.code_id, s.score 
from scores s 
where exists (select id 
       from codes c 
       where s.code_id = c.id 
       and c.code is null) 

Тогда, чтобы получить max(score) для каждого code, вы можете использовать:

select s.id, s.code_id, s.score 
from scores s 
inner join codes c 
    on s.code_id = c.id 
inner join 
(
    select c.code, max(s.score) score 
    from scores s 
    inner join codes c 
    on s.code_id = c.id 
    where c.code is not null 
    group by c.code 
) m 
    on c.code = m.code 
    and s.score = m.score; 

Наконец вы может использовать UNION ALL для объединения двух запросов:

select s.id, s.code_id, s.score 
from scores s 
where exists (select id 
       from codes c 
       where s.code_id = c.id 
       and c.code is null) 
union all 
select s.id, s.code_id, s.score 
from scores s 
inner join codes c 
    on s.code_id = c.id 
inner join 
(
    select c.code, max(s.score) score 
    from scores s 
    inner join codes c 
    on s.code_id = c.id 
    where c.code is not null 
    group by c.code 
) m 
    on c.code = m.code 
    and s.score = m.score 
    group by c.code //To remove duplicates where the code and the score are equal 

См. SQL Fiddle with Demo.

Редактировать как примечание стороны, если значение code пустая строка и не null, то вы можете изменить код, чтобы использовать '' (см demo).

+0

Большое спасибо за этот подробный быстрый ответ bluefeet. Я поставлю его на тест утром. Выглядит надеяться ;-) – Termine

+0

@Termine Добро пожаловать, сообщите мне, есть ли какие-либо проблемы. :) – Taryn

+0

Извините bluefeet. Я не сделал себе достаточно ясно.ID 8 показан в моих желаемых результатах, потому что он имеет самый высокий балл не потому, что он имеет самый высокий ID. Я работаю в этом сейчас и буду публиковать, если я его взломаю. – Termine

1

Попробуйте это:

select s.* 
from scores s join 
    (select coalesce(code, cast(id as varchar(32))) as codeid, max(id) as id 
     from codes c 
     group by coalesce(code, cast(id as varchar(32))) 
    ) c 
    on s.code_id = c.id; 

Идея заключается в том, чтобы обобщить таблицу кодов, чтобы получить максимальный идентификатор каждого кода, а также одну строку для каждого идентификатора, где код является NULL.

Ниже показаны результаты (извинения, это для SQL Server, но код будет очень похож там):

declare @scores table (id int identity(1, 1), code_id int, score int); 

insert into @scores(code_id, score) 
    select 11, 100 union all 
    select 12, 20 union all 
    select 13, 40 union all 
    select 14, 70 union all 
    select 15, 90 union all 
    select 16, 30 union all 
    select 17, 30 union all 
    select 18, 50; 

declare @codes table (id int, code varchar(3)); 

insert into @codes(id, code) 
    select 11, NULL union all 
    select 12, NULL union all 
    select 13, NULL union all 
    select 14, NULL union all 
    select 15, NULL union all 
    select 16, 'BBB' union all 
    select 17, 'BBB' union all 
    select 18, 'BBB'; 

select s.* 
from @scores s join 
    (select coalesce(code, cast(id as varchar(32))) as codeid, max(id) as id 
     from @codes c 
     group by coalesce(code, cast(id as varchar(32))) 
    ) c 
    on s.code_id = c.id 
+0

Спасибо, Гордон. Это не выглядит слишком дружелюбным Mysql, но я постараюсь заставить его работать, если я не могу сделать это с помощью более простого запроса. – Termine

+0

@Termine. , , Сам запрос является стандартным SQL. Единственная проблема - использование переменной таблицы вместо временной таблицы для тестирования. Он должен отлично работать в MySQL на ваших данных. –

Смежные вопросы