Oracle SQL variable/parameter usage in query - sql

I have this query below and I need to change WHERE conditions depending on QUARTER.
Meaning that I have to copy that query and change the DATE conditions to 06.2020 then use UNION.
I have no idea how can I optimize this query only with SQL because I am not able to DEFINE some variables/parameters in SQL (not using PL/SQL).
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
'Q1 2020' as QUARTER
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
AND b.balance_date = last_day(to_date('03.2020', 'MM.YYYY'))
WHERE a.account_close_date > last_day(to_date('03.2020', 'MM.YYYY')) and a.account_open_date <= last_day(to_date('03.2020', 'MM.YYYY'))
Thanks for help

If SQL*Developer, or SQLPlus, you can use the 'substitution variables'.
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
'Q1 2020' as QUARTER -- << probably want TO_CHAR('&&1', 'Q YYYY') or similar here
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
AND b.balance_date = last_day(to_date('&&1', 'MM.YYYY'))
WHERE a.account_close_date > last_day(to_date('&&1', 'MM.YYYY')) and a.account_open_date <= last_day(to_date('&&1', 'MM.YYYY'))
When you run this it will prompt you for the value.
If you used just '&1' it would prompt you for each occurence.
'&&1' reuses the value of the first occurence.
You could specify different variables using &1, &2, ...
Also you may used named variable as follows:
To prompt for the date :
ACCEPT dt CHAR PROMPT 'ENter the date (MM.YYYY): '
Or setting the value at declaration:
DEFINE dt='03.2020'
Then:
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
'Q1 2020' as QUARTER -- << probably want TO_CHAR('&&dt', 'Q YYYY') or similar here
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
AND b.balance_date = last_day(to_date('&&dt', 'MM.YYYY'))
WHERE a.account_close_date > last_day(to_date('&&dt', 'MM.YYYY')) and a.account_open_date <= last_day(to_date('&&dt', 'MM.YYYY'))

Ok first of all a disclaimer:
As I know nothing about your original query's logic - the query I propose only shows the main logic - and probably will not run as is.
Having said that - the approach would be:
Based on parameters :start_y (start year) and :end_y (end year)
generate a list with all the quarters for those years years_and_quarters.
Join the years_and_quarters with the required table based on quarter start and end dates - and then calculate the sums grouping by year and quarter.
with quarters as
(
select 'Q1' quarter, '03' q_end_date, '01' q_start_date from dual
union
select 'Q2' quarter, '06' q_end_date,'04' q_start_date from dual
union
select 'Q3' quarter, '09' q_end_date,'07' q_start_date from dual
union
select 'Q4' quarter, '12' q_end_date,'10' q_start_date from dual
),
years as
(select :start_y + (level-1) as mydate
from dual
connect by level <= (:end_y - :start_y) +1
),
years_and_quarters as (
select * from years,quarters
order by mydate
),
accounts as (
SELECT a.limit_amount ,
b.balance_amount,
'LOAN' as TYPE, b.balance_date,a.account_open_date,a.account_close_date
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
)
select sum(accounts.limit_amount) as LIMIT,
sum(accounts.balance_amount) as OUTSTANDING,
years_and_quarters.quarter,
accounts.TYPE
from
years_and_quarters,accounts
where
trunc(balance_date) = last_day(to_date(q_end_date||'.'||mydate, 'MM.YYYY'))
and trunc(account_close_date) > last_day(to_date(q_end_date||'.'||mydate, 'MM.YYYY')) and trunc(account_open_date) <= last_day(to_date(q_end_date||'.'||mydate, 'MM.YYYY'))
group by years_and_quarters.mydate,years_and_quarters.quarter

How about just aggregate by the quarter?
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
to_char(balance_date, '"Q"Q YYYY') as quarter
FROM accounts a LEFT JOIN
account_balances b
ON a.account_key = b.account_key AND
b.balance_type_key = 16 AND
b.balance_date = LAST_DAY(TRUNC(balance_date, 'Q') + INTERVAL '2' MONTH)
WHERE a.account_close_date > LAST_DAY(TRUNC(balance_date, 'Q') + INTERVAL '2' MONTH) AND
a.account_open_date <= LAST_DAY(TRUNC(balance_date, 'Q') + INTERVAL '2' MONTH)
GROUP BY TRUNC(balance_date, 'Q') ;
Your query seems focused on the last day of the quarter. This arrives at that by adding two months to the start and using LAST_DAY().

