From: Frank Swarbrick on
First of all I want to acknowledge that I do not believe that the following
should have been done in the first place. And perhaps I can influence those
on the project to realize what a bad idea it was to go this direction. That
being said, I wonder if this issue can be addressed without changing the
database design...

We have a "maintenance" database where we store fairly generic maintenance
records. By maintenance I refer to the action of changing a column in a
table and storing the old value and the new value in this separate
maintenance table. This table is then used to report on changes that have
been made to various tables. So a report may look something like this:

ACCOUNT NUMBER FIELD DESCR OLD VALUE NEW VALUE
123456789 OPEN DATE 10/29/2009 9/17/2008

Depending on what FIELD DESCR is (and of course FIELD DESCR stored as a code
in the database) OLD_VALUE and NEW_VALUE may hold integers, monetary values,
dates, freeform text, etc.

In and of itself I don't believe this to be a bad idea. But I'm sure I'll
here from someone if it is.

The problem I'm dealing with is someone seems to have "co-opted" this
"maintenance table" for something that I'm not sure it should be used for.
Then again I don't (yet) know much about the project. All I know is that a
programmer has written the following query:

SELECT NEW_VALUE
FROM MAINT.MAINT_IDS M2
JOIN MAINT.MAINT_ACTIONS M3
ON M2.MASTER_ID = M3.MASTER_ID
JOIN MAINT.MAINT_ACTION_DETAILS M4
ON M3.ACTION_ID = M4.ACTION_ID
WHERE ID_TYPE_CODE = 'CIF'
AND ID_AFFECTED = ?
AND MAINT_TYPE_CODE = 'SARFILING'
AND FIELD_CODE = 'DATE'
AND DATE(NEW_VALUE) <= CURRENT DATE - 1 DAYS
AND DATE(NEW_VALUE) >= CURRENT DATE - 90 DAYS
FETCH FIRST 1 ROW ONLY


I believe his goal is to get SQLCODE = 0 if there is at least one result and
SQLCODE = 100 if there is not. (He's gone home for the day and I'm being
impatient which is why I am missing some possibly relevent information.)

Anyway, depending on which ID_AFFECTED parameter we are querying on we may
get a result or we may get the following error:
SQL0180N The syntax of the string representation of a datetime value is
incorrect. SQLSTATE=22007

After some research I have found that there are cases where even though
FIELD_CODE = 'DATE', the value in NEW_VALUE is not a valid date.
Specifically one has '8/20/209' when it obviously should have '8/20/2009'.

I have no idea *where* this data came from. Obviously it needs some "data
validation" done to it before being dumped in to this database. Still, I am
curious if there is anything in my query that could be done in order to,
umm, not get this error? Maybe that's not even what I should be doing,
but... I'm kind of thinking of something similar to how COALESCE deals with
nulls by returning something a different value. So here maybe the invalid
date could be somehow converted to a valid date, like perhaps CURRENT DATE?

I dunno. Probably there's no point in even worrying about it; we should fix
the data. And I have to think that's where we'll end up. Still, having
this may actually help us find the bad data. How could I do a query that
returns be all cases where NEW_VALUE is not a valid date?

I guess I should ask the question I don't want to ask... Based on what I've
explained so far (and feel free to ask for more details), is this an example
of the dreaded "Entity Attribute Value" database? And is it a bad thing in
this case? I had a big part in designing this database, but I felt at the
time that it was the appropriate way to go. And honestly I still feel that
way. It's generic enough to be flexible for many types of "maintenance
reports" yet specific enough to not just be a "data dump" type of database.

Perhaps I should show you what the various tables are...

CREATE TABLE MAINT_TYPES (
CODE VARCHAR(10) NOT NULL,
ADD_CHG_DELETE CHAR(1) NOT NULL,
DESCRIPTION VARCHAR(25) NOT NULL,
SHORT_NAME VARCHAR(25),
VERIFY_REQ_YN CHAR(1) DEFAULT 'Y' NOT NULL
);
ALTER TABLE MAINT_TYPES
ADD CONSTRAINT MAINT_TYPES_PK PRIMARY KEY (CODE, ADD_CHG_DELETE);
ALTER TABLE MAINT_TYPES
ADD CONSTRAINT MAINT_TYPES_CK1 CHECK (MAINT.MAINT_TYPES.ADD_CHG_DELETE
in ('A','C','D'));
ALTER TABLE MAINT_TYPES
ADD CONSTRAINT MAINT_TYPES_CK2 CHECK (MAINT.MAINT_TYPES.VERIFY_REQ_YN in
('Y','N'));

