Простой запрос для получения максимального значения для каждого идентификатора

StackOverflow https://stackoverflow.com/questions/755918

Вопрос

Хорошо, у меня есть такая таблица:

ID     Signal    Station    OwnerID
111     -120      Home       1
111     -130      Car        1
111     -135      Work       2
222     -98       Home       2
222     -95       Work       1
222     -103      Work       2

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

ID    Signal    Station    OwnerID
111   -120      Home        1
222   -95       Work        1

Я попробовал использовать MAX(), но агрегация не удалась: Station и OwnerID различаются для каждой записи.Нужно ли мне делать JOIN?

Это было полезно?

Решение

Что-то вроде этого?Соедините таблицу сама с собой и исключите строки, для которых был найден более высокий сигнал.

select cur.id, cur.signal, cur.station, cur.ownerid
from yourtable cur
where not exists (
    select * 
    from yourtable high 
    where high.id = cur.id 
    and high.signal > cur.signal
)

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

Другие советы

Вы выполняете групповую операцию максимума/минимума.Это распространенная ловушка:Кажется, что это должно быть легко сделать, но в SQL это, к сожалению, не так.

Существует ряд подходов (как стандартных ANSI, так и специфичных для конкретного поставщика) к этой проблеме, большинство из которых во многих ситуациях неоптимальны.Некоторые дадут вам несколько строк, если более чем одна строка имеет одно и то же максимальное/минимальное значение;некоторые не будут.Некоторые хорошо работают с таблицами с небольшим количеством групп;другие более эффективны для большего количества групп с меньшим количеством строк в каждой группе.

Вот обсуждение из некоторых распространенных (предвзятых к MySQL, но в целом применимых).Лично, если я знаю, что нет множественных максимумов (или меня не волнует их получение), я часто склоняюсь к методу самосоединения с нулевым левым значением, который я опубликую, поскольку еще никто не делал:

SELECT reading.ID, reading.Signal, reading.Station, reading.OwnerID
FROM readings AS reading
LEFT JOIN readings AS highersignal
    ON highersignal.ID=reading.ID AND highersignal.Signal>reading.Signal
WHERE highersignal.ID IS NULL;

В классическом SQL-92 (без использования операций OLAP, используемых Quassnoi) вы можете использовать:

SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID
  FROM (SELECT id, MAX(Signal) AS MaxSignal
          FROM t
          GROUP BY id) AS g
       JOIN t ON g.id = t.id AND g.MaxSignal = t.Signal;

(Непроверенный синтаксис;предполагает, что ваша таблица равна «t».)

Подзапрос в предложении FROM определяет максимальное значение сигнала для каждого идентификатора;соединение объединяет это с соответствующей строкой данных из основной таблицы.

Примечание:Если для определенного идентификатора есть несколько записей, которые имеют одинаковую мощность сигнала и эта мощность равна MAX(), то вы получите несколько выходных строк для этого идентификатора.


Протестировано на IBM Informix Dynamic Server 11.50.FC3, работающем на Solaris 10:

+ CREATE TEMP TABLE signal_info
(
    id      INTEGER NOT NULL,
    signal  INTEGER NOT NULL,
    station CHAR(5) NOT NULL,
    ownerid INTEGER NOT NULL
);
+ INSERT INTO signal_info VALUES(111, -120, 'Home', 1);
+ INSERT INTO signal_info VALUES(111, -130, 'Car' , 1);
+ INSERT INTO signal_info VALUES(111, -135, 'Work', 2);
+ INSERT INTO signal_info VALUES(222, -98 , 'Home', 2);
+ INSERT INTO signal_info VALUES(222, -95 , 'Work', 1);
+ INSERT INTO signal_info VALUES(222, -103, 'Work', 2);
+ SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID
  FROM (SELECT id, MAX(Signal) AS MaxSignal
            FROM signal_info
            GROUP BY id) AS g
      JOIN signal_info AS t  ON g.id = t.id AND g.MaxSignal = t.Signal;

111     -120    Home    1
222     -95     Work    1

Для этого теста я назвал таблицу Signal_Info, но, похоже, она дает правильный ответ.Это показывает только то, что существует хотя бы одна СУБД, поддерживающая эту нотацию.Однако я немного удивлен, что MS SQL Server этого не делает — какую версию вы используете?


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


with tab(id, sig, sta, oid) as
(
select 111 as id, -120 as signal, 'Home' as station, 1 as ownerId union all
select 111, -130, 'Car',  1 union all
select 111, -135, 'Work', 2 union all
select 222, -98, 'Home',  2 union all
select 222, -95, 'Work',  1 union all
select 222, -103, 'Work', 2
) ,
tabG(id, maxS) as
(
   select id, max(sig) as sig from tab group by id
)
select g.*, p.* from tabG g
cross apply ( select  top(1) * from tab t where t.id=g.id order by t.sig desc ) p

WITH q AS
         (
         SELECT  c.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY signal DESC) rn
         FROM    mytable
         )
SELECT   *
FROM     q
WHERE    rn = 1

Это вернет одну строку, даже если есть дубликаты MAX(signal) для данного ID.

Наличие индекса на (id, signal) значительно улучшит этот запрос.

Мы можем сделать, используя самостоятельное присоединение

SELECT  T1.ID,T1.Signal,T2.Station,T2.OwnerID
FROM (select ID,max(Signal) as Signal from mytable group by ID) T1
LEFT JOIN mytable T2
ON T1.ID=T2.ID and T1.Signal=T2.Signal;

Или вы также можете использовать следующий запрос

SELECT t0.ID,t0.Signal,t0.Station,t0.OwnerID 
FROM mytable t0 
LEFT JOIN mytable t1 ON t0.ID=t1.ID AND t1.Signal>t0.Signal 
WHERE t1.ID IS NULL;
select a.id, b.signal, a.station, a.owner from 
mytable a
join 
(SELECT ID, MAX(Signal) as Signal FROM mytable GROUP BY ID) b
on a.id = b.id AND a.Signal = b.Signal 
SELECT * FROM StatusTable
WHERE Signal IN (
    SELECT A.maxSignal FROM
    (
        SELECT ID, MAX(Signal) AS maxSignal
        FROM StatusTable
        GROUP BY ID
    ) AS A
);

Выберите ID, max_signal, владелец, владелец из (select *, rank () over (раздел по идентификатору по порядку по сигналу) как max_signal из таблицы), где max_signal = 1;

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top