Re: Need help with complicated SQL statement

From: Shane Ambler <pgsql(at)Sheeky(dot)Biz>
To: Ted Byers <r(dot)ted(dot)byers(at)rogers(dot)com>
Cc: Sam Mason <sam(at)samason(dot)me(dot)uk>, pgsql-general(at)postgresql(dot)org
Subject: Re: Need help with complicated SQL statement
Date: 2007-11-17 16:37:03
Message-ID: 473F18AF.2090706@Sheeky.Biz
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Ted Byers wrote:
> Please consider the following statement (it becomes
> obvious if you remember the important thing about the
> table is that it has columns for each of stock_id,
> price_date, and price).
>
> (SELECT * FROM stockprices WHERE stock_id = 1 ORDER BY
> price_date DESC LIMIT 1)
> UNION
> (SELECT * FROM (SELECT * FROM stockprices WHERE
> stock_id = 1 ORDER BY price_date DESC LIMIT 22) AS T2
> ORDER BY T2.price_date ASC LIMIT 1)
> UNION
> (SELECT * FROM (SELECT * FROM stockprices WHERE
> stock_id = 1 ORDER BY price_date DESC LIMIT 66) AS T3
> ORDER BY T3.price_date ASC LIMIT 1)
> UNION
> (SELECT * FROM (SELECT * FROM stockprices WHERE
> stock_id = 1 ORDER BY price_date DESC LIMIT 132) AS T4
> ORDER BY T4.price_date ASC LIMIT 1)
> UNION
> (SELECT * FROM (SELECT * FROM stockprices WHERE
> stock_id = 1 ORDER BY price_date DESC LIMIT 264) AS T5
> ORDER BY T5.price_date ASC LIMIT 1);
>
> This statement works flawlessly, and is blindingly
> fast relative to everything else I have tried. But I
> am stuck.

I would have these subselects as -

UNION
(SELECT * FROM stockprices WHERE
stock_id = 1 ORDER BY price_date DESC LIMIT 1 OFFSET 264)

I would expect that to give the same result but make the query plan a
bit simpler and quicker using less memory.

> First, while this statement gets me the correct data,
> I need to obtain a single record with stock_id,
> current price (that obtained from the first select
> statement in the union, and each of the prices
> returned by the subsequent select statements as a the
> current price minus the price at the previous date,
> and the result divided by the price at the previous
> date, expressed as a percentage. I do not yet know
> how to do this using SQL (it would be trivial if I
> exported the data to Java or C++ - but it isn't clear
> how to do it within SQL).

I haven't tested this but I would start with -

CREATE VIEW stock_price_combined AS
SELECT
stock_id

, (SELECT stock_price FROM stockprices WHERE stock_id = OT.stock_id
ORDER BY price_date DESC LIMIT 1) as orig_price

, (SELECT stock_price FROM stockprices WHERE stock_id = OT.stock_id
ORDER BY price_date DESC LIMIT 1 OFFSET 22) as price_two

, (SELECT stock_price FROM stockprices WHERE stock_id = OT.stock_id
ORDER BY price_date DESC LIMIT 1 OFFSET 66) as price_three

, (SELECT stock_price FROM stockprices WHERE stock_id = OT.stock_id
ORDER BY price_date DESC LIMIT 1 OFFSET 132) as price_four

, (SELECT stock_price FROM stockprices WHERE stock_id = OT.stock_id
ORDER BY price_date DESC LIMIT 1 OFFSET 264) as price_five

FROM stock_prices OT;

Then you can -

SELECT
orig_price
, (orig_price - price_two) as price_increase
, ((orig_price - price_two)/price_two) as percentile
...
...

FROM stock_price_combined

WHERE stock_id in (SELECT stock_id FROM someTable WHERE ...)

> To make things more difficult, suppose I have another
> select statement that returns a set of stock_ids. How
> do I apply the SQL logic I require to only those
> stocks in the set returned by a statement like SELECT
> stock_id FROM someTable WHERE ... The result of this
> extension would be that I have one record for each
> stock in the selected set of stocks.

SELECT * from stockprices WHERE stock_id in (SELECT stock_id FROM
someTable WHERE ...)

If that isn't the answer you want I hope it points you in the right
direction...

--

Shane Ambler
pgSQL(at)Sheeky(dot)Biz

Get Sheeky @ http://Sheeky.Biz

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Michelle Konzack 2007-11-17 16:48:17 Re: Temporary, In-memory Postgres DB?
Previous Message Tom Lane 2007-11-17 16:01:27 Re: pg_dump not including custom CAST?