dnibbo Ответов: 4

Sql получает другие поля из записи, возвращающей максимальное значение


SQL-это не мой родной язык!

Я хочу найти строку с помощью функции MAX, но возвращаю другие столбцы из этой строки.
Не уверен, что это вообще возможно?

Допустим, у нас есть простая таблица:

Счет, Счет-Фактура, Дата-Время, Стоимость

Я хочу получить последнюю дату и время для каждой учетной записи и значение, связанное с этой строкой. Давайте притворимся, что индексов нет, и счет-фактура не гарантированно будет находиться в каком-то определенном порядке.

Так что я могу сказать:

SELECT Account, MAX(DateTime) AS Maxdate FROM Table GROUP BY Account


Пока все хорошо, но я также хочу вернуть столбец value из строки, которая вернула последнюю дату и время, но как я могу это сделать?
Я знаю, что могу внутренне присоединиться к тому же столу, но стол огромен, и это очень медленно.

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

Это не моя база данных, поэтому я не имею права добавлять какие-либо индексы...!

Большое спасибо в предвкушении.

Что я уже пробовал:

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

4 Ответов

Рейтинг:
4

dnibbo

Спасибо всем за ваше время и предложения.

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

Возможно, мне следовало бы упомянуть, что количество "счетов" относительно невелико, но таблица содержит более 30 миллионов строк....

Теперь я использую

SELECT Phase1.Account, MaxDate, Value FROM
( SELECT Account, MAX(DateTime) FROM Table 
  GROUP BY Account ) Phase1
INNER JOIN Table T2 ON T2.Account = Phase1.Account AND T2.DateTime = MaxDate

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

То, что я обнаружил, было еще быстрее (имея в виду, что этот запрос используется в коде .NET), это сделать первый выбор:
SELECT Account, MAX(DateTime) FROM Table GROUP BY Account

А затем перебирать результаты, генерируя SQL-запрос select / union:
SELECT TOP 1 Account, MaxDate, Value FROM Table WHERE Account = '<Account1>' AND DateTime = '<maxdate1>'
UNION
SELECT TOP 1 Account, MaxDate, Value FROM Table WHERE Account = '<Account2>' AND DateTime = '<maxdate2>'


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



Еще раз спасибо за все ответы.


RickZeeland

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

Рейтинг:
1

RickZeeland

Вы можете попробовать это онлайн по адресу: Скрипка SQL[^]

CREATE TABLE ForgeRock
    ([productName] varchar(13), 
     [description] varchar(57),
     [price] int)
;
    
INSERT INTO ForgeRock
    ([productName], [description], [price])
VALUES
    ('OpenIDM', 'Platform for building enterprise provisioning solutions', 1),
    ('OpenAM', 'Full-featured access management', 2),
    ('OpenDJ', 'Robust LDAP server for Java', 3)
;


SELECT a.productName, a.description, a.price FROM ForgeRock a
	JOIN (SELECT MAX(t.price) AS max_subkey
	FROM ForgeRock t) b 
    ON b.max_subkey = a.price


dnibbo

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

Рейтинг:
1

JJ-DBA

-- Временные столы на выручку моему другу


create table maxdate(Account varchar(255),thedate datetime,thevalue int)

insert into maxdate(Account,thedate,thevalue) values('joe bloggs','2017-06-25',4)
insert into maxdate(Account,thedate,thevalue) values('joe bloggs','2017-06-26',2)
insert into maxdate(Account,thedate,thevalue) values('joe bloggs','2017-06-27',1)
insert into maxdate(Account,thedate,thevalue) values('joe bloggs','2017-06-28',8)
insert into maxdate(Account,thedate,thevalue) values('joe bloggs','2017-06-29',16)

insert into maxdate(Account,thedate,thevalue) values('Superman','2017-05-25',16)
insert into maxdate(Account,thedate,thevalue) values('Superman','2017-05-26',8)
insert into maxdate(Account,thedate,thevalue) values('Superman','2017-05-27',4)
insert into maxdate(Account,thedate,thevalue) values('Superman','2017-05-28',2)
insert into maxdate(Account,thedate,thevalue) values('Superman','2017-05-29',1)

insert into maxdate(Account,thedate,thevalue) values('Batman','2017-05-25',1)
insert into maxdate(Account,thedate,thevalue) values('Batman','2017-05-26',2)
insert into maxdate(Account,thedate,thevalue) values('Batman','2017-05-27',3)
insert into maxdate(Account,thedate,thevalue) values('Batman','2017-05-28',4)
insert into maxdate(Account,thedate,thevalue) values('Batman','2017-05-29',5)

if OBJECT_ID('tempdb..#accountlatestdate') is not null
begin
	drop table #accountlatestdate 
end 

SELECT Account,MAX(thedate) AS Maxdate
into #accountlatestdate
FROM maxdate
group by Account

select b.* 
from #accountlatestdate a 
join maxdate b on a.Account = b.Account and a.Maxdate = b.thedate


Результаты

joe bloggs	2017-06-29 00:00:00.000	16
Superman	2017-05-29 00:00:00.000	1
Batman	2017-05-29 00:00:00.000	5


dnibbo

Спасибо за ваше время и ваш ответ. Однако, согласно предложению 1, думаю, что в любом случае у меня будет только разрешение на чтение.

Рейтинг:
0

Richard Deeming

Предполагая, что вы используете Microsoft SQL Server 2008 или более позднюю версию, НОМЕР СТРОКИ[^] функция, вероятно, поможет:

WITH cteOrderedData As
(
    SELECT
        Account,
        DateTime,
        Value,
        ROW_NUMBER() OVER (PARTITION BY Account ORDER BY DateTime DESC) As RN
    FROM
        Table
)
SELECT 
    Account, 
    DateTime AS Maxdate,
    Value
FROM 
    cteOrderedData
WHERE
    RN = 1
;


dnibbo

Привет, спасибо за предложение. Я попробовал ваш метод, и он действительно работает, но все равно результаты медленные. В этом виноват плохой дизайн БД...
Я добавлю то, что считаю самым быстрым решением.
Спасибо, что уделили мне время.