What is the syntax for day of week select case? - sql

I'm trying to use a case select if the day is Monday (or d is equal to 2), and the 'else' would handle every other day of the week.
Select to_char (sysdate, 'D') d from dual,
/*if 2 or Monday then run this part*/
CASE
2
Then
SELECT DISTINCT RPAD(CLAIM.CLAIM_NUMBER, 20) ||
LPAD(CLAIM.CLAIM_ID, 15, '0') ||
TO_CHAR(CLAIM.INCIDENT_DATE, 'MMDDYYYY') ||
LPAD(' ',2) ||
'D'
FROM CLAIM,CLAIMANT,INSURER,POLICY
WHERE CLAIM.CLAIM_ID = CLAIMANT.CLAIM_ID
AND POLICY.INSURER_NUMBER = INSURER.INSURER_NUMBER
AND INSURER.INSURER_NUMBER NOT IN ('7','8')
AND CLAIMANT.EXAMINER1_CODE NOT IN ('MAYCONV')
AND CLAIM.INSURANCE_TYPE = 2
AND CLAIM.JURISDICTION_CODE <> 1
AND CLAIMANT.CLAIMANT_TYPE_CODE in (4,7)
/*if Monday then go 2 days back*/
AND CLAIMANT.EDIT_DATE > (SYSDATE - 2)
/*if not equal to 2 or any day but Monday then run this part*/
Else
SELECT DISTINCT RPAD(CLAIM.CLAIM_NUMBER, 20) ||
LPAD(CLAIM.CLAIM_ID, 15, '0') ||
TO_CHAR(CLAIM.INCIDENT_DATE, 'MMDDYYYY') ||
LPAD(' ',2) ||
'D'
FROM CLAIM,CLAIMANT,INSURER,POLICY
WHERE CLAIM.CLAIM_ID = CLAIMANT.CLAIM_ID
AND POLICY.INSURER_NUMBER = INSURER.INSURER_NUMBER
AND INSURER.INSURER_NUMBER NOT IN ('7','8')
AND CLAIMANT.EXAMINER1_CODE NOT IN ('MAYCONV')
AND CLAIM.INSURANCE_TYPE = 2
AND CLAIM.JURISDICTION_CODE <> 1
AND CLAIMANT.CLAIMANT_TYPE_CODE in (4,7)
/*if not Monday then go 1 day back*/
AND CLAIMANT.EDIT_DATE > (SYSDATE - 1)
/

