I've run into a puzzle trying to formulate a query. I initially did a
direct port of a query from our old WebObjects apps, but the SQL it
generated was a surprise and didn't fetch the right set of records.
We have a TradeSource entity with a db column TradeStatus_ID which
relates to a read-only TradeStatus table. In other words, a
non-mandatory 1:1 relationship TradeSource -> TradeStatus. Let's say I
want to fetch all TradeSources with either a null tradeStatus OR a
tradeStatus having one of several primary-key values. (Legacy values
that are meaningful to our users.)
I didn't want to expose the TradeStatus_ID foreign key in the
TradeSource entity, but I figured there's no harm in exposing the
primary key of the read-only TradeStatus table. That attribute is named
"oid". My first attempt was:
Expression statusNullExp = ExpressionFactory.
matchExp("tradeStatus", null);
String[] types = { "FX", "CB", "TE", "LM", "TC", "U", "ES" };
Expression statusValuesExp = ExpressionFactory.
inExp("tradeStatus.oid", types);
Expression statusExp = statusNullExp.orExp(statusValuesExp);
SelectQuery query = new SelectQuery("TradeSource", statusExp);
List tradeSources = dc.performQuery(query);
It generated this SQL:
SELECT * FROM TRADESOURCE t0, LKPTRADESTATUS t1 WHERE
t0.TRADESTATUS_ID = t1.TRADESTATUS_ID AND
((RTRIM(t0.TRADESTATUS_ID) IS NULL)
OR (RTRIM(t1.TRADESTATUS_ID) IN ('FX', 'CB', 'TE', 'LM', 'TC', 'U', 'ES')))
That fetches too few records. What I expected was:
SELECT * FROM TRADESOURCE t0, LKPTRADESTATUS t1 WHERE
((RTRIM(t0.TRADESTATUS_ID) IS NULL)
OR (RTRIM(t0.TRADESTATUS_ID) IN ('FX', 'CB', 'TE', 'LM', 'TC', 'U', 'ES')))
That is, the same SQL with no reference to the second table.
The extra qualifier "TRADESTATUS_ID = t1.TRADESTATUS_ID" required a
related record to exist, defeating the effect of "TRADESTATUS_ID IS NULL".
Now, I can work around it by exposing the TradeStatus_ID foreign key in
the TradeSource table, but that feels like a hack. Another way would be
to use the db: attribute in the IN expression, that is, replacing:
ExpressionFactory.inExp("tradeStatus.oid", types);
with:
Expression.fromString("db:TRADESTATUS_ID in
('FX','CB','TE','LM','TC','U','ES')");
Both ways work, but it seems odd that one should have to think about
such things. Maybe I'm missing something.
This archive was generated by hypermail 2.0.0 : Fri Oct 29 2004 - 18:53:15 EDT