Oracle Tip: Ignoring case and diacritic differences in an Oracle search.

February 1, 2010 by Reboot · Leave a Comment 

http://forums.oracle.com/forums/thread.jspa?threadID=14970

Instead of using the SQL UPPER and LOWER functions to perform case-insensitive queries, an alternative approach is to utilize the linguistic sort GENERIC_BASELETTER. GENERIC_BASELETTER groups all characters together based on their base letter values, this is achieved by ignoring their case and the diacritic differences.
Here is an example of a GENERIC_BASELETTER query.

ALTER SESSION SET NLS_COMP=ANSI;
ALTER SESSION SET NLS_SORT=GENERIC_BASELETTER;

SELECT * FROM PRODUCT
WHERE PRODUCT_NAME = database;

All other operators, such as LIKE, perform comparisons in binary mode only. i.e. they do not honor the NLS_SORT value. This has now been be enhanced in 10gR2.

See also:
Diacritics in like clause, Globalization support
http://dbaforums.org/oracle/index.php?showtopic=915

Diacritics
http://en.wikipedia.org/wiki/Diacritic

Oracle® Database Globalization Support Guide
http://download.oracle.com/docs/cd/B14117_01/server.101/b10749/ch5lingsort.htm#i1006463

Oracle NLS_LOWER
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions098.htm#i78373

Oracle Replace
http://www.psoug.org/reference/translate_replace.html

SELECT translate('árvíztűrőtükörfúrógép','áéíóöőúüű','aeiooouuu') without FROM dual

To GUID or not to GUID, on Oracle …

November 30, 2009 by Reboot · Leave a Comment 

I keep running into that issue when I design a database, this time around it’s an Oracle schema, thus I need fresh input on GUIDs and Oracle. It’s basically the old story, if distribution and replication is a serious feature, a GUID would be very welcome. We could also create a hybrid monster, take a numeric primary key and supplement a GUID field for distribution purposes, sure it takes up additional space …

Arguments for the use of GUIDs

- Makes distribution and replication a lot easier.
- ID’s can be created in the application, thus no ID would need to fetched from a DB insert.
- Creating ID’s on the “client” side enables working “offline”.
- Enabled (dirty?) cross-table references, e.g. a table which contains website url’s could contain a generic “ID” column which contains id’s from the “books” table or “articles” table. This also applies for class models ofcourse.
- Security (by obscurity) in urls.
- don’t have to create those (annoying) sequences with triggers in Oracle :)

Arguments against the use of GUIDs

- Performance (will depend on which database, e.g. Oracle also has sequential GUIDs and MS-Sql has a native guid type).
- Universally small chance that it’s not unique.
- Looks ugly (heard that a LOT)
- It has a Microsoft feel to it :)

Well, Google also supplies some nice information about the performance, reasons to use (or not) and options:

[1] How should I store a Guid in Oracle
[2] Unique IDs for multi-master replication – Sequence or SYS_GUID?
[3] Watch out for sequential Oracle GUIDs!
[4] UUIDs as primary keys

- Probable performance loss of 40% when using a CHAR / RAW(16) instead of an integer. [1] (Searching is faster in CHAR as all the strings are stored at a specified position from the each other, the system doesnot have to search for the end of string, thus CHAR instead of VARCHAR2, plus the length of a GUID is fixed anyway)
Whereas in VARCHAR the system has to first find the end of string and then go for searching.
- SYS_GUID is sequential because random GUIDs play hell with indexes. SQL Server has a sequential GUID generator as well for the same reason.
- On SQL Server, the base datatype of a Guid is actually a binary(16) (equivalent to Raw(16) on Oracle). But when the Guid value is marshalled into the binary, the bytes are re-ordered!
- You can uses sys_guid() as a default column so that it is automatically populated. CREATE TABLE guid_table (pky RAW(16) default sys_guid() PRIMARY KEY, NAME VARCHAR2(100));
- Using UUIDs in URLs is more secure. [4]
- A nice function to format the SYS_GUID() [3] :

CREATE OR REPLACE FUNCTION GET_FORMATTED_GUID RETURN VARCHAR2 IS guid VARCHAR2(38) ;
BEGIN
SELECT SYS_GUID() INTO guid FROM DUAL ;

guid :=
'{' || SUBSTR(guid,  1, 8) ||
'-' || SUBSTR(guid,  9, 4) ||
'-' || SUBSTR(guid, 13, 4) ||
'-' || SUBSTR(guid, 17, 4) ||
'-' || SUBSTR(guid, 21) || '}' ;

RETURN guid ;
END GET_FORMATTED_GUID ;
/
/*
CREATE TABLE "TEST_GUID_FORMATTED"
(  "GUID_FORMATTED" CHAR(36),
"NAME" NVARCHAR2(50),
CONSTRAINT "PK_GUID_FORMATTED" PRIMARY KEY ("GUID_FORMATTED"
)</code>

truncate table test_guid_formatted;
commit;
*/