I didn't follow your code closely, but it seems you just want the last condition in your where clause to depend on the day of the week.
If so, you need something like (WARNING: I didn't check anything else in the code to make sure it is correct or efficient!) - the only change is in the last line. You don't need the select... from dual and you only need to write the select statement once.
SELECT DISTINCT RPAD(CLAIM.CLAIM_NUMBER, 20) ||
LPAD(CLAIM.CLAIM_ID, 15, '0') ||
TO_CHAR(CLAIM.INCIDENT_DATE, 'MMDDYYYY') ||
LPAD(' ',2) ||
'D'
FROM CLAIM,CLAIMANT,INSURER,POLICY
WHERE CLAIM.CLAIM_ID = CLAIMANT.CLAIM_ID
AND POLICY.INSURER_NUMBER = INSURER.INSURER_NUMBER
............
AND CLAIMANT.EDIT_DATE > SYSDATE - case to_char(sysdate, 'd') when 2 then 2 else 1 end

Related

Validation of first 6 digits in a SQL query in Oracle SQL developer

There is a requirement where I need to validate the identity card number with the first 6 digits as DOB. I need to find out the users not maintaining correct format.
If the dob is 02/10/1983 - 83021023456 && if its 02/10/2083 ->83221023456 (DOB is in MM/DD/YYYY and if year of birth >2000 then the +20 is done to the dob month). The query I tried with is given below:-
SELECT f_account_name,F_SSN ,F_DOB from table where
CASE WHEN SUBSTR(to_char(F_DOB, 'YYYY-MM-DD'),0,4)>2000
THEN
SUBSTR(f_ssn,0,6) <>
SUBSTR(to_char(F_DOB, 'YY-MM-DD'),0,2)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),4,2)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),7,2)
ELSE
SUBSTR(f_ssn,0,6) <>
SUBSTR(to_char(F_DOB, 'YY-MM-DD'),0,2)
||(SUBSTR(to_char(F_DOB, 'YY-MM-DD'),4,2)+20)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),7,2)
END;
Its not working .
You cannot have the comparison inside the CASE expression; since the left-hand side of the expression is identical then it is simple to move it out and then you can simplify the rest:
SELECT f_account_name,
F_SSN,
F_DOB
FROM table_name
WHERE SUBSTR(f_ssn,0,6) !=
CASE
WHEN EXTRACT( YEAR FROM F_DOB ) > 2000
THEN TO_CHAR( F_DOB, 'YYMMDD')
ELSE TO_CHAR( F_DOB, 'YY' )
|| TO_CHAR( EXTRACT( MONTH FROM F_DOB )+20, 'FM00' )
|| TO_CHAR( F_DOB, 'DD')
END;
or, if the rule is to add 20 to the month for each century past 1900 (i.e. 20XX add 20 and 21XX add 40, etc.) then:
SELECT f_account_name,
F_SSN,
F_DOB
FROM table_name
WHERE SUBSTR(f_ssn,0,6) !=
TO_CHAR( F_DOB, 'YY' )
|| TO_CHAR(
EXTRACT( MONTH FROM F_DOB )
+ 20 * GREATEST( TRUNC( EXTRACT( YEAR FROM F_DOB ) / 100 ) - 19, 0 ),
'FM00'
)
|| TO_CHAR( F_DOB, 'DD');
I tried some date arithmetics and worked with numbers rather than strings ...
WITH
-- your input
indata(f_account_name,f_ssn,f_dob) AS (
--string -- number -- string
SELECT 'Arthur',83021023456,'02/10/1983' FROM dual
UNION ALL SELECT 'Tricia',83221023456,'02/10/2083' FROM dual
)
SELECT
f_account_name
, f_ssn
, f_dob
FROM indata
WHERE CAST(TRUNC(f_ssn/100000) AS NUMBER(6))
-- ^ integer division by 100000 to get the first 6 digits ...
= MOD(EXTRACT(YEAR FROM TO_DATE(f_dob,'MM/DD/YYYY')),100) * 10000
-- ^ modulo year of date of 100 gives 3rd and 4th digit of year
+ (
EXTRACT(MONTH FROM TO_DATE(f_dob,'MM/DD/YYYY'))
+CASE
WHEN EXTRACT(YEAR FROM TO_DATE(f_dob,'MM/DD/YYYY')) >= 2000 THEN 20
ELSE 0
END
) * 100
+ EXTRACT(DAY FROM TO_DATE(f_dob,'MM/DD/YYYY'))
;

Grouping SQL-Result by time does not work

I am trying to set up an SQL query in Firebird 2.5 in order to make a statistic about sales grouped by time.
My approach I followed up so far would be:
SELECT EXTRACT(WEEKDAY FROM ODR.ORDERDATE) AS S1, EXTRACT(HOUR FROM ODR.ORDERDATE) AS S2,
CASE
WHEN (EXTRACT(HOUR FROM ODR.ORDERDATE)) < 10 THEN
'0' || CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':00 - ' || '0' ||
CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':59 '
WHEN EXTRACT(HOUR FROM ODR.ORDERDATE) >= 10 THEN
CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':00 - ' ||
CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':59 '
END AS TINTERVAL,
COUNT(ODR.ID) AS ABSCOUNT
FROM ODR
GROUP BY S1,S2,TINTERVAL
ORDER BY S1,S2 ASC
The syntax of this query seems to be fine for SQL-Connection established by Firebird ODBC 2.5.
My question:
For hour=0 (<10) the query returns a result set which is not presented by the data given by the orders.
e.g. the result-set for this query might look like this:
S1 S2 TINTERVAL ABSCOUNT
0 0 00:00 - 00:59 30
0 1 01:00 - 01:59 2
I don't know how this query comes to its strange count in hour = 0.
This does not make any sense to me.

