【问题标题】:Oracle SQL For Loop OptionsOracle SQL For 循环选项
【发布时间】:2022-01-11 23:24:54
【问题描述】:

我有一个查询,我一直在使用用户输入(即 &&year)来输入要在查询中运行的年份:

SELECT 
  t.type_code , 
  t.sub_type_code,
  COUNT(t.unique_number_id), 
  SUM(t.area_in_hectares)
FROM   
  mytable t
WHERE
       to_char(t.start_date, 'YYYY') <= '&&year' AND
       (
          to_char(t.event_date, 'YYYY') > '&&year' OR
          t.event_date IS NULL OR
          t.type_code = 'P'
       )
GROUP BY 
  t.type_code , 
  t.sub_type_code

我想让这个查询更高效,并且考虑到我的一些其他编程经验,我认为,如果我可以循环多年,我可以让这个查询更高效地运行。我想知道是否有一种方法可以将列表中的年份迭代地注入到用户变量中,而不是手动输入它们。我每年运行一次查询,用户运行近 100 年,显然手动输入年份效率不高。

我一直在阅读有关 for 循环和 while 循环的信息,但我不清楚是否可以在 Oracle SQL 中使用它们。

感谢您的任何想法或建议。

【问题讨论】:

  • 如果您知道年份的范围,那么您可以在没有循环的情况下生成任意数量的年份,但使用递归或分层子查询:db<>fiddle

标签: sql oracle loops


【解决方案1】:

使用子查询分解 (WITH) 子句在单个查询中输入所有年份,然后将 JOIN 输入到您的表中。这样您就不必在客户端和数据库之间产生多个请求的开销,并且数据库不需要解析多个查询:

WITH years (year) AS (
  SELECT 1942 FROM DUAL UNION ALL
  SELECT 1970 FROM DUAL UNION ALL
  SELECT 2000 FROM DUAL UNION ALL
  SELECT 2022 FROM DUAL
)
SELECT y.year,
       t.type_code, 
       t.sub_type_code,
       COUNT(t.unique_number_id), 
       SUM(t.area_in_hectares)
FROM   mytable t
       INNER JOIN years y
       ON (
           t.start_date < TO_DATE( (year+1) || '-01-01', 'YYYY-MM-DD' )
       AND (
              t.event_date >= TO_DATE( (year+1) || '-01-01', 'YYYY-MM-DD' )
           OR t.event_date IS NULL
           OR t.type_code = 'P'
           )
       )
GROUP BY
       y.year,
       t.type_code,
       t.sub_type_code

您还可以将年份转换为日期,而不是尝试将表格列转换为字符串。这将允许您在日期列上使用索引(如果存在)。

【讨论】:

    【解决方案2】:

    你可以这样做:

    BEGIN
    FOR years IN (
                 SELECT * FROM years
                  ORDER BY year asc
                 )
    LOOP
          SELECT 
                t.type_code , 
                t.sub_type_code,
                COUNT(t.unique_number_id), 
                SUM(t.area_in_hectares)
            FROM mytable t
           WHERE to_char(t.start_date, 'YYYY') <= year.year AND
                (
                 to_char(t.event_date, 'YYYY') > year.year OR
                 t.event_date IS NULL OR
                 t.type_code = 'P'
                )
        GROUP BY  t.type_code , t.sub_type_code
    END LOOP;
    END;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-03
      • 2022-08-14
      • 1970-01-01
      • 2015-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-06
      相关资源
      最近更新 更多