declare
stopwatch date;
begin
stopwatch := sysdate;
for counter in 1..1000000 loop
insert into test_guid_formatted (guid_formatted, name)
values (get_formatted_guid, 'test: ' || to_char(counter));
end loop;
dbms_output.put_line(to_char(sysdate - stopwatch));
commit;
end;

Oracle Tip: The decimal marker to a dot, and the thousands marker to a comma in to_number().

November 17, 2009 by Reboot · Leave a Comment 

to_number(t.yournumbercolumn,'9G999G999D99','NLS_NUMERIC_CHARACTERS='',.''')

See also:

Oracle NLS_NUMERIC_CHARACTERS
http://download.oracle.com/docs/cd/B28359_01/olap.111/b28126/dml_options072.htm

Create a custom Oracle aggregate function that accepts multiple parameters through parameter encapsulation!

November 4, 2009 by Reboot · Leave a Comment 

Why would you want a feature like this?

Scenarios:
- You want to group by but treat a specific value to overrule no matter what else is specified it would look like:

select id, strpref(string_prefered_pars_type(status, status, ‘active’)) from tablename group by id;
(prefer the ‘active’ value above all else)

- The value has a dependency on another column which looks like:

select id, strpref(string_prefered_pars_type(return_column, pref_dependency_column, ‘active’)) from tablename group by id;
(prefer the value from a record which has its pref_dependency_column set to ‘active’)

Naturally with some code changes it enables all kind of fun aggregation features!

Everything below the line is Oracle PL/SQL example code which demonstrates how a custom aggregate function can be created which accepts multiple parameters by encapsulating the parameters in a custom type.

/*
quote:
There is no support for writing custom aggregate functions that accept multiple parameters.

source:
Build Custom Aggregate Functions
By Jonathan Gennick
http://www.oracle.com/technology/oramag/oracle/06-jul/o46sql.html

This example uses a custom type to use a custom aggregate function that accepts multiple parameters through parameter encapsulation!

more references:

Oracle® Database Data Cartridge Developer's Guide, 10g Release 2 (10.2)
11 User-Defined Aggregate Functions
http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96595/dci11agg.htm
*/

create or replace type STRING_PREFERED_PARS_TYPE as object
(
-- Author  : O. Lissenberg
-- Created : 4-11-2009
-- Purpose : Passes parameters to the STRING_PREFERED_TYPE's ODCIAggregateIterate function

-- Attributes
strvalue varchar2(100),
pref varchar2(10),
prefvalue varchar2(10)

-- Member functions and procedures
-- N.a.
)
/
create or replace type string_prefered_type as object
(
retvalue varchar2(4000),

static function ODCIAggregateInitialize(sctx IN OUT string_prefered_type) return number,
member function ODCIAggregateIterate(self IN OUT string_prefered_type, value IN STRING_PREFERED_PARS_TYPE) return number,
member function ODCIAggregateTerminate(self IN string_prefered_type, returnValue OUT varchar2, flags IN number) return number,
member function ODCIAggregateMerge(self IN OUT string_prefered_type, ctx2 IN string_prefered_type) return number
);
/
create or replace type body string_prefered_type is
static function ODCIAggregateInitialize(sctx IN OUT string_prefered_type)
return number is
begin
sctx := string_prefered_type(null);
return ODCIConst.Success;
end;

member function ODCIAggregateIterate(self IN OUT string_prefered_type, value IN STRING_PREFERED_PARS_TYPE)
return number is
begin

IF self.retvalue is null THEN
self.retvalue := value.strvalue;
ELSIF value.pref is not null AND lower(value.pref) = lower(value.prefvalue) THEN
-- only change the return value if the prefered value is found
-- hence otherwise the behavior is "the first non null value is accepted and does not change", which
-- might be nice to change into a max() or min() feature.
self.retvalue := value.strvalue;
END IF;

return ODCIConst.Success;
end;

member function ODCIAggregateTerminate(self IN string_prefered_type, returnValue OUT varchar2, flags IN number)
return number is
begin
-- just return the set value.
returnValue := self.retvalue;
return ODCIConst.Success;
end;

member function ODCIAggregateMerge(self IN OUT string_prefered_type, ctx2 IN string_prefered_type)
return number is
begin
-- this might prove to be difficult, it's easier to disable PARALLEL execution
-- to enable though, a state needs to be added to enable the merge, the state
-- would flag if the current or other context value was set with a "prefered" value.

return ODCIConst.Success;
end;
end;
/
CREATE or replace
FUNCTION strpref(input STRING_PREFERED_PARS_TYPE)
RETURN varchar2
AGGREGATE USING string_prefered_type;
-- PARALLEL_ENABLE (to enable: implement the merge function)
/
select t.id ,strpref(STRING_PREFERED_PARS_TYPE(t.name, t.pref, 'pickme'))
from testgroupby t group by t.id;

