3

I have the huge table of over 100 million rows of data which is joined to another reference table that I want to create a conditional count for.

The first table is the large one which is an audit log and contains data which lists data on countries and contains a date of audit. The second table is a smaller table which contains relational data to the audit log. The first part is the easy bit which is to identify which audit data I want to see. I have the following code to identify this:

    select aud.*
    from audit_log aud
    join database db on db.id=aud.release_id
    where aud.event_description like '% opted in'
    and r.creation_source = 'system_a'

This gives me the data in the following format:

Country             Event Description                                   Audit Date
Czech Republic      Czech Republic has been automatically opted in      11-AUG-14 07.01.52.606000000
Denmark             Denmark has been automatically opted in             12-AUG-15 07.01.53.239000000
Denmark             Denmark has been automatically opted in             11-SEP-15 07.01.53.902000000
Dominican Republic  Dominican Republic has been automatically opted in  11-SEP-15 07.01.54.187000000
Ecuador             Ecuador  has been automatically opted in            11-DEC-14 07.01.54.427000000
Ecuador             Ecuador has been automatically opted in             11-NOV-14 07.01.54.679000000

The number of results from this query still returns over 5 million rows so I cannot export the data to Excel to create a count. My two main issues are the number of rows and the date format of the 'Audit Date' field.

Ideally I want to create a count which shows the data as:

Country                |Aug-14|Nov-14|Dec-14|Aug-15|Sep-15
Czech Republic         |  1   |      |      |      |
Denmark                |      |      |      |  1   | 1
Dominican Republic     |      |      |      |      | 1
Ecuador                |      | 1    |  1   |      |        

Any idea's on how I extract the month and year and drop the figures into column by country?

Thanks

Edit - Thank you xQbert for you solution, it worked perfectly! The problem now is that I have run into a new problem. I need to constrain the count by another query, but there is no unique identifier between the tables involved.

For example, I amended your query to fit my db:

select cty.country_name, 
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2014' then 1 else 0 end) as "AUG-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2014' then 1 else 0 end) as "SEP-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='OCT-2014' then 1 else 0 end) as "OCT-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='NOV-2014' then 1 else 0 end) as "NOV-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='DEC-2014' then 1 else 0 end) as "DEC-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JAN-2015' then 1 else 0 end) as "JAN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='FEB-2015' then 1 else 0 end) as "FEB-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAR-2015' then 1 else 0 end) as "MAR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='APR-2015' then 1 else 0 end) as "APR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAY-2015' then 1 else 0 end) as "MAY-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUN-2015' then 1 else 0 end) as "JUN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUL-2015' then 1 else 0 end) as "JUL-15",
    SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2015' then 1 else 0 end) as "AUG-15",
    SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2015' then 1 else 0 end) as "SEP-15"
    from dschd.audit_trail aud
    join dschd.release r on r.id=aud.release_id
    join dschd.country cty on aud.EVENT_COUNTRY_ID=cty.id
    where aud.event_description like '% opted in'
    and r.creation_source = 'DSCHED'
    GROUP BY cty.COUNTRY_name

My second query is:

select  *
from DSCHD.RELEASE_COUNTRY_RIGHT rcr
join dschd.release r on rcr.RELEASE_ID=r.ID
join dschd.country cty on rcr.COUNTRY_ID=cty.id
where r.release_status in ('DRAFT', 'SCHEDULED', 'FINAL', 'DELIVERED')
and r.is_active = 'Y'
and rcr.MARKETING_RIGHT = 'Y'
and rcr.OPT_OUT = 'N'
and r.creation_source = 'DSCHED'

The problem is that I have many countries which can relate to one ID (Release_ID) but there is no unique identifier between the tables on a country level. Each country has an ID though.

So for query 1, to identify each unique row I would need the 'aud.Release_ID' and the 'aud.Event_country_id' and for query 2 to achieve the same I would need to use the 'rcr.Release_ID' and 'rcr.country_id'.

select cty.country_name, 
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2014' then 1 else 0 end) as "AUG-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2014' then 1 else 0 end) as "SEP-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='OCT-2014' then 1 else 0 end) as "OCT-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='NOV-2014' then 1 else 0 end) as "NOV-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='DEC-2014' then 1 else 0 end) as "DEC-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JAN-2015' then 1 else 0 end) as "JAN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='FEB-2015' then 1 else 0 end) as "FEB-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAR-2015' then 1 else 0 end) as "MAR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='APR-2015' then 1 else 0 end) as "APR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAY-2015' then 1 else 0 end) as "MAY-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUN-2015' then 1 else 0 end) as "JUN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUL-2015' then 1 else 0 end) as "JUL-15",
    SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2015' then 1 else 0 end) as "AUG-15",
    SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2015' then 1 else 0 end) as "SEP-15"
    from dschd.audit_trail aud
    join dschd.release r on r.id=aud.release_id
    join dschd.country cty on aud.EVENT_COUNTRY_ID=cty.id
    where aud.event_description like '% opted in'
    and ***** in (select  ******
                 from DSCHD.RELEASE_COUNTRY_RIGHT rcr
                 join dschd.release r on rcr.RELEASE_ID=r.ID
                 join dschd.country cty on rcr.COUNTRY_ID=cty.id
                 where r.release_status in ('DRAFT', 'SCHEDULED', 'FINAL', 'DELIVERED')
                 and r.is_active = 'Y'
                 and rcr.MARKETING_RIGHT = 'Y'
                 and rcr.OPT_OUT = 'N'
                 and r.creation_source = 'DSCHED')
