开发者

SQL complex view for virtually showing data

开发者 https://www.devze.com 2023-01-31 20:12 出处:网络
I have a table with the following table. ---------------------------------- HourLocationStock ----------------------------------

I have a table with the following table.

----------------------------------
Hour    Location        Stock
----------------------------------
6        2000           20
9        2000           24
----------------------------------

So this shows stock against some of the hours in which there is a change in the quantity. Now my requirement is to create a view on this table which will virtually show the data (if stock is not htere for a particular hour). So the data that should be shown is

----------------------------------
Hour    Location        Stock
----------------------------------
6        2000           20
7        2000           20             -- same as hour 6 stock
8        2000           20             -- same as hour 6 stock
9        2000           24
----------------------------------

That means even if the data is not there for some particular hour then we should show the last hour's stock which is having stock. And i have another table with all the available hours from 1-23 in a column.

I have tried partition over by method as given below. But i think i am missing some thing around this to get my requirement done.

SELECT
HOUR_NUMBER,
CASE WHEN TOTAL_STOCK IS NULL
THEN SUM(TOTAL_STOCK)
OVER (
PARTITION BY LOCATION
ORDER BY CURRENT_HOUR ROWS  1 PR开发者_开发知识库ECEDING 
)
ELSE
TOTAL_STOCK
END AS FULL_STOCK
FROM 
(
    SELECT HOUR_NUMBER AS HOUR_NUMBER
    FROM HOURS_TABLE -- REFEERENCE TABLE WITH  HOURS FROM 1-23
    GROUP BY 1
) HOURS_REF
LEFT OUTER JOIN
(
SEL CURRENT_HOUR  AS CURRENT_HOUR 
, STOCK AS TOTAL_STOCK
,LOCATION AS LOCATION
FROM STOCK_TABLE
WHERE STOCK<>0
) STOCKS
ON HOURS_REF.HOUR_NUMBER = STOCKS.CURRENT_HOUR

This query is giving all the hours with stock as null for the hours without data. We are looking at ANSI sql solution so that it can be used on databases like Teradata.

I am thinking that i am using partition over by wrongly or is there any other way. We tried with CASE WHEN but that needs some kind of looping to check back for an hour with some stock.


I've run into similar problems before. It's often simpler to make sure that the data you need somehow gets into the database in the first place. You might be able to automate it with a stored procedure that runs periodically.

Having said that, did you consider trying COALESCE() with a scalar subquery? (Or whatever similar function your dbms supports.) I'd try it myself and post the SQL, but I'm leaving for work in two minutes.


Haven't tried, but along the lines of what Mike said:

SELECT a.hour
     , COALESCE( a.stock
               , (  select b.stock 
                    from   tbl.b 
                    where  b.hour=a.hour-1   )
               ) "stock"
FROM   tbl a

Note: this will impact performance greatly.


Thanks for your responses. I have tried out RECURSIVE VIEW for the above requirement and is giving correct results (I am fearing about the CPU usage for big tables as it is recursive). So here is stock table

----------------------------------
Hour    Location        Stock
----------------------------------
6        2000           20
9        2000           24
----------------------------------

Then we will have a view on this table which will give all 12 hours data using Left outer join.

----------------------------------
Hour    Location        Stock
----------------------------------
6        2000           20
7        2000           NULL
8        2000           NULL
9        2000           24
----------------------------------

Then we will have a recursive view which joins the table recursively with the same view to get the Stock of each hour moved one hour up and appended with level of data coming incremented.

REPLACE RECURSIVE VIEW HOURLY_STOCK_VIEW
(HOUR_NUMBER,LOCATION, STOCK, LVL) 
AS
(
    SELECT
    HOUR_NUMBER,
    LOCATION,
    STOCK,
    1 AS LVL
    FROM STOCK_VIEW_WITH_LEFT_OUTER_JOIN
    UNION ALL
    SELECT
    STK.HOUR_NUMBER,
    THE_VIEW.LOCATION,
    THE_VIEW.STOCK,
    LVL+1 AS LVL
    FROM STOCK_VIEW_WITH_LEFT_OUTER_JOIN STK
    JOIN
    HOURLY_STOCK_VIEW  THE_VIEW
    ON THE_VIEW.HOUR_NUMBER = STK.HOUR_NUMBER -1
    WHERE LVL <=12
)
;

You can observe that first we select from the Left outer joined view then we union it with the left outer join view joined on the same view which we are creating and giving it its level at which data is coming.

Then we select the data from this view with the minimum level.

SEL * FROM HOURLY_STOCK_VIEW 
WHERE
(
    HOUR_NUMBER,
    LVL
)
IN
(
    SEL 
    HOUR_NUMBER, 
    MIN(LVL)
     FROM HOURLY_STOCK_VIEW
    WHERE STOCK IS NOT NULL
    GROUP BY 1
)
;

This is working fine and giving the result as

----------------------------------
Hour    Location        Stock
----------------------------------
6        2000           20
7        2000           20             -- same as hour 6 stock
8        2000           20             -- same as hour 6 stock
9        2000           24
10        2000           24
11        2000           24
12        2000           24
----------------------------------

I know this is going to take huge CPU for large tables to get the recursion work ( we are limiting the recursion to only 12 levels as 12 hours data is needed to stop it go into infinite loop). But I thought some body can use this for some kind of Hierarchy building. I will look for some more responses from you guys on any other approaches available. Thanks. You can have a look at Recursive views in the below link for teradata. http://forums.teradata.com/forum/database/recursion-in-a-stored-procedure


The most common uses of view is, the removal of complexity. For example:

CREATE VIEW FEESTUDENT
    AS
    SELECT S.NAME,F.AMOUNT FROM STUDENT AS S
    INNER JOIN FEEPAID AS F ON S.TKNO=F.TKNO

Now do a SELECT:

SELECT * FROM FEESTUDENT 
0

精彩评论

暂无评论...
验证码 换一张
取 消