用于虚拟显示数据的SQL复杂视图

时间:2010-12-21 13:53:14

标签: sql database-partitioning ansi-sql

我有一张包含下表的表格。

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

因此,这显示了库存数量变化的时间。 现在我的要求是在这个表上创建一个虚拟显示数据的视图(如果库存不是特定小时的htere)。所以应该显示的数据是

----------------------------------
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
----------------------------------

这意味着即使某个特定小时的数据不存在,我们也应该显示最后一小时的库存量。我还有另一张桌子,其中所有可用的小时数从1-23开始。

我已经通过下面给出的方法尝试了分区。但我想我错过了一些关于完成我的要求的事情。

SELECT
HOUR_NUMBER,
CASE WHEN TOTAL_STOCK IS NULL
THEN SUM(TOTAL_STOCK)
OVER (
PARTITION BY LOCATION
ORDER BY CURRENT_HOUR ROWS  1 PRECEDING 
)
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

此查询为没有数据的小时数提供了库存为零的所有小时数。 我们正在研究ANSI sql解决方案,以便它可以在像Teradata这样的数据库上使用。

我在想我是错误地使用分区还是有其他办法。我们尝试使用CASE WHEN但是需要某种循环来检查一些库存的一小时。

4 个答案:

答案 0 :(得分:0)

之前我遇到过类似的问题。通常,更容易确保您需要的数据以某种方式进入数据库。您可以使用定期运行的存储过程自动执行它。

话虽如此,您是否考虑过使用标量子查询来尝试COALESCE()? (或者你的dbms支持的任何类似函数。)我自己尝试并发布SQL,但是我将在两分钟内离开工作。

答案 1 :(得分:0)

没试过,但是按照Mike所说的那样:

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

注意:这会大大影响性能。

答案 2 :(得分:0)

感谢您的回复。我已经尝试了RECURSIVE VIEW以满足上述要求,并且正在给出正确的结果(我担心大表的CPU使用率,因为它是递归的)。所以这是库存表

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

然后我们将在这个表上有一个视图,它将使用Left outer join提供所有12小时的数据。

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

然后我们将有一个递归视图,它以相同的视图递归地连接表,以使每小时的股票移动一小时,并附加增加的数据级别。

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
)
;

您可以观察到,首先我们从左外连接视图中选择,然后我们将它与在我们创建的同一视图上连接的左外连接视图结合,并为其提供数据来源的级别。

然后我们从该视图中选择最低级别的数据。

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
)
;

这样可以正常工作并将结果显示为

----------------------------------
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
----------------------------------

我知道这会占用大型CPU以获得递归工作(我们将递归限制在12个级别,因为需要12个小时的数据来阻止它进入无限循环)。但我认为某些身体可以将其用于某种层次结构构建。我会寻找你们的其他任何方法的更多回复。谢谢。您可以在以下链接中查看teradata的递归视图。 http://forums.teradata.com/forum/database/recursion-in-a-stored-procedure

答案 3 :(得分:0)

视图最常见的用途是消除复杂性。 例如:

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

现在执行SELECT

SELECT * FROM FEESTUDENT