Reputation: 31
My table contains the following structure:
START_DATE | END_DATE | COST
2012-11-01 | 2012-11-05 | 500.5
I would like to perform a SELECT statement that returns the following result:
DATE | COST
2012-11-01 | 100.1
2012-11-02 | 100.1
2012-11-03 | 100.1
2012-11-04 | 100.1
2012-11-05 | 100.1
I can figure out how to divide the total cost by the amount of days between start and end date, but no idea how to create these 'virtual rows' for the DATE column.
Maybe it isn't possible at all. Any help is very much appreciated!
Upvotes: 3
Views: 1528
Reputation: 501
i agree with you Sebas that this one works in oracle.. Place your tablename in place of table1
if you don't have access to all_objects
then
select ( I +START_DATE-1) date1,cost/((END_DATE-START_DATE)+1) cost from table1 ,( select I from DUAL
model
dimension by (1 i)
measures (0 X)
(X[for I from 2 to 10000 increment 1] = 0))
where END_DATE>=I +START_DATE-1;
if you have access to metatable all_objects
then try this one
SELECT DATE1.DATE_ALL, table1.cost/((table1.END_DATE-table1.START_DATE)+1) NEW_COST
FROM table1 INNER JOIN
(
SELECT START_DATE + rownum-1 DATE_ALL
FROM ALL_OBJECTS
CROSS JOIN table1
WHERE
START_DATE + rownum - 1 <= (SELECT MAX(END_DATE) FROM table1)
) DATE1 ON table1.END_DATE >= DATE1.DATE_ALL
please let me know if you have any issue.
Upvotes: 0
Reputation: 24046
I agree with Dems to have a calender table, which is the best option.. As Mysql doesn't have a function like ROW_NUMBER as many other RDBMSs have.
Another option would be to create a table with sequence number. You can populate this table with a considerable number of values (say 1 through 100k), which you think will be the maximum number of days between any start_date and end_date
something like
create table seq
(rn int);
insert into seq
select 0 as rn union all
select 1 as rn union all
select 2 as rn union all
select 3 as rn union all
select 4 as rn union all
select 5 as rn
then run following query:
select DATE_ADD(START_DATE, INTERVAL rn day) ,
COST/(select datediff(END_DATE,START_DATE)+1 from table1)
from Table1
cross join seq
where rn<=(select datediff(END_DATE,START_DATE) from table1)
Upvotes: 2
Reputation: 86706
Your best bet is to create a Calendar
table.
For your purposes, all you need is one column...
CREATE TABLE Calendar AS (calendar_date DATE)
Then you fill that table with all the dates you will ever be interested in. Even if it's a hundred years, the table will still be tiny.
Do remember to add that column as a Primary Key.
Then you just join on the table...
SELECT
*
FROM
yourTable
INNER JOIN
calendar
ON calendar.calendar_date >= yourTable.start_date
AND calendar.calendar_date <= yourTable.end_date
Later you may find that you want to know dates of holidays, financial year boundaries, etc. These can all be added as addition fields and indexes to that calendar table.
It's much like a cache, rather than re-calculating messy date based rules within a query.
Or, you can think of it as a dimension table where the data is the ID and the other columns are facts.
Upvotes: 3