Related

Count of consecutive days ORACLE SQL

I need help with a query where a need to count de consecutive days like this
select
a.numcad, a.datapu , f.datapu , nvl(to_char(f.datapu, 'DD'),0)dia,
row_number() over (partition by a.numcad, f.datapu order by f.datapu)particao
from
ronda.r066apu a
left join (select t.numcad, t.numemp, t.datacc, t.datapu
from ronda.r070acc t
where t.datacc >= '21/01/2022'
and t.datacc <= trunc(sysdate)
group by t.numcad, t.numemp, t.datacc, t.datapu)f
on a.numemp = f.numemp
and a.numcad = f.numcad
and a.datapu = f.datapu
where a.numcad = 2675
and A.DATAPU >= '21/01/2022'
and A.DATAPU <= trunc(sysdate)
group by a.numcad, a.datapu, f.datapu, f.datacc
order by a.datapu
result is
between 24/01/2022 and 04/02/2022
is 12 days i need know this count , but i will ways get the '21/mes/year'
You can try:
SELECT TO_DATE('2022-01-24', 'YYYY-MM-DD') -
TO_DATE('2022-02-04', 'YYYY-MM-DD')
FROM dual
This returns 21, for example...

Creating Crosstab/Matrix KPI Report Showing Counts of Open Records Over Time

