Tuesday, 13 August 2013
Suppressing leading zeros in date and time formats
I recently looked into a problem with a date format issue. The problem was a time component of a date needed to be formatted to match a certain format in a text file.
The format was DD/MM/YYYY HH24:MI:SS but if the hour was less than 10 it should suppres the leading zero but the normal format mask here doesn't do that.
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'DD/MM/YYYY HH24:MI:SS')
FROM dual
07/04/2004 07:05:05
With a bit of searching I found the Format Model Modifiers and specifically Fill Mode (FM). It can be used to strip leading zeros as well as leading spaces.
Basically it is used as toggle in the string. The first time it is used fill mode is turned on. The sceong time it is used fill mode is turned off.
Here are some examples.
To achieve the result for the problem at hand we surround the hour component with the fm tag like this.
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'DD/MM/YYYY fmHH24fm:MI:SS')
FROM dual
07/04/2004 7:05:05
To strip off the zeros from the date we can also do this
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'fmDDfm/fmMMfm/YYYY fmHH24fm:MI:SS')
FROM dual
7/4/2004 7:05:05
Or another way we use it across day and month
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'fmDD/MMfm/YYYY fmHH24fm:MI:SS')
FROM dual
7/4/2004 7:05:05
Or then across day, month, year and hour in one go.
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'fmDD/MM/YYYY HH24fm:MI:SS')
FROM dual
7/4/2004 7:05:05
But if we do the whole format mask we end up with something that is probably not what you want.
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'fmDD/MM/YYYY HH24:MI:SSfm')
FROM dual
7/4/2004 7:5:5
This fill mode is also useful for the dates where you use the full word. If you format it without fill mode the month will have leading spaces. Like this
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'DD/MONTH/YYYY HH24:MI:SS')
FROM dual
07/APRIL /2004 07:05:05
But if we use fill mode around the month then it is fomatted with the leading spaces stripped off.
SELECT to_char(to_date('07/04/2004 07:05:05',
'DD/MM/YYYY HH24:MI:SS'),
'DD/fmMONTHfm/YYYY HH24:MI:SS')
FROM dual
07/APRIL/2004 07:05:05
Tuesday, 14 May 2013
A quick cheat sheet for clearing out oracle database queues with DBMS_AQADM
To find the name of the queue table you might need to deal with you can simply do
Which will give you the name and owner of the queue table. Then you can do a select to find out how many items are in the queue. In the example below the queue table is called test_msg_queue_table and the owner is app_owner. Note the aq$ must be added to the start of the queue table name.
SELECT count(*) FROM app_owner.aq$test_msg_queue_table
Then as the schema owner you can run a script as below to clear out all the items in the queue.
DECLARE
po dbms_aqadm.aq$_purge_options_t;
BEGIN
po.block := TRUE;
DBMS_AQADM.PURGE_QUEUE_TABLE(
queue_table => 'APP_OWNER.TEST_MSG_QUEUE_TABLE',
purge_condition => NULL,
purge_options => po);
END;
Wednesday, 6 February 2013
Using DBMS_XMLGEN for XML from PL/SQL
I started looking into the
DBMS_XMLGEN package when we had a need to do character escaping of some XML
text. Basically we needed to convert all the < and > characters to <
and > in PL/SQL.
Here is a quick script to demonstrate using DBMS_XMLGEN.CONVERT
to do this.
To convert to a simple string ‘<>CAT<>’
SELECT DBMS_XMLGEN.CONVERT(xmldata=>'<>CAT<>',
flag=>0) FROM dual
results in the string
<>CAT<>
Then to convert back the other way.
SELECT DBMS_XMLGEN.CONVERT(xmldata=>'<>CAT<>',
flag=>1) FROM dual
results in the original string
<>CAT<>
With the flags instead of using 0 or 1 you should be able to
use DBMS_XMLGEN.ENCODE and DBMS_XMLGEN.DECODE but I have not been able to get
these to be recognised which might be an environmental issue in this database.
Looking further into the DBMS_XMLGEN package I found that
is can do a great deal more with XML processing. Here is a basic example of
running a query and having it formatted as XML then using dbms_output.put_line
to display the CLOB.
DECLARE
v_ctxhandle DBMS_XMLGEN.ctxHandle;
v_clob CLOB;
v_offset NUMBER := 1;
BEGIN
v_ctxhandle
:= DBMS_XMLGEN.NEWCONTEXT (
'SELECT
employee_id ID,
last_name,
to_char(hire_date,
''DD/MM/YYYY'') Hire
FROM
employees
WHERE
employee_id < 105');
v_clob :=
DBMS_XMLGEN.getXML(v_ctxhandle);
loop exit
when v_offset > dbms_lob.getlength(v_clob);
dbms_output.put_line(dbms_lob.substr(
v_clob, 32767, v_offset));
v_offset := v_offset +
32767;
end loop;
DBMS_LOB.FREETEMPORARY(v_clob);
DBMS_XMLGEN.CLOSECONTEXT(v_ctxhandle);
END;
This results in this XML
<?xml version="1.0"?>
<ROWSET>
<ROW>
<ID>100</ID>
<LAST_NAME>King</LAST_NAME>
<HIRE>17/06/1987</HIRE>
</ROW>
<ROW>
<ID>101</ID>
<LAST_NAME>Kochhar</LAST_NAME>
<HIRE>21/09/1989</HIRE>
</ROW>
<ROW>
<ID>102</ID>
<LAST_NAME>De Haan</LAST_NAME>
<HIRE>13/01/1993</HIRE>
</ROW>
<ROW>
<ID>103</ID>
<LAST_NAME>Hunold</LAST_NAME>
<HIRE>03/01/1990</HIRE>
</ROW>
<ROW>
<ID>104</ID>
<LAST_NAME>Ernst</LAST_NAME>
<HIRE>21/05/1991</HIRE>
</ROW>
</ROWSET>
Now to further expand the example we can include some
options to change the way the XML is handled.
DECLARE
v_ctxhandle
DBMS_XMLGEN.ctxHandle;
v_clob CLOB;
v_offset NUMBER := 1;
BEGIN
v_ctxhandle
:= DBMS_XMLGEN.NEWCONTEXT (
'SELECT
employee_id ID,
last_name,
to_char(hire_date, ''DD/MM/YYYY'') Hire
FROM employees
WHERE
employee_id < 105');
-- Pretty print will do the nice indentation.
DBMS_XMLGEN.setPrettyPrinting(v_ctxhandle, TRUE);
-- The indentation width can be set.
DBMS_XMLGEN.setIndentationWidth(v_ctxhandle, 2);
-- Set the tag for the rowset
DBMS_XMLGEN.setrowsettag(v_ctxhandle, 'PEOPLE');
-- Set the tag for the row.
DBMS_XMLGEN.setrowtag(v_ctxhandle, 'PERSON');
-- when we retrieve row from this query only get two at a
time, this can let
-- you do things like control the amount of data you show on one page.
DBMS_XMLGEN.setmaxrows(v_ctxhandle,
2);
-- Now do the query as before
v_clob :=
DBMS_XMLGEN.getXML(v_ctxhandle);
loop exit
when v_offset > dbms_lob.getlength(v_clob);
dbms_output.put_line(dbms_lob.substr( v_clob, 32767, v_offset));
v_offset := v_offset + 32767;
end loop;
dbms_output.put_line('Can do some new page processing here');
DBMS_LOB.FREETEMPORARY(v_clob);
v_offset :=
1;
v_clob :=
DBMS_XMLGEN.getXML(v_ctxhandle);
loop exit
when v_offset > dbms_lob.getlength(v_clob);
dbms_output.put_line(dbms_lob.substr( v_clob, 32767, v_offset));
v_offset := v_offset + 32767;
end loop;
DBMS_LOB.FREETEMPORARY(v_clob);
DBMS_XMLGEN.CLOSECONTEXT(v_ctxhandle);
END;
<?xml version="1.0"?>
<PEOPLE>
<PERSON>
<ID>100</ID>
<LAST_NAME>King</LAST_NAME>
<HIRE>17/06/1987</HIRE>
</PERSON>
<PERSON>
<ID>101</ID>
<LAST_NAME>Kochhar</LAST_NAME>
<HIRE>21/09/1989</HIRE>
</PERSON>
</PEOPLE>
Can do some new page processing here
<?xml version="1.0"?>
<PEOPLE>
<PERSON>
<ID>102</ID>
<LAST_NAME>De Haan</LAST_NAME>
<HIRE>13/01/1993</HIRE>
</PERSON>
<PERSON>
<ID>103</ID>
<LAST_NAME>Hunold</LAST_NAME>
<HIRE>03/01/1990</HIRE>
</PERSON>
</PEOPLE>
There are lots of ways of doing XML processing from PL/SQL
and DBMS_XMLGEN seems to offer many options that can be explored further.
Subscribe to:
Posts (Atom)