Есть БД, в которой хрянятся записи о товарах и тех, кто им торгует.
Во-первых, состояние товара может изменяться со временем, поэтому структура таблицы с описанием его примерно такая:
CREATE TABLE description (id, fk, since TIMESTAMP, остальные поля, UNIQUE(fk, since));
Нужно уметь выбирать самую новую запись. Сделал так:
SELECT * FROM description d WHERE since >= ALL(SELECT since FROM description d2 WHERE d2.fk = d.fk);
оно-то работает, но выглядит некрасиво. Эдакое недосамообъединение. Как сделать по-человечески?
Данные о продавцах хранятся примерно так:
CREATE TABLE term (id, fk, since TIMESTAMP, agent, price DECIMAL NULL, url, UNIQUE(fk, since));
Я сделал view тем же методом, что выше, чтобы для каждого агента оставить его последнюю цену — если он еще торгует данным товаром. А вот теперь хочется отобразить в интерфейсе примерно следующее (для каждого FK): «Цена: от 123 (Пупкин и К°) до 456 (Олигархъ Ltd.)» Как бы сие сделать? Если у двоих агентов одна и та же цена, можно выбрать любого. Например, того, чья запись появилась раньше.
Здравствуйте, wildwind, Вы писали:
RO>>Есть БД, в которой хрянятся записи о товарах и тех, кто им торгует.
W>Не понял структуры данных, поэтому посоветовать нечего. Где что хранится и кто куда FK? :) W>На всякий случай: http://www.rsdn.ru/article/db/dbhistory.xml
-- это всё время постоянноCREATE TABLE taProperty (
idProperty SERIAL PRIMARY KEY,
всякие_неизменяемые_поля
);
-- это может изредка менятьсяCREATE TABLE taDescription (
idDescription SERIAL PRIMARY KEY,
idProperty BIGINT UNSIGNED NOT NULL,
since TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
всякие_изменяемые_поля,
UNIQUE(idProperty, since),
FOREIGN KEY (idProperty) REFERENCES taProperty(idProperty) ON UPDATE CASCADE ON DELETE CASCADE
);
-- цены тоже могут менятьсяCREATE TABLE taTermSale (
idTermSale SERIAL PRIMARY KEY,
idProperty BIGINT UNSIGNED NOT NULL,
agent VARCHAR(255) NOT NULL,
since TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
nPrice TINYINT UNSIGNED NOT NULL,
price DECIMAL(14, 4) NULL,
url VARCHAR(1024) NOT NULL,
UNIQUE(idProperty, since),
FOREIGN KEY (idProperty) REFERENCES taProperty(idProperty) ON UPDATE CASCADE ON DELETE CASCADE
);
Здравствуйте, Roman Odaisky, Вы писали:
RO>Есть БД, в которой хрянятся записи о товарах и тех, кто им торгует.
RO>Во-первых, состояние товара может изменяться со временем, поэтому структура таблицы с описанием его примерно такая: RO>
CREATE TABLE description (id, fk, since TIMESTAMP, остальные поля, UNIQUE(fk, since));
RO>Нужно уметь выбирать самую новую запись. Сделал так: RO>
SELECT * FROM description d WHERE since >= ALL(SELECT since FROM description d2 WHERE d2.fk = d.fk);
RO>оно-то работает, но выглядит некрасиво. Эдакое недосамообъединение. Как сделать по-человечески?
with cte as(
select
*,
row_number() over(partition by [fk] order by [since] desc) as Приоритет
from
description
)
select
*
from
cte
where
Приоритет = 1
;
Roman Odaisky wrote:
> SELECT * FROM table WHERE since = MAX(since);
SELECT * FROM table HAVING since = MAX(since)
Но из-за MAX группировать придётся, без GROUP BY не заработает.
А вообще говоря, тебе правильно http://rsdn.ru/article/db/dbhistory.xml
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, _d_m_, Вы писали:
___>>
___>>with cte as(
___>> select
___>> *,
___>> row_number() over(partition by [fk] order by [since] desc) as Приоритет
___>> from
___>> description
___>>)
___>>select
___>> *
___>>from
___>> cte
___>>where
___>> Приоритет = 1
___>>;
___>>
RO>Ну, это явно оракл-онли. Хочется решения на SQL и без подзапросов. Лучше всего было бы как-то так: RO>
SELECT * FROM table WHERE since = MAX(since);
RO>но это, конечно, не работает.
1) Это работает в MS SQL 2005;
2) Это SQL. Стандартный SQL!;
3) Подзапросов здесь нет. Ни одного. И план запроса это подтверждает. Есть (опять же стандартное) CTE — Common Table Expression.
Рекомендую подробнее ознакомится с языком SQL.
PS: Кстати, здесь принято указывать СУБД и ее версию чтобы помощь была целенаправленной. Еще порекомендовать местную статью "Как правильно задавать вопросы", а?
Здравствуйте, _d_m_, Вы писали:
___>Рекомендую подробнее ознакомится с языком SQL. ___>PS: Кстати, здесь принято указывать СУБД и ее версию чтобы помощь была целенаправленной. Еще порекомендовать местную статью "Как правильно задавать вопросы", а?
Здравствуйте, MasterZiv, Вы писали:
>> Ну, это явно оракл-онли. Хочется решения на SQL и без подзапросов. Лучше >> всего было бы как-то так:
MZ>Без подзапросов или self-join-а никак.
Как. Мой пример с ОТВ как раз без подзапросов и без self-join-а.
Проясните еще раз структуру данных.
Где связь таблицы с товарами и продавцами?
Что хочется получить в результате?
Вытаскивание самой последней записи в Oracle( и примерно так же в MS SQL):
select * from (
select d.*, row_number() over (order by since desc) rn from description d
) where rn = 1
Re[2]: Ограничиться одной записью
От:
Аноним
Дата:
14.04.08 08:07
Оценка:
U>
U>select * from (
U> select d.*, row_number() over (order by since desc) rn from description d
U>) where rn = 1
U>
к чему заставлять сервер выбирать все записи, попутно нумеруя, а только затем отсекать лишние
это типичная задача
но не на аналитику, а на агрегаты
намек ясен?
Здравствуйте, Аноним, Вы писали:
А>к чему заставлять сервер выбирать все записи, попутно нумеруя, а только затем отсекать лишние А>это типичная задача А>но не на аналитику, а на агрегаты А>намек ясен?
Телепатов нет. Поток сознания непонят.
Re[4]: Ограничиться одной записью
От:
Аноним
Дата:
15.04.08 06:32
Оценка:
Здравствуйте, _d_m_, Вы писали: ___>Телепатов нет. Поток сознания непонят.
если не ясно, чем аналитика отличается от агрегата, то RTFM
речь, в частности, шла о keep & dense_rank
а в принципе, о том, что давать советы с использованием аналитики, в общем случае — без ознакомления с "магией данных", это реальная возможность поставить чужой продуктив на колени
Здравствуйте, <Аноним>, Вы писали: А>а в принципе, о том, что давать советы с использованием аналитики, в общем случае — без ознакомления с "магией данных", это реальная возможность поставить чужой продуктив на колени
Есть мнение, что, к примеру, MS SQL достаточно умен, чтобы не выполнять запрос буквально. В частности, он не будет "выбирать все записи, попутно нумеруя, а только затем отсекать лишние". Не в курсе про Оракл.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Ограничиться одной записью
От:
Аноним
Дата:
16.04.08 06:16
Оценка:
Здравствуйте, Sinclair, Вы писали:
S>Есть мнение, что, к примеру, MS SQL достаточно умен, чтобы не выполнять запрос буквально. В частности, он не будет "выбирать все записи, попутно нумеруя, а только затем отсекать лишние". Не в курсе про Оракл.
план запроса, пожалуйста, который это подтвердит
или у MS SQL есть некий прогрессивный механизм, который позволяет сформировать окно (over) без чтения данных из таблицы(индекса)?)