GROUP BY cty.COUNTRY_name

The bit I am stuck at are the two parts which are indicated by '*****' as the join criteria is two fields.

Any ideas?

bobtastic
  • 169
  • 8
  • 1
    Do you have a finite number of months/years you're looking at or is it dynmaic based on data? to get the date format use `Select to_char(sysdate,'MON-YYYY') from dual; which you could then group by` then you need to `pivot` the data this can be done using dynamic SQL, or if you have a finite number of columns you could use case statements, or define using a pivot statement. – xQbert Aug 14 '15 at 15:00
  • Yes it will be every month from Aug-14 to present. Not sure how to use that syntax, i'll need to look it up along with dynamic SQL/Pivots. My Oracle/SQL knowledge is limited. – bobtastic Aug 14 '15 at 15:02

1 Answers1

3

Quick and dirty, not dynamic floating based on a 12 month cylce or anything...

select country, 
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2014' then 1 else 0 end) as "AUG-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2014' then 1 else 0 end) as "SEP-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='OCT-2014' then 1 else 0 end) as "OCT-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='NOV-2014' then 1 else 0 end) as "NOV-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='DEC-2014' then 1 else 0 end) as "DEC-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JAN-2015' then 1 else 0 end) as "JAN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='FEB-2015' then 1 else 0 end) as "FEB-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAR-2015' then 1 else 0 end) as "MAR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='APR-2015' then 1 else 0 end) as "APR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAY-2015' then 1 else 0 end) as "MAY-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUN-2015' then 1 else 0 end) as "JUN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUL-2015' then 1 else 0 end) as "JUL-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2015' then 1 else 0 end) as "AUG-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2015' then 1 else 0 end) as "SEP-15"

    from audit_log aud
    join database db on db.id=aud.release_id
    where aud.event_description like '% opted in'
    and r.creation_source = 'system_a'
GROUP BY COUNTRY

Ideally we'd simply use a Pivot statement or base it on earliest date in range and go on... Such as found in this prior stack article Dynamic pivot in oracle sql

update based on changing requirements you do know you can join on multiple criteria right? :P

Note we created an inline view with your second query alias it as z table name and then add the two columns desired to match on as part of the results. Then we join it as if it were a table!

select cty.country_name, 
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2014' then 1 else 0 end) as "AUG-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2014' then 1 else 0 end) as "SEP-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='OCT-2014' then 1 else 0 end) as "OCT-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='NOV-2014' then 1 else 0 end) as "NOV-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='DEC-2014' then 1 else 0 end) as "DEC-14",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JAN-2015' then 1 else 0 end) as "JAN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='FEB-2015' then 1 else 0 end) as "FEB-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAR-2015' then 1 else 0 end) as "MAR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='APR-2015' then 1 else 0 end) as "APR-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='MAY-2015' then 1 else 0 end) as "MAY-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUN-2015' then 1 else 0 end) as "JUN-15",
SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='JUL-2015' then 1 else 0 end) as "JUL-15",
    SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='AUG-2015' then 1 else 0 end) as "AUG-15",
    SUM(CASE WHEN to_char(Audit_Date,'MON-YYYY') ='SEP-2015' then 1 else 0 end) as "SEP-15"
    from dschd.audit_trail aud
    join dschd.release r on r.id=aud.release_id
    join dschd.country cty on aud.EVENT_COUNTRY_ID=cty.id
    join (select  Release_ID, country_id
                 from DSCHD.RELEASE_COUNTRY_RIGHT rcr
                 join dschd.release r on rcr.RELEASE_ID=r.ID
                 join dschd.country cty on rcr.COUNTRY_ID=cty.id
                 where r.release_status in ('DRAFT', 'SCHEDULED', 'FINAL', 'DELIVERED')
                 and r.is_active = 'Y'
                 and rcr.MARKETING_RIGHT = 'Y'
                 and rcr.OPT_OUT = 'N'
                 and r.creation_source = 'DSCHED') Z
       ON aud.Release_ID = z.Realease_ID and
          aud.Event_country_id = z.country_id
    where aud.event_description like '% opted in'
GROUP BY cty.COUNTRY_name
Community
  • 1
  • 1
xQbert
  • 34,733
  • 2
  • 41
  • 62
  • Nice technique; I use it myself to avoid proprietary specific olap extensions. – Gerardo Lima Aug 14 '15 at 15:09
  • Thanks, but I had to correct the case evaluation year and display year when it went to 2015 (forgot to!) – xQbert Aug 14 '15 at 15:23
  • Thank you very much xQbert! Although I have now run into a new problem. I've updated my opening post. Have you any ideas? – bobtastic Aug 14 '15 at 16:11
  • xQbert - Thank you so much! I did know you can join on two fields, though I could never get the syntax right. It seems so simple now! You're a legend! – bobtastic Aug 14 '15 at 16:36
  • Just bobtastic :P I was struggling until I saw the **** in your example showing where you had the problem. Good communication on your part made answering this easier. – xQbert Aug 14 '15 at 16:42