Ограничиться одной записью
От: Roman Odaisky Украина  
Дата: 07.04.08 09:51
Оценка:
Есть БД, в которой хрянятся записи о товарах и тех, кто им торгует.

Во-первых, состояние товара может изменяться со временем, поэтому структура таблицы с описанием его примерно такая:
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.)» Как бы сие сделать? Если у двоих агентов одна и та же цена, можно выбрать любого. Например, того, чья запись появилась раньше.
До последнего не верил в пирамиду Лебедева.
Re: Ограничиться одной записью
От: wildwind Россия  
Дата: 07.04.08 10:43
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Есть БД, в которой хрянятся записи о товарах и тех, кто им торгует.


Не понял структуры данных, поэтому посоветовать нечего. Где что хранится и кто куда FK?
На всякий случай: http://www.rsdn.ru/article/db/dbhistory.xml
Автор(ы): Смирнов Андрей
Дата: 23.10.2004
Рассматриваются подходы к отслеживанию действий пользователей в БД, протоколирование изменений и получение данных по состоянию на какой-либо момент.



P.S. Еще на всякий случай: http://www.rsdn.ru/article/db/sqlnames.xml
Автор(ы): Джо Селко
Дата: 09.04.2006
Глава из книги “Стиль программирования Джо Селко на SQL”
Неудачные имена для элементов данных приводят к тому, что код бывает трудно, а то и невозможно прочитать.
Невозможность чтения — не шутка. В старину компании, разрабатывавшие программное обеспечение, нарочно искажали имена и удаляли из исходного кода форматирование, чтобы скрыть от покупателей алгоритм. Эта традиция все еще жива, хотя, может быть, изначальное намерение и утрачено. В августе 2004 г. в одной из групп новостей по SQL была опубликована программа, в которой все имена состояли из одной буквы и длинной цепочки цифр.
В настоящее время существуют стандарты метаданных ISO-11179, описывающие правила именования элементов данных и регистрации стандартов. Поскольку это стандарт ISO, его надлежит применять не только в SQL, но и вообще везде.
Стандартизация, немного печатного мастерства и некоторый здравый смысл — вот слагаемые успешной работы.
Re[2]: Ограничиться одной записью
От: Roman Odaisky Украина  
Дата: 07.04.08 12:12
Оценка:
Здравствуйте, wildwind, Вы писали:

RO>>Есть БД, в которой хрянятся записи о товарах и тех, кто им торгует.


W>Не понял структуры данных, поэтому посоветовать нечего. Где что хранится и кто куда FK? :)

W>На всякий случай: http://www.rsdn.ru/article/db/dbhistory.xml
Автор(ы): Смирнов Андрей
Дата: 23.10.2004
Рассматриваются подходы к отслеживанию действий пользователей в БД, протоколирование изменений и получение данных по состоянию на какой-либо момент.


W>P.S. Еще на всякий случай: http://www.rsdn.ru/article/db/sqlnames.xml
Автор(ы): Джо Селко
Дата: 09.04.2006
Глава из книги “Стиль программирования Джо Селко на SQL”
Неудачные имена для элементов данных приводят к тому, что код бывает трудно, а то и невозможно прочитать.
Невозможность чтения — не шутка. В старину компании, разрабатывавшие программное обеспечение, нарочно искажали имена и удаляли из исходного кода форматирование, чтобы скрыть от покупателей алгоритм. Эта традиция все еще жива, хотя, может быть, изначальное намерение и утрачено. В августе 2004 г. в одной из групп новостей по SQL была опубликована программа, в которой все имена состояли из одной буквы и длинной цепочки цифр.
В настоящее время существуют стандарты метаданных ISO-11179, описывающие правила именования элементов данных и регистрации стандартов. Поскольку это стандарт ISO, его надлежит применять не только в SQL, но и вообще везде.
Стандартизация, немного печатного мастерства и некоторый здравый смысл — вот слагаемые успешной работы.


Просто не хотел загромождать. Если так проще, то:

-- это всё время постоянно
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
);
До последнего не верил в пирамиду Лебедева.
Re: Ограничиться одной записью
От: _d_m_  
Дата: 08.04.08 07:09
Оценка:
Здравствуйте, 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
;
Re[2]: Ограничиться одной записью
От: Roman Odaisky Украина  
Дата: 08.04.08 13:41
Оценка:
Здравствуйте, _d_m_, Вы писали:

___>
___>with cte as(
___>    select
___>        *,
___>        row_number() over(partition by [fk] order by [since] desc) as Приоритет
___>    from
___>        description
___>)
___>select
___>    *
___>from
___>    cte
___>where
___>    Приоритет = 1
___>;
___>


Ну, это явно оракл-онли. Хочется решения на SQL и без подзапросов. Лучше всего было бы как-то так:
SELECT * FROM table WHERE since = MAX(since);

но это, конечно, не работает.
До последнего не верил в пирамиду Лебедева.
Re: Ограничиться одной записью
От: Centaur Россия  
Дата: 08.04.08 17:33
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Нужно уметь выбирать самую новую запись. Сделал так:

RO>
SELECT * FROM description d WHERE since >= ALL(SELECT since FROM description d2 WHERE d2.fk = d.fk);

RO>оно-то работает, но выглядит некрасиво. Эдакое недосамообъединение. Как сделать по-человечески?

Запросить:
SELECT * FROM description ORDER BY since DESC;

Из результата fetch’нуть первую запись, а на всё остальное забить. Ни один вменяемый драйвер/клиент не потащит всю выборку на клиента сразу.