CREATE TABLE MAINT_ID_TYPE (
CODE VARCHAR(10) NOT NULL,
DESCRIPTION VARCHAR(25) NOT NULL,
SHORT_NAME VARCHAR(25)
) ;
ALTER TABLE MAINT_ID_TYPE
ADD CONSTRAINT MAINT_ID_TYPE_PK PRIMARY KEY (CODE);

CREATE TABLE MAINT_IDS (
MASTER_ID DECIMAL(12) NOT NULL,
ID_TYPE_CODE VARCHAR(10) NOT NULL,
ID_AFFECTED VARCHAR(40) NOT NULL,
DESCRIPTION VARCHAR(50)
);
ALTER TABLE MAINT_IDS
ADD CONSTRAINT MAINT_ID_PK PRIMARY KEY (MASTER_ID, ID_TYPE_CODE);
ALTER TABLE MAINT_IDS
ADD CONSTRAINT MAINT_ID_FK2 FOREIGN KEY (ID_TYPE_CODE)
REFERENCES MAINT_ID_TYPE (CODE);

CREATE TABLE MAINT_ACTIONS (
ACTION_ID DECIMAL(12) NOT NULL GENERATED ALWAYS AS IDENTITY,
MASTER_ID DECIMAL(12) NOT NULL,
MAINT_TYPE_CODE VARCHAR(10) NOT NULL,
ADD_CHG_DELETE CHAR(1) NOT NULL
);
ALTER TABLE MAINT_ACTIONS
ADD CONSTRAINT MAINT_ACTIONS_PK PRIMARY KEY (ACTION_ID);
ALTER TABLE MAINT_ACTIONS
ADD CONSTRAINT MAINT_ACTIONS_FK2 FOREIGN KEY (MAINT_TYPE_CODE,
ADD_CHG_DELETE)
REFERENCES MAINT_TYPES (CODE, ADD_CHG_DELETE);

CREATE TABLE MAINT_ACTION_DETAILS (
DETAIL_ID DECIMAL(12) NOT NULL GENERATED ALWAYS AS IDENTITY,
ACTION_ID DECIMAL(12) NOT NULL,
FIELD_CODE VARCHAR(10) NOT NULL,
OLD_VALUE VARCHAR(200),
NEW_VALUE VARCHAR(200)
);
ALTER TABLE MAINT_ACTION_DETAILS
ADD CONSTRAINT MAINT_ACTION_DETAILS_PK PRIMARY KEY (DETAIL_ID);
ALTER TABLE MAINT_ACTION_DETAILS
ADD CONSTRAINT MAINT_ACTION_DETAILS_FK1 FOREIGN KEY (ACTION_ID)
REFERENCES MAINT_ACTIONS (ACTION_ID);
ALTER TABLE MAINT_ACTION_DETAILS
ADD CONSTRAINT MAINT_ACTION_DETAILS_FK2 FOREIGN KEY (FIELD_CODE)
REFERENCES MAINT_FIELDS (CODE);

With some trepidation I wait for your opinion.

Thanks,
Frank

--

Frank Swarbrick
Applications Architect - Mainframe Applications Development
FirstBank Data Corporation - Lakewood, CO USA
P: 303-235-1403

