2011-02-10 2 views
0

У меня есть таблица с парами имя-значение и дополнительный атрибут. Одно и то же имя может иметь более одного значения. Если это произойдет, я хочу вернуть строку с более высоким значением атрибута.Запрос уникальных значений Mysql

Таблица:

ID | name | value | attribute 
1 | set1 | 1  | 0 
2 | set2 | 2  | 0 
3 | set3 | 3  | 0 
4 | set1 | 4  | 1 

Желаемые результаты запроса:

name | value 
set2 | 2 
set3 | 3 
set1 | 4 

Что является лучшим выполнения SQL-запрос, чтобы получить желаемые результаты?

+0

ли значение 'атрибута' имеет значение? – BoltClock

+0

Да, это сложная часть. Я не ищу значение в строке с самым высоким атрибутом. Я думаю, что ему нужно внутреннее соединение, но я не уверен, как его написать. – pmm

+0

Как насчет связей? Предположим, что есть еще одна строка: (5, set1, 5, 1). Должны ли возвращаться строки 4 или строки 5? – Thomas

ответ

0

Это решение вероятно, будет работать следующим образом:

Select ... 
From Table As T 
    Left Join Table As T2 
     On T2.name = T.name 
      And T2.attribute > T1.attribute 
Where T2.ID Is Null 

Другое решение, которое может не быть перфомансом ОРМ, а также (вы должны оценить против ваших данных):

Select ... 
From Table As T 
Where Not Exists (
        Select 1 
        From Table As T2 
        Where T2.name = T.name 
         And T2.attribute > T.attribute 
        ) 
0
select name,max(value) 
from table 
group by name 
+0

Это не будет делать то, что задает вопрос. Вопрос запрашивает строки с самым высоким атрибутом, а не самым высоким значением. –

0

Нет простого способа сделать это.

Аналогичный вопрос был задан here.

Edit: Вот предложение:

SELECT `name`,`value` FROM `mytable` ORDER BY `name`,`attribute` DESC 

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

Редактировать снова: Еще одно предложение:

Если вы знаете, что value является положительным целым числом, то вы можете сделать это. Это здорово, но это сработает.

SELECT `name`,CAST (GROUP_CONCAT(`value` ORDER by `attribute` DESC) as UNSIGNED) FROM `mytable` GROUP BY `name` 

Чтобы включить отрицательные числа можно изменить UNSIGNED к SIGNED.

+0

К сожалению, значение может быть любым, поэтому это не сработает. – pmm

0
SELECT name, value 
FROM (SELECT name, value, attribute 
     FROM table_name 
     ORDER BY attribute DESC) AS t 
GROUP BY name; 
+0

Стандарт SQL не позволяет неагрегатные столбцы (в данном случае 'значение') в списке выбора. Возможно, он работает, но теоретически MySQL может возвращать любое «значение» в случайном порядке. – awm

+0

Я собирался проверить этот ответ, так как я тестировал его, и он работает хорошо, но теперь меня смущает комментарий awm. – pmm

+0

@awm group_concat - это совокупная функция справа? Некоторые простые манипуляции с ним, чтобы получить первое значение, должны соответствовать стандарту. Но теперь мы направляемся в грязную территорию. например измените первый SELECT на «SELECT name», substring_index (group_concat (value), ',', 1) как значение ». –

0

Возможно, вы захотите сравнить все эти варианты, вот еще один.

SELECT t1.name, t1.value 
    FROM temp t1 
WHERE t1.attribute IN (
    SELECT MAX(t2.attribute) 
    FROM temp t2 
    WHERE t2.name = t1.name); 
+0

+1 Это довольно неэффективный запрос, но до сих пор это ** только ** ответ, который фактически делает то, что было задано. – awm

+1

: D, мы могли бы предложить ему нормализовать таблицы. – phfeenikz

+0

сделайте пожалуйста. Как бы вы нормализовали таблицы, а затем как бы вы выполняли запрос? – pmm

0

Как насчет:

SELECT ID, name, value, attribute 
    FROM table A 
WHERE A.attribute = (SELECT MAX(B.attribute) FROM table B WHERE B.NAME = A.NAME); 

Edit: Похоже, кому-то уже сказал то же самое.

1

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

select 
s.set_id, 
s.name as set_name, 
a.attrib_id, 
a.name as attrib_name, 
sav.value 
from 
sets s 
inner join set_attribute_values sav on 
    sav.set_id = s.set_id and sav.attrib_id = s.max_attrib_id 
inner join attributes a on sav.attrib_id = a.attrib_id 
order by 
s.set_id; 

+--------+----------+-----------+-------------+-------+ 
| set_id | set_name | attrib_id | attrib_name | value | 
+--------+----------+-----------+-------------+-------+ 
|  1 | set1  |   3 | attrib3  | 20 | 
|  2 | set2  |   0 | attrib0  | 10 | 
|  3 | set3  |   0 | attrib0  | 10 | 
|  4 | set4  |   4 | attrib4  | 10 | 
|  5 | set5  |   2 | attrib2  | 10 | 
+--------+----------+-----------+-------------+-------+ 

явно для этой работы вы собираетесь также нормализовать свой дизайн и реализовать простой триггер:

drop table if exists attributes; 
create table attributes 
(
attrib_id smallint unsigned not null primary key, 
name varchar(255) unique not null 
) 
engine=innodb; 

drop table if exists sets; 
create table sets 
(
set_id smallint unsigned not null auto_increment primary key, 
name varchar(255) unique not null, 
max_attrib_id smallint unsigned not null default 0, 
key (max_attrib_id) 
) 
engine=innodb; 

drop table if exists set_attribute_values; 
create table set_attribute_values 
(
set_id smallint unsigned not null, 
attrib_id smallint unsigned not null, 
value int unsigned not null default 0, 
primary key (set_id, attrib_id) 
) 
engine=innodb; 

delimiter # 

create trigger set_attribute_values_before_ins_trig 
before insert on set_attribute_values 
for each row 
begin 
    update sets set max_attrib_id = new.attrib_id 
    where set_id = new.set_id and max_attrib_id < new.attrib_id; 
end# 

delimiter ; 

insert into attributes values (0,'attrib0'),(1,'attrib1'),(2,'attrib2'),(3,'attrib3'),(4,'attrib4'); 
insert into sets (name) values ('set1'),('set2'),('set3'),('set4'),('set5'); 

insert into set_attribute_values values 
(1,0,10),(1,3,20),(1,1,30), 
(2,0,10), 
(3,0,10), 
(4,4,10),(4,2,20), 
(5,2,10); 
0

ли не сравнить их, но вот как это выполнимо: TableName = ТСМОС

1) Строка с максимальным значением атрибута :

select t.name, t.value 
from (
    select name, max(attribute) as maxattr 
    from temm group by name 
) as x inner join temm as t on t.name = x.name and t.attribute = x.maxattr; 

2) Топ N строк с максимальным значением атрибута:

select name, value 
from temm 
where (
    select count(*) from temm as n 
    where n.name = temm.name and n.attribute > temm.attribute 
) < 1 ; /* 1 can be changed to 2,3,4 ..N to get N rows */ 
Смежные вопросы