2009-12-25 1 views
2

Я хочу, чтобы получитьSQL проблема, проблема

id a b  c 
-------------------- 
1 1 100 90 
6 2 50 100 

... от:

id a b  c 
-------------------- 
1 1 100 90 
2 1 300 50 
3 1 200 20 
4 2 200 30 
5 2 300 70 
6 2 50 100 

Это строка с наименьшим Ь группы а.

Как это сделать с sql?

EDIT

Я думал, что это может быть достигнуто за счет

select * from table group by a having min(b); 

который я нашел позже, что это неправильно.

Но можно ли это сделать с заявлением having?

Я использую MySQL

+1

Добавлен тег 'great-n-per-group', потому что этот вопрос по существу такой же, как и многие другие, заданные в StackOverflow. –

+1

Что делать, если я добавил следующую строку в ваши данные образца: 'insert into mytable (id, a, b, c) значения (7, 2, 50, 80);' Какую строку вы ожидаете получить в своем запросе: 'id = 6' или' id = 7'? и то и другое? – Asaph

+1

Хорошая точка - должны ли быть связи (где есть две строки с одинаковым минимальным значением b), как бы одна строка была выбрана над другой? –

ответ

3
SELECT t1.* 
FROM mytable t1 
LEFT OUTER JOIN mytable t2 
    ON (t1.a=t2.a AND t1.b>t2.b) 
WHERE t2.a IS NULL; 

Это работает потому, что не должно быть никакой соответствующей строки t2 с тем же a и в меньшей b.


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

SELECT t1.* 
FROM mytable t1 
LEFT OUTER JOIN mytable t2 
    ON (t1.a=t2.a AND (t1.b>t2.b OR t1.b=t2.b AND t1.id>t2.id)) 
WHERE t2.a IS NULL; 

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


Это не делает трюк:

select * from table group by a having min(b); 

Поскольку HAVING MIN(b) только проверяет, что наименьшее значение в группе не является ложным (что в MySQL означает не ноль). Условие в предложении HAVING предназначено для исключения групп из результата, а не для выбора строки в возвращаемой группе.

+0

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

0

Вы правы. выберите min (b), a из группы таблиц a. Если вы хотите всю строку, то вы используете функцию analytics. Это зависит от базы данных s/w.

1

Использование:

SELECT DISTINCT 
     x.* 
    FROM TABLE x 
    JOIN (SELECT t.a, 
       MIN(t.b) 'min_b' 
      FROM TABLE T 
     GROUP BY t.a) y ON y.a = x.a 
        AND y.min_b = x.b 
+0

Когда я пытаюсь это сделать в MySQL (используя команды 'create table' и' insert' из моего ответа, чтобы настроить и настроить имена таблиц для соответствия), я получаю 'ERROR 1054 (42S22): Неизвестный столбец 'ta' in 'on clause''. – Asaph

+0

Вероятно, следует использовать 'ON y.a = x.a AND y.min_b = x.b' в соединении. –

+0

К сожалению - слишком много eggnog, исправлено. –

3

В MySQL:

select t1.* from test as t1 
inner join 
(select t2.a, min(t2.b) as min_b from test as t2 group by t2.a) as subq 
on subq.a=t1.a and subq.min_b=t1.b; 

Вот доказательство:

mysql> create table test (id int unsigned primary key auto_increment, a int unsigned not null, b int unsigned not null, c int unsigned not null) engine=innodb; 
Query OK, 0 rows affected (0.55 sec) 

mysql> insert into test (a,b,c) values (1,100,90), (1,300,50), (1,200,20), (2,200,30), (2,300,70), (2,50,100); 
Query OK, 6 rows affected (0.39 sec) 
Records: 6 Duplicates: 0 Warnings: 0 

mysql> select * from test; 
+----+---+-----+-----+ 
| id | a | b | c | 
+----+---+-----+-----+ 
| 1 | 1 | 100 | 90 | 
| 2 | 1 | 300 | 50 | 
| 3 | 1 | 200 | 20 | 
| 4 | 2 | 200 | 30 | 
| 5 | 2 | 300 | 70 | 
| 6 | 2 | 50 | 100 | 
+----+---+-----+-----+ 
6 rows in set (0.00 sec) 

mysql> select t1.* from test as t1 inner join (select t2.a, min(t2.b) as min_b from test as t2 group by t2.a) as subq on subq.a=t1.a and subq.min_b=t1.b; 
+----+---+-----+-----+ 
| id | a | b | c | 
+----+---+-----+-----+ 
| 1 | 1 | 100 | 90 | 
| 6 | 2 | 50 | 100 | 
+----+---+-----+-----+ 
2 rows in set (0.00 sec) 
+1

Повторите попытку после выполнения «вставки в тестовые значения (7,2,100,95)», и это не сработает. –

+0

Это работает только в том случае, если MIN (b) для каждой группы a, * never * отображается как не-MIN() s в другой группе-a. Например, для таблицы {a, b} (1200), (2100), (2200); он вернет все три строки, хотя есть только две группы. – RBarryYoung

+0

Почему люди этим занимаются? Это, безусловно, один из немногих неправильных ответов здесь. – RBarryYoung

0

Это зависит от реализации, но это, как правило, быстрее, чем само- метод объединения:

SELECT id, a, b, c 
FROM 
    (
     SELECT id, a, b, c 
     , ROW_NUMBER() OVER(PARTITION BY a ORDER BY b ASC) AS [b IN a] 
    ) As SubqueryA 
WHERE [b IN a] = 1 

Конечно, это требует, чтобы реализация SQL была достаточно актуальной со стандартом.

+0

Интересно, что будет работать на Oracle 9i + и SQL Server 2005 +, но не MySQL. –

+0

В последней версии MySQL еще нет функции ROW_NUMBER()? Это настоящий позор, очень полезный (и был в стандарте на некоторое время сейчас). – RBarryYoung

+0

Последнее, что я проверил, MySQL имеет нет функциональности ранжирования вообще:/ –