From: Lennart on
On 8 Okt, 02:08, "Frank Swarbrick" <Frank.Swarbr...(a)efirstbank.com>
wrote:
> First of all I want to acknowledge that I do not believe that the following
> should have been done in the first place.  And perhaps I can influence those
> on the project to realize what a bad idea it was to go this direction.  That
> being said, I wonder if this issue can be addressed without changing the
> database design...
>
> We have a "maintenance" database where we store fairly generic maintenance
> records.  By maintenance I refer to the action of changing a column in a
> table and storing the old value and the new value in this separate
> maintenance table.  This table is then used to report on changes that have
> been made to various tables.  So a report may look something like this:
>
> ACCOUNT NUMBER  FIELD DESCR   OLD VALUE    NEW VALUE
>      123456789    OPEN DATE   10/29/2009   9/17/2008
>
> Depending on what FIELD DESCR is (and of course FIELD DESCR stored as a code
> in the database) OLD_VALUE and NEW_VALUE may hold integers, monetary values,
> dates, freeform text, etc.
>
> In and of itself I don't believe this to be a bad idea.  But I'm sure I'll
> here from someone if it is.
>
> The problem I'm dealing with is someone seems to have "co-opted" this
> "maintenance table" for something that I'm not sure it should be used for..
> Then again I don't (yet) know much about the project.  All I know is that a
> programmer has written the following query:
>
> SELECT NEW_VALUE                              
> FROM MAINT.MAINT_IDS M2                        
> JOIN MAINT.MAINT_ACTIONS M3                    
>      ON M2.MASTER_ID = M3.MASTER_ID                  
> JOIN MAINT.MAINT_ACTION_DETAILS M4            
>      ON M3.ACTION_ID = M4.ACTION_ID                  
> WHERE ID_TYPE_CODE = 'CIF'
>   AND ID_AFFECTED = ?
>   AND MAINT_TYPE_CODE = 'SARFILING'
>   AND FIELD_CODE = 'DATE'
>   AND DATE(NEW_VALUE) <= CURRENT DATE - 1 DAYS
>   AND DATE(NEW_VALUE) >= CURRENT DATE - 90 DAYS    
> FETCH FIRST 1 ROW ONLY        
>

One thing that strikes me is, what happens if db2 decides to evaluate
DATE(NEW_VALUE) <= CURRENT DATE - 1 DAYS before FIELD_CODE = 'DATE'?
Won't you (or rather the missing developer) run into situations like:

DATE('This for sure is not a valid date') <= CURRENT DATE - 1
DAYS


/Lennart
From: Frank Swarbrick on

--

Frank Swarbrick
Applications Architect - Mainframe Applications Development
FirstBank Data Corporation - Lakewood, CO USA
P: 303-235-1403


n 10/8/2009 at 4:05 AM, in message
<49272539-a5cc-49ce-8550-d3177da96f5d(a)s6g2000vbp.googlegroups.com>,
Lennart<erik.lennart.jonsson(a)gmail.com> wrote:
> On 8 Okt, 02:08, "Frank Swarbrick" <Frank.Swarbr...(a)efirstbank.com>
> wrote:
>> First of all I want to acknowledge that I do not believe that the
> following
>> should have been done in the first place. And perhaps I can influence
> those
>> on the project to realize what a bad idea it was to go this direction.
> That
>> being said, I wonder if this issue can be addressed without changing the
>> database design...
>>
>> We have a "maintenance" database where we store fairly generic
> maintenance
>> records. By maintenance I refer to the action of changing a column in a
>> table and storing the old value and the new value in this separate
>> maintenance table. This table is then used to report on changes that
> have
>> been made to various tables. So a report may look something like this:
>>
>> ACCOUNT NUMBER FIELD DESCR OLD VALUE NEW VALUE
>> 123456789 OPEN DATE 10/29/2009 9/17/2008
>>
>> Depending on what FIELD DESCR is (and of course FIELD DESCR stored as a
> code
>> in the database) OLD_VALUE and NEW_VALUE may hold integers, monetary
> values,
>> dates, freeform text, etc.
>>
>> In and of itself I don't believe this to be a bad idea. But I'm sure
> I'll
>> here from someone if it is.
>>
>> The problem I'm dealing with is someone seems to have "co-opted" this
>> "maintenance table" for something that I'm not sure it should be used
> for.
>> Then again I don't (yet) know much about the project. All I know is
> that a
>> programmer has written the following query:
>>
>> SELECT NEW_VALUE
>> FROM MAINT.MAINT_IDS M2
>> JOIN MAINT.MAINT_ACTIONS M3
>> ON M2.MASTER_ID = M3.MASTER_ID
>> JOIN MAINT.MAINT_ACTION_DETAILS M4
>> ON M3.ACTION_ID = M4.ACTION_ID
>> WHERE ID_TYPE_CODE = 'CIF'
>> AND ID_AFFECTED = ?
>> AND MAINT_TYPE_CODE = 'SARFILING'
>> AND FIELD_CODE = 'DATE'
>> AND DATE(NEW_VALUE) <= CURRENT DATE - 1 DAYS
>> AND DATE(NEW_VALUE) >= CURRENT DATE - 90 DAYS
>> FETCH FIRST 1 ROW ONLY
>>
>
> One thing that strikes me is, what happens if db2 decides to evaluate
> DATE(NEW_VALUE) <= CURRENT DATE - 1 DAYS before FIELD_CODE = 'DATE'?
> Won't you (or rather the missing developer) run into situations like:
>
> DATE('This for sure is not a valid date') <= CURRENT DATE - 1
> DAYS

Can that occur? In Cobol that would never occur because terms are evaluated
in order and short circuit once the predicate is determined to be false.

Frank

From: Lennart on
On 8 Okt, 17:07, "Frank Swarbrick" <Frank.Swarbr...(a)efirstbank.com>
wrote:
> --
>
> Frank Swarbrick
> Applications Architect - Mainframe Applications Development
> FirstBank Data Corporation - Lakewood, CO  USA
> P: 303-235-1403
>
> n 10/8/2009 at 4:05 AM, in message
> <49272539-a5cc-49ce-8550-d3177da96...(a)s6g2000vbp.googlegroups.com>,
>
>
>
> Lennart<erik.lennart.jons...(a)gmail.com> wrote:
> > On 8 Okt, 02:08, "Frank Swarbrick" <Frank.Swarbr...(a)efirstbank.com>
> > wrote:
> >> First of all I want to acknowledge that I do not believe that the
> > following
> >> should have been done in the first place.  And perhaps I can influence
> > those
> >> on the project to realize what a bad idea it was to go this direction.  
> > That
> >> being said, I wonder if this issue can be addressed without changing the
> >> database design...
>
> >> We have a "maintenance" database where we store fairly generic
> > maintenance
> >> records.  By maintenance I refer to the action of changing a column in a
> >> table and storing the old value and the new value in this separate
> >> maintenance table.  This table is then used to report on changes that
> > have
> >> been made to various tables.  So a report may look something like this:
>
> >> ACCOUNT NUMBER  FIELD DESCR   OLD VALUE    NEW VALUE
> >>      123456789    OPEN DATE   10/29/2009   9/17/2008
>
> >> Depending on what FIELD DESCR is (and of course FIELD DESCR stored as a
> > code
> >> in the database) OLD_VALUE and NEW_VALUE may hold integers, monetary
> > values,
> >> dates, freeform text, etc.
>
> >> In and of itself I don't believe this to be a bad idea.  But I'm sure
> > I'll
> >> here from someone if it is.
>
> >> The problem I'm dealing with is someone seems to have "co-opted" this
> >> "maintenance table" for something that I'm not sure it should be used
> > for.
> >> Then again I don't (yet) know much about the project.  All I know is
> > that a
> >> programmer has written the following query:
>
> >> SELECT NEW_VALUE                              
> >> FROM MAINT.MAINT_IDS M2                        
> >> JOIN MAINT.MAINT_ACTIONS M3                    
> >>      ON M2.MASTER_ID = M3.MASTER_ID                  
> >> JOIN MAINT.MAINT_ACTION_DETAILS M4            
> >>      ON M3.ACTION_ID = M4.ACTION_ID                  
> >> WHERE ID_TYPE_CODE = 'CIF'
> >>   AND ID_AFFECTED = ?
> >>   AND MAINT_TYPE_CODE = 'SARFILING'
> >>   AND FIELD_CODE = 'DATE'
> >>   AND DATE(NEW_VALUE) <= CURRENT DATE - 1 DAYS
> >>   AND DATE(NEW_VALUE) >= CURRENT DATE - 90 DAYS    
> >> FETCH FIRST 1 ROW ONLY        
>
> > One thing that strikes me is, what happens if db2 decides to evaluate
> > DATE(NEW_VALUE) <= CURRENT DATE - 1 DAYS before FIELD_CODE = 'DATE'?
> > Won't you (or rather the missing developer) run into situations like:
>
> >        DATE('This for sure is not a valid date') <= CURRENT DATE - 1
> > DAYS
>
> Can that occur?  In Cobol that would never occur because terms are evaluated
> in order and short circuit once the predicate is determined to be false.
>

I realize by your signature that this is probably not db2 for LUW that
we are dealing with. I have no idea how db2 for other platforms works,
so this might not hold. The principle is that you tell the DBMS what
you want it to do, and the optimizer decides how that should be done,
amongst other things in what orde the predicates should be evaluated.
To conclude, yes it can happen (as mentioned, might not hold for your
platform).


/Lennart

From: --CELKO-- on
A trick I have is a look-up table with one column of type DATE, and
one or more columns of various date-as-string CHAR(n) columns. Build
a century with a spreadsheet and a text editor in 10 minutes or less.
OUTER JOIN to it and the bad strings are NULLs.