/*
CREATE TABLE "TESTGROUPBY"
(  "ID" NUMBER,
"NAME" NVARCHAR2(10),
"PREF" NVARCHAR2(10) );

insert into TESTGROUPBY (id,name,pref) values (1,'test1','ignoreme');
insert into TESTGROUPBY (id,name,pref) values (1,'test2','pickme');
insert into TESTGROUPBY (id,name,pref) values (1,'test3','ignoreme');
insert into TESTGROUPBY (id,name,pref) values (2,'test4','pickme');
insert into TESTGROUPBY (id,name,pref) values (2,'test5','pickme');
insert into TESTGROUPBY (id,name,pref) values (2,'test6','ignoreme');

select t.id ,strpref(STRING_PREFERED_PARS_TYPE(t.name, t.pref, 'pickme'))
from testgroupby t group by t.id;

drop table TESTGROUPBY;
*/

JQuery Plugin Tip : LiveQuery!

September 25, 2009 by Reboot · Leave a Comment 

http://docs.jquery.com/Plugins/livequery

Code examples will follow shortly ;-D

Fetch Oracle NLS Settings, Install Oracle Full Client in Zend Server.

September 21, 2009 by Reboot · 1 Comment 

Note that these results were not the ones I’d hoped for, the result was the installation of the full Oracle Instant client in PHP instead of the light version.

SELECT * FROM NLS_DATABASE_PARAMETERS;

PARAMETER VALUE
1 NLS_LANGUAGE AMERICAN
2 NLS_TERRITORY AMERICA
3 NLS_CURRENCY $
4 NLS_ISO_CURRENCY AMERICA
5 NLS_NUMERIC_CHARACTERS .,
6 NLS_CHARACTERSET WE8ISO8859P1
7 NLS_CALENDAR GREGORIAN
8 NLS_DATE_FORMAT DD-MON-RR
9 NLS_DATE_LANGUAGE AMERICAN
10 NLS_SORT BINARY
11 NLS_TIME_FORMAT HH.MI.SSXFF AM
12 NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
13 NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
14 NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
15 NLS_DUAL_CURRENCY $
16 NLS_COMP BINARY
17 NLS_LENGTH_SEMANTICS BYTE
18 NLS_NCHAR_CONV_EXCP FALSE
19 NLS_NCHAR_CHARACTERSET AL16UTF16
20 NLS_RDBMS_VERSION 9.2.0.7.0

To replace the light with the full client in Zend Server, put the “oraociei11.dll” (full) into the __ZendServerInstallPath__\ZendServer\bin directory and remove or rename the “oraociicus11.dll” (light). These libraries can be found in oracle client installation.

For a Linux environment it might be required to set the following environment variables:

export NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
export DNLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
export LC_ALL=AMERICAN_AMERICA.WE8ISO8859P1

In Windows it might be necessary to set the registry entry:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\NLS_LANG = DUTCH_THE NETHERLANDS.WE8MSWIN1252
(or HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\KEY_OraClient10g_home\NLS_LANG)

to

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\NLS_LANG = AMERICAN_AMERICA.WE8ISO8859P1

Zend Code Generator on Google Code

September 17, 2009 by Reboot · 4 Comments 

I started a project to create a zend code generator. It’s a pretty basic 3 layer model that it generates right now, tests included. Take a look at http://code.google.com/p/zend-code-generator/

Quick and Dirty RegEx Tester in Zend Framework.

August 19, 2009 by Reboot · Leave a Comment 

1 public function indexAction()
2 {
3 Zend_Layout::startMvc();
4 self::getFrontController ()->setParam ( “noViewRenderer”, true );
5
6 $subject = $this->_getParam(”subject”,”");
7 $pattern = $this->_getParam(”pattern”,”//”);
8 $result = preg_match_all($pattern, $subject, $matches);
9
10 $form = new Zend_Form();
11 $subjectElement = new Zend_Form_Element_Text(”subject”);
12 $subjectElement->setValue($subject);
13 $form->addElement($subjectElement);
14
15 $patternElement = new Zend_Form_Element_Text(”pattern”);
16 $patternElement->setValue($pattern);
17 $form->addElement($patternElement);
18
19 $form->addElement(”submit”,”send”);
20
21 echo $form;
22 echo Zend_Json::encode($matches);
23 }

Thanks for the html conversion of this code:
http://www.phpdebutant.com

Regex Tutorial/Reference:
http://www.phpro.org/tutorials/Introduction-to-PHP-Regex.html

Google Favicon PHP Proxy.

July 9, 2009 by Reboot · Leave a Comment 

A little code snippet to fetch and cache favicons via the google s2 favicon service.
It uses the PHP Zend framework to store and retrieve the favicons from a (MySQL) database …

http://ingol.nl/code/FaviconProxy.htm

Exploring jQuery Grids

April 21, 2009 by Reboot · Leave a Comment 

Grids:
FlexiGrid
jqGrid

Next Page »