简体   繁体   English

如何在不使用 GROUP BY 或 PARTITION BY 的情况下对 Oracle SQL 中的数据进行分组

[英]How do I group data in Oracle SQL without using GROUP BY OR PARTITION BY

My data is like this我的数据是这样的

MY_TABLE MY_TABLE

DATE日期 CUSTOMER_ID客户ID FAC_NUM FAC_NUM MONIES金钱
01/Jan/2020 2020 年 1 月 1 日 12345678 12345678 ABC123 ABC123 125000 125000
02/Jan/2020 2020 年 1 月 2 日 12345678 12345678 ABC123 ABC123 125000 125000
03/Jan/2020 2020 年 1 月 3 日 12345678 12345678 ABC123 ABC123 125000 125000
01/Feb/2020 2020 年 2 月 1 日 12345678 12345678 ABC123 ABC123 143000 143000
02/Feb/2020 2020 年 2 月 2 日 12345678 12345678 ABC123 ABC123 143000 143000
03/Feb/2020 2020 年 2 月 3 日 12345678 12345678 ABC123 ABC123 143000 143000
04/Feb/2020 2020 年 2 月 4 日 12345678 12345678 ABC123 ABC123 143000 143000
05/Feb/2020 2020 年 2 月 5 日 12345678 12345678 ABC123 ABC123 143000 143000
01/Mar/2020 2020 年 3 月 1 日 12345678 12345678 ABC123 ABC123 125000 125000
02/Mar/2020 2020 年 3 月 2 日 12345678 12345678 ABC123 ABC123 125000 125000
03/Mar/2020 2020 年 3 月 3 日 12345678 12345678 ABC123 ABC123 125000 125000
04/Mar/2020 2020 年 3 月 4 日 12345678 12345678 ABC123 ABC123 125000 125000

I want the output to be like this我希望 output 是这样的

CUSTOMER_ID客户ID FAC_NUM FAC_NUM MONIES金钱 START_DATE开始日期 END_DATE结束日期
12345678 12345678 ABC123 ABC123 125000 125000 01/Jan/2020 2020 年 1 月 1 日 03/JAN/2020 2020 年 1 月 3 日
12345678 12345678 ABC123 ABC123 143000 143000 01/Feb/2020 2020 年 2 月 1 日 05/Feb/2020 2020 年 2 月 5 日
12345678 12345678 ABC123 ABC123 125000 125000 01/Mar/2020 2020 年 3 月 1 日 04/Mar/2020 2020 年 3 月 4 日

I have tried using the following我试过使用以下

SELECT CUSTOMER_ID
      ,FAC_NUM
      ,MONIES
      ,MIN(DATE) AS START_DATE
      ,MAX(DATE) AS END_DATE
FROM MY_TABLE
GROUP BY CUSTOMER_ID
      ,FAC_NUM
      ,MONIES

However, the output I get with this approach is as follows (this is not the desired output)但是,我用这种方法得到的 output 如下(这不是所需的输出)

CUSTOMER_ID客户ID FAC_NUM FAC_NUM MONIES金钱 START_DATE开始日期 END_DATE结束日期
12345678 12345678 ABC123 ABC123 125000 125000 1 Jan 2020 2020 年 1 月 1 日 4 Mar 2020 2020 年 3 月 4 日
12345678 12345678 ABC123 ABC123 143000 143000 1 Feb 2020 2020 年 2 月 1 日 5 Feb 2020 2020 年 2 月 5 日

Is there a way to obtain the output I am looking for without using PL/SQL (I need to run this query over a huge dataset)?有没有办法在不使用 PL/SQL 的情况下获得我正在寻找的 output(我需要在一个巨大的数据集上运行这个查询)? If not, what would be the most efficient way to do this using PL/SQL?如果不是,那么使用 PL/SQL 执行此操作的最有效方法是什么?

I am new to stackoverflow and SQL.我是 stackoverflow 和 SQL 的新手。 Your support would be highly appreciated.您的支持将不胜感激。

Thanks in advance for your help.在此先感谢您的帮助。

Regards, Ani问候, 阿尼

Instead of "I want output", it would probably helped if you described what you wanted.如果您描述了您想要的内容,而不是“我想要输出”,它可能会有所帮助。

To me, it looks as if you'd want to group additionally by month, eg your query slightly modified:对我来说,您似乎还想按月另外分组,例如您的查询稍作修改:

SELECT CUSTOMER_ID
      ,FAC_NUM
      ,MONIES
      ,MIN(DATE) AS START_DATE
      ,MAX(DATE) AS END_DATE
FROM MY_TABLE
GROUP BY CUSTOMER_ID
      ,FAC_NUM
      ,MONIES
      , to_char(date, 'yyyymm')      --> this

Of course, date column name is invalid;当然, date列名是无效的; it is reserved for date datatype so I presume it is, actually, named differently.它是为date数据类型保留的,所以我认为它实际上命名不同。

This reads like a gaps-and-islands problem.这听起来像是一个空白和孤岛问题。 Islands are adjacent rows having the same customer, fac num and amount.岛是具有相同客户、面数和金额的相邻行。 Whenever the amount changes, a new group starts.每当数量发生变化时,就会开始一个新的组。

Here is one approach using the difference between row numbers to identify the islands:这是一种使用行号之间的差异来识别岛屿的方法:

select customer_id, fac_num, monies,
    min(date) as start_date, max(date) as end_date
from (
    select t.*, 
        row_number() over(partition by customer_id, fac_num order by date) as rn1,
        row_number() over(partition by customer_id, fac_num, monies order by date) as rn2
    from mytable t
) t
group by customer_id, fac_num, monies, rn1 - rn2
order by customer_id, fac_num, min(start_date)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM