【问题标题】:How do I efficiently extract multiple values from a temporary table?如何有效地从临时表中提取多个值?
【发布时间】:2019-07-14 18:24:02
【问题描述】:

我正在尝试做的是根据它们的行号提取各种值并将它们存储到变量中,以便以后可以将这些变量用于某些分析。目前我需要从前 7 行中获取值,这些值按输入表的日期排序。使用以下代码,我可以获得所需的特定值:

WITH tempTable AS
(
    SELECT date, ROUND( SUM(size / 1024 / 1024 ) ) AS Size_Used FROM storageTable
    group by date
    order by date DESC
)
SELECT Size_Used INTO lastRowMinus0Value FROM
(
    SELECT Size_Used, ROWNUM AS rn FROM
    (
        SELECT Size_Used FROM tempTable
        ORDER BY date DESC
    )
)
WHERE rn = lastRowMinus0;

但事实证明,这样做效率非常低,因为每个变量都重复了这段代码,因此编译需要很长时间。

我想也许 UNION ALL 可能是让我的代码更高效的方法,但是当我尝试运行它时,我不断收到编译错误:

WITH tempTable AS
(
    SELECT date, ROUND( SUM(size / 1024 / 1024 ) ) AS Size_Used FROM storageTable
    group by date
    order by date DESC
)
SELECT Size_Used INTO lastRowMinus0Value FROM tempTable
WHERE ROWNUM = lastRowMinus0
UNION ALL
SELECT Size_Used INTO lastRowMinus1Value FROM tempTable
WHERE ROWNUM = lastRowMinus1;

如果有人能就如何以更有效的方式提取价值提供一些指导,我将不胜感激。

【问题讨论】:

  • 请解释什么是 lastRowMinus0 + lastRowMinus1 值 - 表中没有这样的列。通常,如果您只想选择前 7 个日期,则不要对所有可能的日期运行 GROUPBY+SUM 查询 - 使用 WHERE 子句,条件如下:date <= ALL (SELECT 7 first dates from the table),并在 date 列上创建索引 - 这应该会加快大大提高您的查询。

标签: sql oracle common-table-expression


【解决方案1】:

UNION ALL 将给出第一个和第二个查询的所有行组合的结果。您不能将其结果存储到单独的变量中。

如果您真的想使用UNION ALL,那么应该采用以下方法:

WITH TEMPTABLE AS (
    SELECT
        DATE,
        ROUND(SUM(SIZE / 1024 / 1024)) AS SIZE_USED
    FROM
        STORAGETABLE
    GROUP BY
        DATE
    ORDER BY
        DATE DESC
)
SELECT
    SUM(CASE ROWNUM
        WHEN LASTROWMINUS0   THEN SIZE_USED
    END),
    SUM(CASE ROWNUM
        WHEN LASTROWMINUS1   THEN SIZE_USED
    END)
INTO
    LASTROWMINUS0VALUE,
    LASTROWMINUS1
FROM
    TEMPTABLE
WHERE
    ROWNUM IN (
        LASTROWMINUS0,
        LASTROWMINUS1
    );

干杯!!

【讨论】:

  • 这将不起作用,除非 LASTROWMINUS0LASTROWMINUS12 因为 ROWNUM 是一个伪列,并且只会应用于与 WHERE 匹配的行子句(见this answer for more details)。您需要在子查询分解(又名WITH)子句中(或在ORDERing 之后的另一个中间步骤)而不是在最终的SELECT 子句中生成ROWNUM
  • 查看db<>fiddle 示例。
【解决方案2】:

试试PIVOT:

DECLARE
  lastRowMinus0 NUMBER;
  lastRowMinus1 NUMBER;
  lastRowMinus2 NUMBER;
  lastRowMinus3 NUMBER;
  lastRowMinus4 NUMBER;
  lastRowMinus5 NUMBER;
  lastRowMinus6 NUMBER;
BEGIN
  WITH t1 AS (SELECT
                ROUND(SUM("size" / 1024 / 1024)) Size_Used,
                ROW_NUMBER() OVER(ORDER BY "date" DESC) rn
              FROM storageTable
              GROUP BY "date")
  SELECT
    "1", "2", "3", "4", "5", "6", "7"
    INTO lastRowMinus0, lastRowMinus1, lastRowMinus2, lastRowMinus3,
         lastRowMinus4, lastRowMinus5, lastRowMinus6
  FROM (SELECT * FROM t1 WHERE rn < 8) t2
  PIVOT(SUM(Size_Used) FOR rn IN(1, 2, 3, 4, 5, 6, 7)) p;

  DBMS_OUTPUT.PUT_LINE('lastRowMinus0: '||lastRowMinus0||CHR(10)||
                       'lastRowMinus1: '||lastRowMinus1||CHR(10)||
                       'lastRowMinus2: '||lastRowMinus2||CHR(10)||
                       'lastRowMinus3: '||lastRowMinus3||CHR(10)||
                       'lastRowMinus4: '||lastRowMinus4||CHR(10)||
                       'lastRowMinus5: '||lastRowMinus5||CHR(10)||
                       'lastRowMinus6: '||lastRowMinus6);
END;

使用db<>fiddle在线测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    相关资源
    最近更新 更多