Home » RADICORE » How To » LIST2 Pattern Problem
|
|
|
|
|
|
Re: LINK2 Pattern Problem [message #2126 is a reply to message #2125] |
Thu, 18 June 2009 09:36   |
AJM
Messages: 2382 Registered: April 2006 Location: Surrey, UK
|
Senior Member |
|
|
Ever since you brought this problem with the Oracle database to my attention via private email I have been seeking a proper solution. After playing around with tasks which use either the GROUP BY or HAVING clause I have made changes to the 'dml.oracle.php4/5.class.inc' files so that they can construct valid SQL statements using the information provided.
The problem is that each database vendor uses a different interpretation of the SQL standard, so what works in MySQL may not work in Oracle.
Take, for example, the GROUP BY clause. Oracle insists that every column in the SELECT list is also in the GROUP BY clause whereas MySQL is less strict. Although the Oracle implemetation was true in the SQL standard of 1991 this was changed in 1999 so that any column in the GROUP BY clause which is functionally dependent on another column in the GROUP BY clause does *NOT* have to be included. According to relational theory any non-key column on a table is functionally dependent on the primary key of that table, so if the GROUP BY clause contains the primary key then any non-key columns do not have to be specified.
The HAVING clause is used when the result set needs to be filtered by an aggregated column. This cannot be referenced in the WHERE clause as this is used before the results of the aggregation are known, so it has to be moved to the HAVING clause. MySQL is intelligent in that where the SELECT list contains an entry such as '<expression> AS aliasname' (where <expression> is an aggregation, a function or a subquery) it will allow the HAVING clause to reference that entry by 'aliasname' instead of '<expression>'. This is intelligent because it prevents <expression> from having to be defined and evaluated again. Oracle, on the other hand, is not so intelligent. You cannot use 'aliasname' in the HAVING clause, it has to be '<expression>', but ONLY if it is an aggregation, and not a function or a subquery. The only way around this is to put the SQL statement (without the HAVING clause) in a subquery, then enclose this in an outer query with the HAVING clause switched to the WHERE clause.
The attached file contains updates which work in MySQL, and the 'dml.oracle.php4/5.class.inc' file will automaically make changes to the GROUP BY and HAVING clauses which are required for Oracle.
This means that any changes which you made to either 'dict_table.class.inc' or 'std.table.class.inc' can be reversed out as they are no longer needed.
Try it out and let me know how you get on.
|
|
|
Re: LINK2 Pattern Problem [message #2127 is a reply to message #2120] |
Thu, 18 June 2009 09:40   |
ajwid01
Messages: 26 Registered: June 2009 Location: UK
|
Junior Member |
|
|
Hmm,
Now I seem to be encountering a new problem.
The LIST2 works fine, having successfully inserted the additional navigation button into the LIST1 form for the parent record(s).
However, the associated child records are not being correctly selected. Every entry from the child table is being returned into the child frame.
Now, initially I thought this would be due to the requirement to ammend the $where string, as the parent PK field is named differently from the child PK field.
I went through the process of trying to trap this, with the use of the recommended additional class function under "Associations" documentation (from an earlier thread).
This still didn't seem to work.
I looked at making the PK/FK field names match, but this wouldn't work either, and I started to run into some 'ambiguous' column errors on SQL selects, so reverted back to different names again.
I have now switched on the SQL Logging for the form, and the output is this:
ALTER SESSION SET CURRENT_SCHEMA = "WAREHOUSE"
SELECT count(*) FROM olap_delivery_data3 WHERE olap_delivery_data3.seq_number='138376' =>Count=1
select * from ( select a.*, rownum as rnum from ( SELECT olap_delivery_data3.* FROM olap_delivery_data3 WHERE olap_delivery_data3.seq_number='138376' ) a where rownum <= 1 ) where rnum >= 1=>Count=1
ALTER SESSION SET CURRENT_SCHEMA = "WAREHOUSE"
ALTER SESSION SET CURRENT_SCHEMA = "WAREHOUSE"
SELECT count(*) FROM olap_delivery_notes3 LEFT JOIN olap_delivery_data3 ON (olap_delivery_data3.seq_number=olap_delivery_notes3.delivery_data_seq) =>Count=2076
select * from ( select a.*, rownum as rnum from ( SELECT olap_delivery_notes3.*, olap_delivery_data3.seq_number FROM olap_delivery_notes3 LEFT JOIN olap_delivery_data3 ON (olap_delivery_data3.seq_number=olap_delivery_notes3.delivery_data_seq) ) a where rownum <= 25 ) where rnum >= 1=>Count=2076
ALTER SESSION SET CURRENT_SCHEMA = "MENU"
SELECT role_id,global_access FROM mnu_role WHERE role_id='GLOBAL' ORDER BY role_id =>Count=1
ALTER SESSION SET CURRENT_SCHEMA = "MENU"
SELECT x.task_id, x.script_id, x.pattern_id, mnu_nav_button.button_text, mnu_nav_button.context_preselect FROM mnu_nav_button LEFT JOIN mnu_task ON (mnu_task.task_id = mnu_nav_button.task_id_snr) LEFT JOIN mnu_task x ON (x.task_id = mnu_nav_button.task_id_jnr) WHERE mnu_task.task_id='mops_olap_delivery_notes3(list2)' AND (x.is_disabled='N') ORDER BY mnu_nav_button.sort_seq =>Count=6
I understand that a where clause should be passed through to the child query from the associated parent record, but there doesn't seem to be any 'where' clause parameter being set.
Do I have to configure this somewhere else?
T.
|
|
|
|
|
|
|
|
|
|
Re: LINK2 Pattern Problem [message #2135 is a reply to message #2120] |
Thu, 18 June 2009 11:01   |
ajwid01
Messages: 26 Registered: June 2009 Location: UK
|
Junior Member |
|
|
The outer table is OLAP_DELIVERY_DATA3, it has a PK of SEQ_NUMBER. Historically, when I failed to properly specify the PK, I couldn't select any row to READ/UPDATE, and I am assuming it would similarly fail to propagate through to the LIST2 task.
The inner table is OLAP_DELIVERY_NOTES3, it has a PK of NOTE_SEQ, and a foreign key field of DELIVERY_DATA_SEQ, which maps to the parent.SEQ_NUMBER.
This parent/child relationship is mapped on that field, as a RESTRICTED relationship.
Within the header form on the LIST2 output, the parent record is displayed along with it's PK field (SEQ_NUMBER), but there does not appear to be any WHERE clause being passed down to the child record retrieval process.
So, still a bit stumped really. Something seems to be amiss in the population of a where clause, but I can't figure out what it might be; what underpins it that is missing.
|
|
|
|
Re: LINK2 Pattern Problem [message #2137 is a reply to message #2120] |
Thu, 18 June 2009 12:02   |
ajwid01
Messages: 26 Registered: June 2009 Location: UK
|
Junior Member |
|
|
Tony,
I'm going to wait until tomorrow, when I can implement the changed code you have sent through to the installation, and just double-check that nothing I have done (and failed to UNDO properly) in the code is causing issues.
I just started to look at a fresh install, and came across an anomaly on the MNU_TASK_FIELD table inserts.
Table is defined as:
Name Null? Type
------------------------- -------- ----------------------------
TASK_ID NOT NULL VARCHAR2(80 CHAR)
FIELD_ID NOT NULL VARCHAR2(40 CHAR)
CREATED_DATE NOT NULL TIMESTAMP(6)
CREATED_USER NOT NULL VARCHAR2(16 CHAR)
FIELD_DESC VARCHAR2(255 CHAR)
REVISED_DATE TIMESTAMP(6)
REVISED_USER VARCHAR2(16 CHAR)
Inserts are attempted like:
INSERT INTO mnu_task_field VALUES('mnu_control(upd3)', 'DEFAULT_LANGUAGE', NULL, '2006-04-10 09:36:18', 'AJM', '2007-09-10 10:44:37', 'AJM')
*
ERROR at line 1:
ORA-12899: value too large for column "MENU"."MNU_TASK_FIELD"."CREATED_USER"
(actual: 19, maximum: 16)
So, looks like a field is being inserted 'out of order' with that expected by the table in this instance.
I spooled everything out to logfiles from SqlPlus initially, but obviously missed the odd error.
So, as per the above, I'll continue tomorrow with a fresh install from your newly-worked Oracle code elements, double-check that there aren't some other errors creeping in along the way, and then at least I'll be debugging from a "clean" install position.
Hopefully I'll end up with a good ending to the week, come close of play tomorrow.
Failing that, I'll have time to mull some things over whilst traipsing down to Heathrow and back tomorrow evening.
T.
[Updated on: Thu, 18 June 2009 12:03] Report message to a moderator
|
|
|
|
|
|
Re: LIST2 Pattern Problem [message #2141 is a reply to message #2120] |
Fri, 19 June 2009 09:58   |
ajwid01
Messages: 26 Registered: June 2009 Location: UK
|
Junior Member |
|
|
I'll park the primary key problem for right now, until I can properly debug it.
I did have the query pasted in notepad for you, until a scheduled update rebooted my PC (when apparently it shouldn't have), and I lost it.
Will be easy enough to recreate. I'll put back the original query, let it error and then post you the results.
Roughly, from what I recall it's:
I think the HAVING clause (count(dict_table.table_id {?}) gets converted to a WHERE clause, but when it gets re-written by Oracle in the separate oracle php class, it's no longer a COUNT(), as the outer SELECT has converted it to a designated column id from the inner select's alias.
[ Hope that makes sense. ]
And I think Oracle is still griping about the inner select's in-line query not being in the 'group by'.
[ This is the bit that I rewrote as a function call, to avoid the in-line query and so allow a group by on it. ]
This is my modified section from the db_table.class.inc:
if ($item == 'table_id') {
// get data from the database, ignoring any tables which have no entries on DICT_COLUMN
$this->sql_select = 'dict_table.table_id, table_desc, count(dict_column.table_id) as column_count';
$this->sql_orderby = 'dict_table.table_id';
$this->sql_ordery_seq = 'asc';
$this->sql_from = 'dict_table '
. 'LEFT JOIN dict_column ON (dict_table.database_id=dict_column.database_id AND dict_table.table_id=dict_column.table_id) ';
$this->sql_having = 'column_count > 0';
$this->sql_groupby = 'dict_table.table_id, table_desc,AJW_RAD_GET_REL_TABLE_COUNT(DICT_TABLE.DATABASE_ID, DICT_TABLE.TABLE_ID) ';
$data = $this->getData($where);
// convert each row into 'id=id' in the output array
foreach ($data as $row => $rowdata) {
$rowvalues = array_values($rowdata);
$array[$rowvalues[0]] = $rowvalues[0];
} // foreach
return $array;
} // if
The main bits are the function call for REL_COUNT, and the changing of the HAVING clause away from the count. I think yours USED to be like this, before avoiding the aliased column that Oracle didn't like.
But now, by the time it gets converted from HAVING to WHERE to the Oracle specific PHP class, it can reference the column directly again.
The simple (rough and ready) code for the REL_COUNT replacement was just:
CREATE OR REPLACE FUNCTION AJW_RAD_GET_REL_TABLE_COUNT(IN_DB VARCHAR2, IN_TAB VARCHAR2) RETURN NUMBER
IS
V_RETURN NUMBER;
BEGIN
BEGIN
SELECT COUNT(*)
INTO V_RETURN
FROM DICT_RELATIONSHIP
WHERE
DATABASE_ID_SNR = IN_DB AND
TABLE_ID_SNR = IN_TAB;
EXCEPTION
WHEN OTHERS
THEN
RETURN 0;
END;
RETURN V_RETURN;
END;
/
I think that kinda works.
Don't think I changed anything else.
|
|
|
|
Re: LIST2 Pattern Problem [message #2144 is a reply to message #2120] |
Mon, 22 June 2009 09:30   |
ajwid01
Messages: 26 Registered: June 2009 Location: UK
|
Junior Member |
|
|
Hi Tony,
Apologies, I misread and thought it was only the oracle php classes that had changed, so didn't extract anything additional.
Admittedly, now invoking your new ammendments to the dict table class resolves all earlier problems.
Regarding the debugging... I still don't have that installed and configured. Am hoping to get to that later today.
In the interim though, I thought I would give you this additional piece of information I have discovered. [ Never know, it might help...]
Originally, I had a 2 field composite PK on the Outer/Parent table but for simplicity converted this to a sequence-based numeric primary key.
When using this in the List2/Multi4 tasks, the where clause against the Inner table ends up null.
However, I reverted back to the 2-field composite key reference this morning and found it PARTIALLY worked!
I ended up with an Inner table 'where' clause based on the leading field in the primary key, which was a massive difference from where I was at before... but as you will appreciate, still brings me back unrelated records from the missing additional composite field.
I figured mentioning this here might allow something to "click" for you, if not entirely backed up with a debug output just yet.
Certainly something is being processed for the pkeynames array, but not quite how it should.
Hopefully will get back to you more fully later, if I can get some debugging working properly.
T.
|
|
|
|
|
|
Re: LIST2 Pattern Problem [message #2148 is a reply to message #2120] |
Mon, 22 June 2009 11:35   |
ajwid01
Messages: 26 Registered: June 2009 Location: UK
|
Junior Member |
|
|

This is exactly what I tried to follow previously.
I think what maybe sidetracked me, is I was maybe expecting to at least SEE a where clause in the generated SQL, but that it would likely generate an error when parsed - to suggest that the column_name in the where clause was invalid.
In actual fact, for a reason I'm not following right now, the 'where' clause just doesn't get to the parse stage, as presumably some code logic recognises it as being an 'invalid' column prior to that.
If I'd seen a parse error, I would have known what was happening and then looked to see where I needed to tranlate it.
As I didn't see a parse error, I wasn't sure, and presumed there was something going wrong somewhere else.

I've attempted, as per someone else's suggestion, that a call to _cm_pre_getData should be placed within the inner table's class file like:
require_once 'std.table.class.inc';
class olap_delivery_notes3 extends Default_Table
{
// ****************************************************************************
function olap_delivery_notes3 ()
{
// save directory name of current script
$this->dirname = dirname(__file__);
$this->dbms_engine = $GLOBALS['dbms'];
$this->dbname = 'warehouse';
$this->tablename = 'olap_delivery_notes3';
// call this method to get original field specifications
// (note that they may be modified at runtime)
$this->fieldspec = $this->getFieldSpec_original();
} // olap_delivery_notes3
function _cm_pre_getData ($where, $where_array, $fieldarray=null){
$where = str_replace('line_no=', 'order_line_no=', $where);
return $where;
}
// ****************************************************************************
} // end class
// ****************************************************************************
This doesn't seem to work for me though. The additional field still isn't picked up.
I'm presuming I just don't know how to write this bit of code, or where exactly to put it!
Hmm!
|
|
|
|
|
Goto Forum:
Current Time: Thu Jun 19 04:12:49 EDT 2025
Total time taken to generate the page: 0.18588 seconds
|