Кроме того, у MS SQL (MSDE, Access) есть конструкция SELECT TOP m, у MySQL — SELECT … LIMIT n, m, у PostgreSQL — SELECT … LIMIT m OFFSET n.
Re[3]: Ограничиться одной записью
От: . Великобритания  
Дата: 08.04.08 22:50
Оценка:
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
Автор(ы): Смирнов Андрей
Дата: 23.10.2004
Рассматриваются подходы к отслеживанию действий пользователей в БД, протоколирование изменений и получение данных по состоянию на какой-либо момент.

посоветовали, лучше структуру бд переделать.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: Ограничиться одной записью
От: _d_m_  
Дата: 09.04.08 01:34
Оценка:
Здравствуйте, 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: Кстати, здесь принято указывать СУБД и ее версию чтобы помощь была целенаправленной. Еще порекомендовать местную статью "Как правильно задавать вопросы", а?
Re[2]: Ограничиться одной записью
От: _d_m_  
Дата: 09.04.08 01:37
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Запросить:

C>
SELECT * FROM description ORDER BY since DESC;

C>Из результата fetch’нуть первую запись, а на всё остальное забить. Ни один вменяемый драйвер/клиент не потащит всю выборку на клиента сразу.

Внимательно посмотри на запрос в исходном посте. Там выборка не просто одной записи, а для каждого fk самая последняя запись.
Re[4]: Ограничиться одной записью
От: Roman Odaisky Украина  
Дата: 09.04.08 11:07
Оценка:
Здравствуйте, _d_m_, Вы писали:

___>Рекомендую подробнее ознакомится с языком SQL.

___>PS: Кстати, здесь принято указывать СУБД и ее версию чтобы помощь была целенаправленной. Еще порекомендовать местную статью "Как правильно задавать вопросы", а?

Добр ты, однако. Ладно, пойду следовать рекомендации :-)

А СУБД потому не указал, что хочу решение на SQL, а не на диалектах.
До последнего не верил в пирамиду Лебедева.
Re[3]: Ограничиться одной записью
От: MasterZiv СССР  
Дата: 09.04.08 12:24
Оценка:
Roman Odaisky пишет:

> Ну, это явно оракл-онли. Хочется решения на SQL и без подзапросов. Лучше

> всего было бы как-то так:

Без подзапросов или self-join-а никак.

> SELECT * FROM table WHERE since = MAX(since);



а это — вообще бред полный.

А лучше бы тебе просто выбрать все записи, начиная с самой
последней, взять ее, родимую, а все остальное отбросить.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: Ограничиться одной записью
От: _d_m_  
Дата: 09.04.08 22:21
Оценка:
Здравствуйте, MasterZiv, Вы писали:

>> Ну, это явно оракл-онли. Хочется решения на SQL и без подзапросов. Лучше

>> всего было бы как-то так:

MZ>Без подзапросов или self-join-а никак.


Как. Мой пример с ОТВ как раз без подзапросов и без self-join-а.
Re[5]: Ограничиться одной записью
От: _d_m_  
Дата: 09.04.08 22:24
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>А СУБД потому не указал, что хочу решение на SQL, а не на диалектах.


Ну так я тебе на SQL-2003 и привел. Вопрос только в том, поддерживает ли твоя СУБД данный стандарт.
Re: Ограничиться одной записью
От: Uzito  
Дата: 11.04.08 14:11
Оценка:
Проясните еще раз структуру данных.
Где связь таблицы с товарами и продавцами?
Что хочется получить в результате?

Вытаскивание самой последней записи в 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[3]: Ограничиться одной записью
От: _d_m_  
Дата: 15.04.08 06:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>к чему заставлять сервер выбирать все записи, попутно нумеруя, а только затем отсекать лишние

А>это типичная задача
А>но не на аналитику, а на агрегаты
А>намек ясен?

Телепатов нет. Поток сознания непонят.
Re[4]: Ограничиться одной записью
От: Аноним  
Дата: 15.04.08 06:32
Оценка:
Здравствуйте, _d_m_, Вы писали:
___>Телепатов нет. Поток сознания непонят.
если не ясно, чем аналитика отличается от агрегата, то RTFM
речь, в частности, шла о keep & dense_rank
а в принципе, о том, что давать советы с использованием аналитики, в общем случае — без ознакомления с "магией данных", это реальная возможность поставить чужой продуктив на колени
Re[5]: Ограничиться одной записью
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.04.08 11:32
Оценка:
Здравствуйте, <Аноним>, Вы писали:
А>а в принципе, о том, что давать советы с использованием аналитики, в общем случае — без ознакомления с "магией данных", это реальная возможность поставить чужой продуктив на колени
Есть мнение, что, к примеру, MS SQL достаточно умен, чтобы не выполнять запрос буквально. В частности, он не будет "выбирать все записи, попутно нумеруя, а только затем отсекать лишние". Не в курсе про Оракл.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Ограничиться одной записью
От: Аноним  
Дата: 16.04.08 06:16
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Есть мнение, что, к примеру, MS SQL достаточно умен, чтобы не выполнять запрос буквально. В частности, он не будет "выбирать все записи, попутно нумеруя, а только затем отсекать лишние". Не в курсе про Оракл.

план запроса, пожалуйста, который это подтвердит
или у MS SQL есть некий прогрессивный механизм, который позволяет сформировать окно (over) без чтения данных из таблицы(индекса)?)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.