Sql (on Oracle) aging report by days

I need help writing a aging report on oracle.
The report should be like:
aging file to submit total 17
aging file to submit 0-2 days 3
aging file to submit 2-4 days 4
aging file to submit 4-6 days 4
aging file to submit 6-8 days 2
aging file to submit 8-10 days 4
I can create a query for each section and then union all the the results like:
select 'aging file to submit total ' || count(*) from FILES_TO_SUBMIT where trunc(DUE_DATE) > trunc(sysdate) -10
union all
select 'aging file to submit 0-2 days ' || count(*) from FILES_TO_SUBMIT where trunc(DUE_DATE) <= trunc(sysdate) and trunc(DUE_DATE) >= trunc(sysdate-2)
union all
select 'aging file to submit 2-4 days ' || count(*) from FILES_TO_SUBMIT where trunc(DUE_DATE) <= trunc(sysdate-2) and trunc(DUE_DATE) >= trunc(sysdate-4) ;
I was wondering if there is a better way using oracle analytic functions or any other query that will get better performance?
Sample data:
CREATE TABLE files_to_submit(file_id int, file_name varchar(255),due_date date);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 1, 'file_' || 1, sysdate);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 2, 'file_' || 2, sysdate -5);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 3, 'file_' || 3, sysdate -4);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 4, 'file_' || 4, sysdate);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 5, 'file_' || 5, sysdate-3);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 6, 'file_' || 6, sysdate-7);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 7, 'file_' || 7, sysdate-10);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 8, 'file_' || 8, sysdate-12);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 9, 'file_' || 9, sysdate-3);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 10, 'file_' || 10, sysdate-5);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 11, 'file_' || 11, sysdate-6);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 12, 'file_' || 12, sysdate-7);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 13, 'file_' || 13, sysdate-5);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 14, 'file_' || 14, sysdate-4);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 15, 'file_' || 15, sysdate-2);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 16, 'file_' || 16, sysdate-6);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 17, 'file_' || 17, sysdate-6);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 18, 'file_' || 18, sysdate-5);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 19, 'file_' || 19, sysdate-10);
INSERT INTO FILES_TO_SUBMIT(FILE_ID,FILE_NAME,DUE_DATE) VALUES ( 20, 'file_' || 20, sysdate-9);
DROP TABLE files_to_submit;
you can use this simple approach to get the report for all days(without total):
select
'aging file to submit '|| trunc(dist/2)*2 ||'-'|| (trunc(dist/2)*2+2) || ' days: ' || count(*)
from (
select trunc(sysdate) - trunc(DUE_DATE) as dist
from FILES_TO_SUBMIT
--where trunc(DUE_DATE) > trunc(sysdate) -10
)
group by trunc(dist/2)
order by trunc(dist/2);
The only thing that is important is just number of days (dist(ance) field).
If you want to have also the Total in the same scan:
select
'aging file to submit '||
case
when trunc(dist/2) is null
then 'Total '
else trunc(dist/2)*2 ||'-'|| (trunc(dist/2)*2+2) || ' days: '
end ||
count(*)
from (
select trunc(sysdate) - trunc(DUE_DATE) as dist
from FILES_TO_SUBMIT
where trunc(DUE_DATE) > trunc(sysdate) -10
)
group by rollup(trunc(dist/2))
order by trunc(dist/2)
nulls first;
Hint: If you have hundreds of days of history an index would be useful. (pay attention: if your table is very big, >100Milion, the creation of the index will take some time)
create index index_name on files_to_submit(due_date);
and then change the condition to:
where DUE_DATE > trunc(sysdate) - 10
This will speed up y
Allow me to suggest WIDTH_BUCKET.
This will divide the date range into equal size. Since you want 10 days range into groups of 2 days, the bucket size will be 10 / 2 = 5.
Query:
SELECT
CASE GROUPING(bucket)
WHEN 1
THEN 'aging file to submit Total'
ELSE 'aging file to submit ' || (bucket-1)*2 || '-' || (bucket)*2 || ' days'
END AS bucket_number,
COUNT(1) AS files
FROM (
SELECT
WIDTH_BUCKET(due_date, sysdate, sysdate-10, 5) bucket
FROM
files_to_submit
WHERE
due_date >= sysdate-10
)
GROUP BY
ROLLUP(bucket)
ORDER BY
bucket NULLS FIRST;
Result:
BUCKET_NUMBER FILES
------------------------------------ ----------
aging file to submit Total 17
aging file to submit 0-2 days 2
aging file to submit 2-4 days 3
aging file to submit 4-6 days 6
aging file to submit 6-8 days 5
aging file to submit 8-10 days 1
I got different counts using your sample data -- I get 19 total instead of 17 (which seems appropriate as only one of the 20 records in your sample data is out of the range):
WITH d1 AS (
SELECT 2 AS day_cnt FROM dual
UNION ALL
SELECT 4 FROM dual
UNION ALL
SELECT 6 FROM dual
UNION ALL
SELECT 8 FROM dual
UNION ALL
SELECT 10 FROM dual
)
SELECT NVL(title, 'aging file to submit total') AS title, COUNT(DISTINCT file_id)
FROM (
SELECT 'aging file to submit ' || prev_day || '-' || day_cnt || ' days' AS title, f1.file_id
FROM (
SELECT day_cnt, NVL(LAG(day_cnt) OVER ( ORDER BY day_cnt ), 0) AS prev_day
FROM d1
) d2, files_to_submit f1
WHERE TRUNC(f1.due_date) <= TRUNC(SYSDATE - d2.prev_day)
AND TRUNC(f1.due_date) >= TRUNC(SYSDATE - d2.day_cnt)
) GROUP BY ROLLUP(title);
Also, the counts for the day ranges aren't right (they don't add up to 19, that is) because of the the files can be counted twice due to the use of TRUNC() and including both end cases. But I'm sure you can tweak the above to give what you want.
WITH r (
'aging file to submit ' Prefix,
Total,
Days0_2,
Days2_4,
Days4_6,
Days6_8,
Days8_10
) AS (
SELECT
SUM(Total) Total,
SUM(Days0_2) Days0_2,
SUM(Days2_4) Days2_4,
SUM(Days4_6) Days4_6,
SUM(Days6_8) Days6_8,
SUM(Days8_10) Days8_10
FROM (
SELECT
(CASE WHEN f.days <= 2 THEN f.num ELSE NULL END) AS Days0_2,
(CASE WHEN f.days >= 2 AND f.days <= 4 THEN f.num ELSE NULL END) AS Days2_4,
(CASE WHEN f.days >= 4 AND f.days <= 6 THEN f.num ELSE NULL END) Days4_6,
(CASE WHEN f.days >= 6 AND f.days <= 8 THEN f.num ELSE NULL END) AS Days6_8,
(CASE WHEN f.days >= 8 AND f.days <= 10 THEN f.num ELSE NULL END) AS Days8_10,
f.num AS Total
FROM (
SELECT
COUNT(*) AS num,
TRUNC(due_date) - TRUNC(SYSDATE) + 10 AS days
FROM FILES_TO_SUBMIT t
WHERE (TRUNC(due_date) - TRUNC(SYSDATE) + 10) >= 0
GROUP BY TRUNC(due_date) - TRUNC(SYSDATE) + 10
) f
) s
)
SELECT Prefix || 'Total' AS Label, Total AS Count FROM r
UNION ALL SELECT Prefix || '0-2 days', Days0_2 FROM r
UNION ALL SELECT Prefix || '2-4 days', Days2_4 FROM r
UNION ALL SELECT Prefix || '4-6 days', Days4_6 FROM r
UNION ALL SELECT Prefix || '6-8 days', Days6_8 FROM r
UNION ALL SELECT Prefix || '8-10 days', Days8_10 FROM r
It will not double count records for the Total row. Since your day ranges overlap you cannot sum up the individual counts to get the total. As another query given here gives a total of 25 with only 20 records and 1 out of range.
The result for total is what you expect with 20 records and 1 being 12 days old. The innermost query does all the heavy lifting but it is executed once to get all aging results. Its result will be at most 11 rows, 0-10 days. The rest of the queries are for final results and pretty output.
You can eliminate one query level by SUMing one level in, I just find it easier to validate the results by being able to select intermediate queries for a spot check.
Here is the result of the query:
This approach allows you to maintain your buckets separately from your main SQL in case you want them to be different sizes or to name them something that is not generated from the SQL, such as 'On time', 'Delinquent', etc. and also provides a very readable main SQL block.
with aging as
(select count(*) count_per_day, (trunc(sysdate) - trunc(f.due_date)) age
from files_to_submit f
where trunc(f.due_date - 10) <= sysdate
group by (trunc(sysdate) - trunc(f.due_date))),
buckets as
(select 1 bucket_id, 0 bucket_min, 2 bucket_max, 'aging file to submit 0-2' bucket_name from dual
union select 2, 2, 4, 'aging file to submit 2-4' from dual
union select 3, 4, 6, 'aging file to submit 4-6' from dual
union select 4, 6, 8, 'aging file to submit 6-8' from dual
union select 5, 8, 10, 'aging file to submit 8-10' from dual
union select 6, null, null, 'aging file to submit total' from dual
)
select nvl(b.bucket_name, (select bucket_name from buckets where bucket_id = 6)), sum(a.count_per_day) bucket_cnt
from aging a
join buckets b on (a.age >= b.bucket_min and a.age <= b.bucket_max)
group by rollup(b.bucket_name)
order by b.bucket_name nulls first;

