删除 Oracle 中额外的子查询,选择值数组

发布于 2024-08-06 01:08:38 字数 1186 浏览 3 评论 0原文

我正在选择一些聚合数据并根据日期和特定字段进行分组。我想显示该字段中的所有值以及这些值的计数,即使当天没有与该字段匹配的数据。例如,

Date        MyField  Count
2009-09-25  A        2
2009-09-25  B        0
2009-09-24  A        1
2009-09-24  B        1

我当前必须执行此操作的 Oracle SQL 类似于以下内容:

SELECT today,
       mytable.myfield,
       COUNT(
         CASE WHEN fields.myfield = mytable.myfield AND
                   date >= today AND
                   date < tomorrow
              THEN 1
         END
       )
FROM (
       SELECT TRUNC(SYSDATE) + 1 - LEVEL AS today,
              TRUNC(SYSDATE) + 2 - LEVEL AS tomorrow
       FROM DUAL
       CONNECT BY LEVEL <= 30
     ),
     (
       /* This is the part that seems inefficient */
       SELECT DISTINCT myfield
       FROM mytable
       WHERE myfield IN ('A', 'B')
     ) fields,
     mytable
GROUP BY today, mytable.myfield
ORDER BY today DESC, mytable.myfield ASC

我关心的是我确切地知道要为 myfield 显示哪些值,并且使用 SELECT 似乎效率低下访问 mytable 查询。我想知道是否有某种方法可以在该子查询中执行类似的操作:

SELECT ('A', 'B') AS myfield
FROM DUAL

我使用的是旧版本的 Oracle,其中 WITH 子句不起作用。

I'm SELECTing some aggregate data and grouping on the date and a particular field. I want to display all values in that field and a count for those values even if there was no data matching that field on that day. E.g.

Date        MyField  Count
2009-09-25  A        2
2009-09-25  B        0
2009-09-24  A        1
2009-09-24  B        1

The Oracle SQL I currently have to do this is akin to the following:

SELECT today,
       mytable.myfield,
       COUNT(
         CASE WHEN fields.myfield = mytable.myfield AND
                   date >= today AND
                   date < tomorrow
              THEN 1
         END
       )
FROM (
       SELECT TRUNC(SYSDATE) + 1 - LEVEL AS today,
              TRUNC(SYSDATE) + 2 - LEVEL AS tomorrow
       FROM DUAL
       CONNECT BY LEVEL <= 30
     ),
     (
       /* This is the part that seems inefficient */
       SELECT DISTINCT myfield
       FROM mytable
       WHERE myfield IN ('A', 'B')
     ) fields,
     mytable
GROUP BY today, mytable.myfield
ORDER BY today DESC, mytable.myfield ASC

My concern is that I know exactly which values I want to display for myfield, and it seems inefficient to have a SELECT query that accesses mytable. I was wondering if there's some way I could do something like this in that sub-query:

SELECT ('A', 'B') AS myfield
FROM DUAL

I'm using an older version of Oracle where WITH clauses do not work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清泪尽 2024-08-13 01:08:38

您必须将它们作为不同的行,而不是不同的列。因此,您最终会得到

select 'A' from dual
union
select 'B' from dual

在这种情况下,只要 mytable 中存在包含字段“A”和“B”的行,查询就应该是等效的。如果没有,那么您的子查询将返回原始子查询不会返回的行。

You would have to get them as different rows, not different columns. So you'll end up with

select 'A' from dual
union
select 'B' from dual

In that case, the query should be equivalent as long as there are rows in mytable with fields 'A' and 'B'. If ever there aren't, then your subquery will return rows that the original subquery would not.

人生百味 2024-08-13 01:08:38

为什么不升级 Oracle 版本? with 子句首先添加到 Oracle 9.2 (2002) 中。您还在使用 Oracle 8 吗?

Why don't you upgrade your Oracle Version? The with-clause is added first to Oracle 9.2 (2002). Are you still using Oracle 8?

别理我 2024-08-13 01:08:38

您在 FIELDS 子查询和 MYTABLE 之间没有联接,因此您的结果集将包含过去 30 天 MYFIELD 的每个值的一行。

但是,为什么不放弃子查询并仅在 MYTABLE.MYFIELD 上进行筛选,而不是添加该联接呢?另外,如果您担心性能,您应该将日期限制在 WHERE 子句中,否则您将处理 MYTABLE 中的每一行。

select today
       , myfield
       , count ( case when trunc(somedate) = today then 1 end ) as ab_count
from   ( select trunc(sysdate) + 1 - level as today
         from dual
         connect by level <= 30 )
       , mytable
where myfield in ('A', 'B')
and somedate >= trunc(sysdate) - 30
group by today, myfield
order by today desc, myfield asc
/

编辑

我已经针对一些测试数据运行了您的原始查询和修改后的查询。您只需相信我的话,这两个结果集实际上是相同的 - 或者您自己尝试一下:)

您的查询返回:

TODAY       M   AB_COUNT
----------- - ----------
26-SEP-2009 A          0
26-SEP-2009 B          0
25-SEP-2009 A          2
25-SEP-2009 B          2
24-SEP-2009 A          2
24-SEP-2009 B          0
...
29-AUG-2009 A          1
29-AUG-2009 B          2
28-AUG-2009 A          1
28-AUG-2009 B          0

60 rows selected.

SQL>

我的查询返回:

TODAY       M   AB_COUNT
----------- - ----------
26-SEP-2009 A          0
26-SEP-2009 B          0
25-SEP-2009 A          2
25-SEP-2009 B          2
24-SEP-2009 A          2
24-SEP-2009 B          0
...
29-AUG-2009 A          1
29-AUG-2009 B          2
28-AUG-2009 A          1
28-AUG-2009 B          0

60 rows selected.

SQL>

You don't have a join between the FIELDS sub-query and MYTABLE, so your resultset will contain a row for every value of MYFIELD for the last thirty days.

However, rather than adding that join, why not ditch the sub-query and just filter on MYTABLE.MYFIELD? Also, if you are concerned about performance you should bound the date in a WHERE clause, otherwise you will process every row in MYTABLE.

select today
       , myfield
       , count ( case when trunc(somedate) = today then 1 end ) as ab_count
from   ( select trunc(sysdate) + 1 - level as today
         from dual
         connect by level <= 30 )
       , mytable
where myfield in ('A', 'B')
and somedate >= trunc(sysdate) - 30
group by today, myfield
order by today desc, myfield asc
/

edit

I have run your original query and my revised one against some test data. You will just have to take my word for it that the two resulsets were in fact identical - or try it yourself :)

Your query returns:

TODAY       M   AB_COUNT
----------- - ----------
26-SEP-2009 A          0
26-SEP-2009 B          0
25-SEP-2009 A          2
25-SEP-2009 B          2
24-SEP-2009 A          2
24-SEP-2009 B          0
...
29-AUG-2009 A          1
29-AUG-2009 B          2
28-AUG-2009 A          1
28-AUG-2009 B          0

60 rows selected.

SQL>

My query returns:

TODAY       M   AB_COUNT
----------- - ----------
26-SEP-2009 A          0
26-SEP-2009 B          0
25-SEP-2009 A          2
25-SEP-2009 B          2
24-SEP-2009 A          2
24-SEP-2009 B          0
...
29-AUG-2009 A          1
29-AUG-2009 B          2
28-AUG-2009 A          1
28-AUG-2009 B          0

60 rows selected.

SQL>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文