I'm using MS Report Builder 3.0 / SQL Server 2012 and I have a database of "ticket" records. Each ticket has a status (simplified to open / closed), an origination date, and a completion date. I've been asked to build a cross-tab report that returns the number of open records as of the last day of the month for the last 12 months.
I could easily provide a report that shows open items NOW. I can also fairly easily calculate the number of open items on any given date (origination date <= #DATE, comp date > #date or comp date is null). Using that logic, I could even define a dataset for each of the 12 periods for the given scope, but since each of those periods would be defined explicitly, they wouldn't be in the same field to use as the column group for the cross tab, so I don't know how I would actually be able to construct a single crosstab table that would summarize those results.
Anyone ever done anything like this and can share their method?
My most recent thought is to select each date period explicitly and combine them using unions and then use that as the basis for the report, but I'm having a tough time forcing my brain to congeal that concept into something I can execute.
Wouldn't something like this work? This query takes all the cases with status 'open' from last year then groups them by months.
select EOMONTH(completionDate), count(*)
from data
where ticketStatus = 'open' and completionDate > EOMONTH(DateAdd(Year, -1, GETDATE())
group by EOMONTH(completionDate)
You can play with the completionDate > EOMONTH(DateAdd(Year, -1, GETDATE()) condition depending whtat exactly do you need.
Creating the query from the perspective of the time period was the solution.
SELECT
PERIOD_START
,COUNT (ACOUNT.ACTIVITY_ID) OPEN_ACT_COUNT
FROM
(
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-12,getdate())),datepart(mm,dateadd(mm,-12,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-12,getdate())),datepart(mm,dateadd(mm,-12,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-11,getdate())),datepart(mm,dateadd(mm,-11,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-11,getdate())),datepart(mm,dateadd(mm,-11,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-10,getdate())),datepart(mm,dateadd(mm,-10,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-10,getdate())),datepart(mm,dateadd(mm,-10,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-9,getdate())),datepart(mm,dateadd(mm,-9,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-9,getdate())),datepart(mm,dateadd(mm,-9,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-8,getdate())),datepart(mm,dateadd(mm,-8,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-8,getdate())),datepart(mm,dateadd(mm,-8,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-7,getdate())),datepart(mm,dateadd(mm,-7,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-7,getdate())),datepart(mm,dateadd(mm,-7,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-6,getdate())),datepart(mm,dateadd(mm,-6,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-6,getdate())),datepart(mm,dateadd(mm,-6,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-5,getdate())),datepart(mm,dateadd(mm,-5,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-5,getdate())),datepart(mm,dateadd(mm,-5,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-4,getdate())),datepart(mm,dateadd(mm,-4,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-4,getdate())),datepart(mm,dateadd(mm,-4,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-3,getdate())),datepart(mm,dateadd(mm,-3,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-3,getdate())),datepart(mm,dateadd(mm,-3,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-2,getdate())),datepart(mm,dateadd(mm,-2,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-2,getdate())),datepart(mm,dateadd(mm,-2,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(datepart(yy,dateadd(mm,-1,getdate())),datepart(mm,dateadd(mm,-1,getdate())),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(datepart(yy,dateadd(mm,-1,getdate())),datepart(mm,dateadd(mm,-1,getdate())),'01')) AS PERIOD_END
UNION
SELECT
DATEFROMPARTS(DATEPART(yy,getdate()),datepart(mm,getdate()),'01') AS PERIOD_START
,EOMONTH(DATEFROMPARTS(DATEPART(yy,getdate()),datepart(mm,getdate()),'01')) AS PERIOD_END
) PERIODS
LEFT JOIN (
SELECT
AROOT.ACTIVITY_ID
,DACT_PARTY.ACT_OWNER_DEPT_GRP
,DACT_ORI.ACT_ORI_DATE
,DACT_COM.ACT_COM_DATE
,CASE WHEN AROOT.LCYCLE_CD IN ('01','02','03','04','60','63') THEN 'OPEN'
WHEN AROOT.LCYCLE_CD IN ('06','07','09') THEN 'COMPLETE' END STATUS
FROM
DM_IAM_D_ACT_ROOT AROOT
JOIN DM_IAM_D_I_ROOT IROOT ON IROOT.DB_KEY = AROOT.PAR_ISSUE_UUID AND IROOT.APPLICATION = 'QIM' AND IROOT.LCYCLE_CD NOT IN ('10', '64') AND IROOT.ZZCAP_FACILITY = CASE WHEN #FAC = 'MT' THEN 'N200' WHEN #FAC = 'PI' THEN 'N202' WHEN #FAC = 'HU' THEN 'N204' ELSE #FAC END
OUTER APPLY (
SELECT
DM_IAM_D_ACT_PARTY.PARENT_KEY
,DM_BUT000.FIRST_LAST_NAME
,NPDA.FLEET_ID
,NPDA.DEPARTMENT
,DEPTS.ZZCAP_OWED_TO_SUB_DEPT_DESC AS DEPT_DESC
,DEPTS.ZZCAP_OWED_DEPT AS ACT_OWNER_DEPT_GRP
,NPDA.SUPERVISOR
FROM
DM_IAM_D_ACT_PARTY
JOIN DM_BUT000 ON DM_IAM_D_ACT_PARTY.PARTNER_ID = DM_BUT000.PARTNER
JOIN DM_ADR6 ON DM_BUT000.PERSNUMBER = DM_ADR6.PERSNUMBER
JOIN NMC_PERSONNEL_DATA NPDA ON LEFT(DM_ADR6.SMTP_ADDR,40) = LEFT(NPDA.WORK_EMAIL,40)
JOIN DM_ZCAP_OWED_DEPT DEPTS ON NPDA.DEPARTMENT = DEPTS.ZZCAP_OWED_TO_SUB_DEPT
WHERE
AROOT.DB_KEY = DM_IAM_D_ACT_PARTY.PARENT_KEY AND AROOT.MANDT = DM_IAM_D_ACT_PARTY.MANDT
AND DM_IAM_D_ACT_PARTY.PARTY_ROLE_CODE IN ('ACTDRIVR', 'ZASSIGN', 'ZACTAPP')
) AS DACT_PARTY
LEFT JOIN (
SELECT
DM_IAM_D_ACT_DATE.PARENT_KEY
,DATEFROMPARTS(LEFT(DM_IAM_D_ACT_DATE.DATE_TIME,4),RIGHT(LEFT(DM_IAM_D_ACT_DATE.DATE_TIME,6),2),RIGHT(LEFT(DM_IAM_D_ACT_DATE.DATE_TIME,8),2)) AS ACT_ORI_DATE
FROM
DM_IAM_D_ACT_DATE
WHERE
DM_IAM_D_ACT_DATE.ROLE_CD = 'ORI'
AND DM_IAM_D_ACT_DATE.DATE_TIME > 19000000000000
) DACT_ORI ON AROOT.DB_KEY = DACT_ORI.PARENT_KEY
LEFT JOIN (
SELECT
DM_IAM_D_ACT_DATE.PARENT_KEY
,DATEFROMPARTS(LEFT(DM_IAM_D_ACT_DATE.DATE_TIME,4),RIGHT(LEFT(DM_IAM_D_ACT_DATE.DATE_TIME,6),2),RIGHT(LEFT(DM_IAM_D_ACT_DATE.DATE_TIME,8),2)) AS ACT_COM_DATE
FROM
DM_IAM_D_ACT_DATE
WHERE
DM_IAM_D_ACT_DATE.ROLE_CD = 'COM'
AND DM_IAM_D_ACT_DATE.DATE_TIME > 19000000000000
) DACT_COM ON AROOT.DB_KEY = DACT_COM.PARENT_KEY
WHERE
AROOT.ACT_TEMPLATE IN (' ', 'CA', 'CAPR', 'CCA', 'FBC-TEMP', 'FBD-TEMP', 'MRA', 'OBD-TEMP', 'OBN_OBD_CO', 'OBN_OBD_FB', 'OBN-TEMP', 'IA')
AND AROOT.LCYCLE_CD NOT IN ('10','64')
AND AROOT.LONG_TERM <> 'X'
) ACOUNT ON ACOUNT.ACT_ORI_DATE <= PERIOD_END AND (ACOUNT.STATUS = 'OPEN' OR ACOUNT.ACT_COM_DATE >= PERIOD_END)
GROUP BY PERIOD_START

List all months with a total regardless of null

I have a very small SQL table that lists courses attended and the date of attendance. I can use the code below to count the attendees for each month
select to_char(DATE_ATTENDED,'YYYY/MM'),
COUNT (*)
FROM TRAINING_COURSE_ATTENDED
WHERE COURSE_ATTENDED = 'Fire Safety'
GROUP BY to_char(DATE_ATTENDED,'YYYY/MM')
ORDER BY to_char(DATE_ATTENDED,'YYYY/MM')
This returns a list as expected for each month that has attendees. However I would like to list it as
January 2
February 0
March 5
How do I show the count results along with the nulls? My table is very basic
1234 01-JAN-15 Fire Safety
108 01-JAN-15 Fire Safety
1443 02-DEC-15 Healthcare
1388 03-FEB-15 Emergency
1355 06-MAR-15 Fire Safety
1322 09-SEP-15 Fire Safety
1234 11-DEC-15 Fire Safety
I just need to display each month and the total attendees for Fire Safety only. Not used SQL developer for a while so any help appreciated.
You would need a calendar table to select a period you want to display. Simplified code would look like this:
select to_char(c.Date_dt,'YYYY/MM')
, COUNT (*)
FROM calendar as c
left join TRAINING_COURSE_ATTENDED as tca
on tca.DATE_ATTENDED = c.Date_dt
WHERE tca.COURSE_ATTENDED = 'Fire Safety'
and c.Date_dt between [period_start_dt] and [period_end_dt]
GROUP BY to_char(c.Date_dt,'YYYY/MM')
ORDER BY to_char(c.Date_dt,'YYYY/MM')
You can create your own set required year month's on-fly with 0 count and use query as below.
Select yrmth,sum(counter) from
(
select to_char(date_attended,'YYYYMM') yrmth,
COUNT (1) counter
From TRAINING_COURSE_ATTENDED Where COURSE_ATTENDED = 'Fire Safety'
Group By Y to_char(date_attended,'YYYYMM')
Union All
Select To_Char(2015||Lpad(Rownum,2,0)),0 from Dual Connect By Rownum <= 12
)
group by yrmth
order by 1
If you want to show multiple year's, just change the 2nd query to
Select To_Char(Year||Lpad(Month,2,0)) , 0
From
(select Rownum Month from Dual Connect By Rownum <= 12),
(select 2015+Rownum-1 Year from Dual Connect By Rownum <= 3)
Try this :
SELECT Trunc(date_attended, 'MM') Month,
Sum(CASE
WHEN course_attended = 'Fire Safety' THEN 1
ELSE 0
END) Fire_Safety
FROM training_course_attended
GROUP BY Trunc(date_attended, 'MM')
ORDER BY Trunc(date_attended, 'MM')
Another way to generate a calendar table inline:
with calendar (month_start, month_end) as
( select add_months(date '2014-12-01', rownum)
, add_months(date '2014-12-01', rownum +1) - interval '1' second
from dual
connect by rownum <= 12 )
select to_char(c.month_start,'YYYY/MM') as course_month
, count(tca.course_attended) as attended
from calendar c
left join training_course_attended tca
on tca.date_attended between c.month_start and c.month_end
and tca.course_attended = 'Fire Safety'
group by to_char(c.month_start,'YYYY/MM')
order by 1;
(You could also have only the month start in the calendar table, and join on trunc(tca.date_attended,'MONTH') = c.month_start, though if you had indexes or partitioning on tca.date_attended that might be less efficient.)

Not Exists query

I'm trying to find the clients, those who didn't order in the last 2 years and they ordered this year more than 500.. I wrote this query and I used the "NOT EXISTS" condition, but it is still showing me the wrong results.
Some suggestions would be appreciated.
My code:
SELECT
"Sales"."Kundennummer" as 'Neuer Kunde',
year("Sales"."Datum"),
sum("Sales"."Umsatz mit Steuer") as "Umsatz"
FROM "Sales"
WHERE year("Sales"."Datum") = '2017'
AND NOT EXISTS
(
SELECT "Sales"."Kundennummer"
FROM "Sales"
WHERE year("Sales"."Datum") = '2015'
AND year("Sales"."Datum") = '2016'
)
GROUP BY
"Sales"."Kundennummer",
"Sales"."Datum"
HAVING sum("Sales"."Umsatz mit Steuer") > 500
The query in the NOT EXISTS clause will probably yield 0 rows, since a row can't have Datum both 2015 and 2016. So it should probably be OR instead of AND.
Also, if you fix this, there is no link between the subquery and the superquery, which means that it will return rows for any customer (given that there exists a row with Datum either 2015 or 2016 in your table which I guess it does).
So, something like:
SELECT
"Sales"."Kundennummer" as 'Neuer Kunde',
year("Sales"."Datum"),
sum("Sales"."Umsatz mit Steuer") as "Umsatz"
FROM "Sales" sales
WHERE year("Sales"."Datum") = '2017'
AND NOT EXISTS
(
SELECT "Sales"."Kundennummer"
FROM "Sales" salesI
WHERE salesI."Kundennummer" = sales."Kundennummer"
AND (year("Sales"."Datum") = '2015'
OR year("Sales"."Datum") = '2016')
)
GROUP BY
"Sales"."Kundennummer",
"Sales"."Datum"
HAVING sum("Sales"."Umsatz mit Steuer") > 500
Your EXISTS query is not correlated to the main query, i.e. it doesn't look for data for the Kundennummer in question, but whether there are any records in 2015 and 2016.
(You also have the condition for the years wrong by using AND where it must be OR and you should not use quotes on numbers like 2015', and you should not use single quotes on names like 'Neuer Kunde'.)
It should be
AND NOT EXISTS
(
SELECT *
FROM Sales other_years
WHERE other_years.Kundennummer = Sales.Kundennummer
AND year(other_years.Datum) in (2015, 2016)
)
or uncorrelated with NOT IN
AND Kundennummer NOT IN
(
SELECT Kundennummer
FROM Sales
WHERE year(Datum) in (2015, 2016)
)
Be aware though, that when using NOT IN the subquery must return no nulls. E.g. where 3 not in (1, 2, null) does not result in true, as one might expect, because the DBMS argues that the unknown value (null) might very well be a 3 :-)
I propose you here below 3 different ways to do it:
Joining 2 tables
select this_year_sales.kundenummer, this_year_sales.tot_umsatz
from (select sum(umsatz) tot_umsatz, kundenummer from sales where extract(year from (datum)) = extract(year from sysdate) group by kundenummer) this_year_sales
, (select kundenummer, max(datum) max_datum from sales where datum < trunc(sysdate, 'year') group by kundenummer) previous_sales
where this_year_sales.kundenummer = previous_sales.kundenummer
and extract(year from previous_sales.max_datum) < (extract(year from sysdate)-2)
and this_year_sales.tot_umsatz > 500;
Using NOT INT
select kundenummer, sum(umsatz)
from sales s
where extract(year from datum) = extract(year from sysdate)
and kundenummer not in (select kundenummer from sales where extract(year from datum) > (extract(year from sysdate) - 2) and extract(year from datum) < (extract(year from sysdate)-1))
group by kundenummer
having sum(umsatz) > 500;
Using NOT EXISTS
select kundenummer, sum(umsatz)
from sales s
where extract(year from datum) = extract(year from sysdate)
and not exists(
select s1.kundenummer, s1.datum from sales s1 where extract (year from s1.datum) >= (extract(year from sysdate)-2) and extract(year from s1.datum) < extract (year from sysdate) and s1.kundenummer = s.kundenummer
)
group by kundenummer
having sum(umsatz) > 500;

ORA-01858 error using dates

I am not a programmer by trade but I know some SQL. I just need another set of eyes on my code because I am not sure why I am getting this error.
select
count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and ci.ci_create_date in (select case when ci.ci_create_date between to_date('1/1/2016','mm/dd/yyyy') and to_date('1/31/2016','mm/dd/yyyy') then 'January'
when ci.ci_create_date between to_date('2/1/2016','mm/dd/yyyy') and to_date('2/29/2016','mm/dd/yyyy') then 'February'
when ci.ci_create_date between to_date('3/1/2016','mm/dd/yyyy') and to_date('3/31/2016','mm/dd/yyyy') then 'March'
else '' end from regmdr.contact_interaction ci group by to_char(ci.ci_create_date, 'yyyy-mm')
You are trying to compare the ci.ci_create_date date value with the string that is produced by your case statement, which is January, February, March or null. So you're effectively doing a comparison like:
ci.ci_create_date = to_date('January')
Unless your NLS_DATE_FORMAT is 'Month' and your language is English, that will get the ORA-01858. You could convert the left-hand side of that to the month name too, but without the year in either format model that would include data from January in any year; and it's better for performance to not convert the data from the table if you can avoid it.
It isn't entirely clear what you're trying to do but as the subquery has an independent view of contact_interaction with no correlation it probably isn't going to do whatever you are trying anyway.
If you're trying to count values from the first three months of this year then you can do:
select count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and ci.ci_create_date >= date '2016-01-01'
and ci.ci_create_date < date '2016-04-01'
Which will give you a single number. If you want it by month your group by was in the wrong place, and you can add
...
group by trunc(ci.ci_create_date, 'MM')
although you really need that in the select list too for the result set to make any sense - so you know which month each count belongs to.
Based on using the month names at all, perhaps you wanted those in the select list:
select to_char(trunc(ci.ci_created_date, 'MM'), 'Month') as month,
count(1) as AH
from regmdr.contact_interaction ci
...
group by trunc(ci.ci_create_date, 'MM')
... but I'm speculating even more now. Also be aware that month names are sensitive to your NLS settings, particularly NLS_DATE_LANGUAGE. You can force them to always be in English via the optional third argument to to_char() though, e.g.
select to_char(trunc(ci.ci_created_date, 'MM'), 'Month', 'NLS_DATE_LANGUAGE=ENGLISH')
...
Why not go with:
select to_char(ci.ci_create_date, 'YYYY-MM') monthyear,
count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and to_char(ci.ci_create_date, 'MON' in ('JAN', 'FEB', 'MAR')
group by to_char(ci.ci_create_date, 'yyyy-mm';
If you are only interested in the counts (without context), wrap it in an outside select statement:
select AH
from (select to_char(ci.ci_create_date, 'YYYY-MM') monthyear,
count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and to_char(ci.ci_create_date, 'MON') in ('JAN', 'FEB', 'MAR')
group by to_char(ci.ci_create_date, 'yyyy-mm'
);