Date range sets

I have a question which is divided in two parts
Part 1
How can I get the following set of records with sysdate as current week?
07-Apr-2013 - 13-Apr-2013
14-Apr-2013 - 20-Apr-2013
21-Apr-2013 - 27-Apr-2013
28-Apr-2013 - 04-May-2013
If week is past 07-Apr-2012 - 13-Apr-2013, then next four sets. So always it will have 4 weeks.
Part 2
and if current week falls within the range of dates i.e. 07-Apr-2012 - 13-Apr-2013, I would like to get Monday and Friday from the list.
How can I get the desired output?
I'm a little confused by the date ranges you provide in your example as the start date of each range is a Sunday in 2013 yet you show 2012 as the year. I am going to assume the 2012 is a typo.
Does this get you what you want?
select
case
when trunc(sysdate) between start_date and end_date
then to_char(start_date + 1, 'DD-MON-YYYY')
else to_char(start_date, 'DD-MON-YYYY')
end
|| ' - ' ||
case
when trunc(sysdate) between start_date and end_date
then to_char(end_date - 1, 'DD-MON-YYYY')
else to_char(end_date, 'DD-MON-YYYY')
end date_range
from
(
select
next_day(trunc(sysdate - 7 + ((level - 1) * 7)), 'SUN') start_date,
next_day(trunc(sysdate) + ((level - 1) * 7), 'SAT') end_date
from dual
connect by level < 5
)
If you want just the 4 weeks then you can do this
select
to_char(next_day(trunc(sysdate - 7 + ((level - 1) * 7)), 'SUN'), 'DD-MON-YYYY')
|| ' - ' ||
to_char(next_day(trunc(sysdate) + ((level - 1) * 7), 'SAT'), 'DD-MON-YYYY') date_range
from dual
connect by level < 5
Part 1 (4 weeks starting with the current week)
SELECT TO_CHAR(trunc(SYSDATE, 'DY')) || ' - ' || TO_CHAR(trunc(SYSDATE, 'DY')+ 6) from dual
UNION
SELECT TO_CHAR(trunc(SYSDATE, 'DY')+7) || ' - ' || TO_CHAR(trunc(SYSDATE, 'DY')+ 13) from dual
UNION
SELECT TO_CHAR(trunc(SYSDATE, 'DY')+14) || ' - ' || TO_CHAR(trunc(SYSDATE, 'DY')+ 20) from dual
UNION
SELECT TO_CHAR(trunc(SYSDATE, 'DY')+21) || ' - ' || TO_CHAR(trunc(SYSDATE, 'DY')+ 27) from dual
;
Part 2 Monday and Friday of the current week:
SELECT trunc(SYSDATE, 'DY')+1 "Monday", trunc(SYSDATE, 'DY')+5 "Friday"
FROM dual;
Here's SQL Fiddle.
select
max(trunc(sysdate) + level - 7) as sunday,
max(trunc(sysdate) + level - 2) as friday,
max(trunc(sysdate) + level - 1) as saturday
from dual
connect by level < 30
group by to_char(sysdate + level, 'iw')
having max(trunc(sysdate) + level - 1) <= sysdate + 27
order by 1
fiddle

DB2 date conversion

I have 2 INTEGER columns like the following:
Month Year
----- -----
5 2011
Is there any way to convert that to a single column VARCHAR like this: May-2011
I don't know of an easy way to do this since you don't have a date object (ie its not like youre finding the month of a timestamp), you can use a case statement but it gets long.
SELECT CASE Month
WHEN '1' THEN 'January'
WHEN '2' THEN 'February'
WHEN '3' THEN 'March'
WHEN '4' THEN 'April'
...
END+'-'+Year
FROM TABLE
I think this will do it:
SELECT
MONTHNAME(
DATE(CAST(Year AS CHAR(4)) || '-' || TRIM(CAST(Month AS CHAR(2))) || '-1')
) || '-' || CAST(Year AS CHAR(4))
FROM TABLE
This should do the trick, assuming that the columns Month and Year are integers and Month has the domain 1-12:
select substring('---JanFebMarAprMayJunJulAugSepOctNovDec', 3*Month , 3 )
+ '-'
+ right(digits(Year),4)
from some_table
If Month is 0 you'll get '---' as the month; if it's less than 0 or greater than 12, you'll get some sort of blooey.
You could create a function to convert the month value, like this...
CREATE FUNCTION INT2MONTH (MONTH INTEGER)
RETURNS VARCHAR(100)
LANGUAGE SQL
CONTAINS SQL
NO EXTERNAL ACTION
DETERMINISTIC
RETURN MONTHNAME('2000-' || RIGHT('0' || STRIP(CHAR(MONTH)), 2) || '-01')
Then you can...
select int2month(month) || '-' || strip(char(year)) from test
1
--------------------------------------------------
May-2011
June-2011
December-2012
If you want a 3 char month then change last last on function to...
RETURN LEFT(MONTHNAME('2000-' || RIGHT('0' || STRIP(CHAR(MONTH)), 2) || '-01'), 3)
I realize this question is pretty old, but there's a way that is a lot simpler than any of the options listed here (in my opinion) -- a combination of some date math and the VARCHAR_FORMAR() function:
SELECT
VARCHAR_FORMAT(
DATE('0001-01-01') + (month_col - 1) MONTH + (year_col - 1) YEAR
,'Month-YYYY'
)
FROM your_table