Case Sensitive query criteria

E

Ernie

I am using access 2k to select records from a 3rd party
database (through odbc). In several tables, the 3rd party
has used 2-character codes to define record types. Among
these codes are both upper and lower case characters each
representing different record types. E.G. (1A) is not
the same as (1a). In my query, I want to select only those
record types with uppercase codes (i.e. I want only the
(1A) codes, not the (1a)'s).
In my query criteria, I have this:

In ("1A","1B","1H","1O","1S")

but the query is pulling all of the lowercase codes as
well as those listed above.

I cannot find anything helpful in either Access Help or in
the various access books that I've been reading through.

How can I get my queries to select just uppercase when
looking for letter codes like the above?

Changing the table from the 3rd party is not an option.
 
J

John Vinson

How can I get my queries to select just uppercase when
looking for letter codes like the above?

With difficulty, if you need multiple criteria, especially if you need
to mix cases within an individual query!

If you are searching just one field you can use the StrComp() VBA
function to do a case-sensitive comparison:

WHERE [field] = "1A" AND StrComp([field], "1A", 0) = 0

The first clause will limit the number of records to be processed to
just 1a and 1A; the strComp criterion will restrict it to exact
matches.

How you would do this with an IN clause is not obvious to me!
 
D

Dirk Goldgar

Ernie said:
I am using access 2k to select records from a 3rd party
database (through odbc). In several tables, the 3rd party
has used 2-character codes to define record types. Among
these codes are both upper and lower case characters each
representing different record types. E.G. (1A) is not
the same as (1a). In my query, I want to select only those
record types with uppercase codes (i.e. I want only the
(1A) codes, not the (1a)'s).
In my query criteria, I have this:

In ("1A","1B","1H","1O","1S")

but the query is pulling all of the lowercase codes as
well as those listed above.

I cannot find anything helpful in either Access Help or in
the various access books that I've been reading through.

How can I get my queries to select just uppercase when
looking for letter codes like the above?

Changing the table from the 3rd party is not an option.

You can use the StrComp and InStr functions to force a case-sensitive
comparison. In the case you describe, where you want to see if a
particular code is in a list of codes, I'd use InStr with a bit of
trickery, like this:

SELECT * FROM CaseSensitiveTable
WHERE InStr(1,"/1A/1B/1H/1O/1S/","/" &
Code:
 & "/",0)=True;

That's based on the premise that the none of the codes will ever contain
the "/" character.  If they might, pick some other character as a list
delimiter, one that won't appear in the data.
 
D

Douglas J. Steele

John Vinson said:
How can I get my queries to select just uppercase when
looking for letter codes like the above?

With difficulty, if you need multiple criteria, especially if you need
to mix cases within an individual query!

If you are searching just one field you can use the StrComp() VBA
function to do a case-sensitive comparison:

WHERE [field] = "1A" AND StrComp([field], "1A", 0) = 0

The first clause will limit the number of records to be processed to
just 1a and 1A; the strComp criterion will restrict it to exact
matches.

How you would do this with an IN clause is not obvious to me!

In addition to Dirk's suggestion, I think you can use

WHERE [field ] IN ("1A","1B","1H","1O","1S")
AND StrComp(UCase([field]), [field], 0) = 0
 
J

John Vinson

You can use the StrComp and InStr functions to force a case-sensitive
comparison. In the case you describe, where you want to see if a
particular code is in a list of codes, I'd use InStr with a bit of
trickery, like this:

SELECT * FROM CaseSensitiveTable
WHERE InStr(1,"/1A/1B/1H/1O/1S/","/" &
Code:
 & "/",0)=True;[/QUOTE]

Dirk, you are a sneaky, clever guy! I LIKE that!

Unless the table is small, I'd still suggest combining this with the
IN clause to at least whittle down the number of times the InStr
function needs to be called. But it certainly solves the problem!
 
D

Dirk Goldgar

John Vinson said:
You can use the StrComp and InStr functions to force a case-sensitive
comparison. In the case you describe, where you want to see if a
particular code is in a list of codes, I'd use InStr with a bit of
trickery, like this:

SELECT * FROM CaseSensitiveTable
WHERE InStr(1,"/1A/1B/1H/1O/1S/","/" &
Code:
 & "/",0)=True;[/QUOTE]

Dirk, you are a sneaky, clever guy! I LIKE that![/QUOTE]

Why, thank you, John!  You honor me.
[QUOTE]
Unless the table is small, I'd still suggest combining this with the
IN clause to at least whittle down the number of times the InStr
function needs to be called. But it certainly solves the problem![/QUOTE]

I think you're right, and I wish I'd thought of it.  Assuming that
multiple, ANDed conditions in a WHERE clause are in fact evaluated
sequentially, and the second condition isn't evaluated if the first is
false, then I think putting the IN condition first and then checking for
binary equality, as you and Doug suggest, is bound to be much more
efficient.
 
E

Ernie

-----Original Message-----
You can use the StrComp and InStr functions to force a case-sensitive
comparison. In the case you describe, where you want to see if a
particular code is in a list of codes, I'd use InStr with a bit of
trickery, like this:

SELECT * FROM CaseSensitiveTable
WHERE InStr(1,"/1A/1B/1H/1O/1S/","/" &
Code:
[/QUOTE] & "/",0)=True;

Dirk, you are a sneaky, clever guy! I LIKE that![/QUOTE]

Why, thank you, John!  You honor me.
[QUOTE]
Unless the table is small, I'd still suggest combining this with the
IN clause to at least whittle down the number of times the InStr
function needs to be called. But it certainly solves[/QUOTE] the problem!

I think you're right, and I wish I'd thought of it. Assuming that
multiple, ANDed conditions in a WHERE clause are in fact evaluated
sequentially, and the second condition isn't evaluated if the first is
false, then I think putting the IN condition first and then checking for
binary equality, as you and Doug suggest, is bound to be much more
efficient.

--
Dirk Goldgar, MS Access MVP
www.datagnostics.com

(please reply to the newsgroup)


.[/QUOTE]
Thanks for your help. Unfortunately, the case sensitive
table that I am selecting from can have any printable
character (in the basic ascii character set) as part of
the code field (from ! to ~). Doug's solution below (in
the other reply thread) looks like it might work for me
though.
 
E

Ernie

-----Original Message-----

How can I get my queries to select just uppercase when
looking for letter codes like the above?

With difficulty, if you need multiple criteria, especially if you need
to mix cases within an individual query!

If you are searching just one field you can use the StrComp() VBA
function to do a case-sensitive comparison:

WHERE [field] = "1A" AND StrComp([field], "1A", 0) = 0

The first clause will limit the number of records to be processed to
just 1a and 1A; the strComp criterion will restrict it to exact
matches.

How you would do this with an IN clause is not obvious
to me!

In addition to Dirk's suggestion, I think you can use

WHERE [field ] IN ("1A","1B","1H","1O","1S")
AND StrComp(UCase([field]), [field], 0) = 0

--
Doug Steele, Microsoft Access MVP

(No private e-mails, please)



.
Thank you for your help. This looks like it might work for
me.
 
J

John Vinson

Doug's solution below (in
the other reply thread) looks like it might work for me
though.

It will work for the problem as you originally stated it - looking
only for upper case values. You'll need to use StrComp([field],
LCase([Field]), 0) = 0 to search for lower-case values only, and I
still cannot think of a good way (given your no-delimiters-allowed
constraint... sheesh!) of searching for ("1A", "2b", "3C", "aB") and
having it work in a case-specific way.
 
E

Ernie

Unfortunately, it didn't work. I tried many, many
variations of the solutions posted here, and could not
isolate codes 1A from 1a.

In the 3rd party database is a table which matches the
code (1A, 1a) with a description (dealer#, last revision).
This was done so that a history table stores just the code
and not the full description with every record (two bytes
vs 30 bytes). The developers of that db chose to allow any
printable character to enable having up to 2 to 64th
tables and fields referenced in the history file
(fortunately there aren't that many tables in use).

The layouts for these tables are:

tblAudit
acctno -- foreign key to customer master
date/time
tableid -- foreign key to the list of tables in the db
fieldid -- foreign key to the list of fields in each
table
other info as needed
(note that the acctno, date, tableid, fieldid combine to
make the primary key for this table).

tblTableList
tableid -- primary key
tablename -- names the table
tabledesc -- describes what, in general, is in that table

tblFieldList
tableid -- foreign key to tabel list above
fieldid -- (tableid + fieldid is primary key)
fieldname -- name of the field
fielddesc -- description

What I need is to extract from the tblAudit certain
records based on one of three table id's and up to 11
field id's (within a date range). Unfortunately, two of
the field id's that I need are being confused by access
between upper and lowercase characters, hence the request
for help. One of the field id's that I need is "1A"
(Dealer number) which is being confused with "1a" (Last
Revision). (The other one is 1B and 1b.) Because of this
confusion, I get two records where I should only get one.

I tried the strcomp as described:
WHERE [field] IN ("1A","1B","1H","1O","1S") AND StrComp
(UCase([field]), [field], 0) = 0

with no luck. I was still getting two records but somehow
the code got changed in the query so that the record
marked as '1a' shows as if it were '1A'.

I also tried selecting out the field names that I don't
want (with 64 to choose from, that's a lot of typing).
Again I got the same two records, this time the field name
was changed, but the codes were correct (I got two dealer
number records).

Does anybody have any other ideas?

Contact me at ESchultz @ SignatureSecurity dot Com dot AU
 
D

Douglas J. Steele

Can you post your entire SQL statement? I just tested (with Access 97) and
it works as advertised for me.
 
E

Ernie

SELECT ALTRANAH0407.ACCOUNT_NUMBER AS AcctNo, [NTD_DATE]-
693596 AS [Date], [NTD_DATE]-693596 AS [Time],
ALFHLIST.FILE_NAME, ALFDLIST.FIELD_NAME,
ALTRANAH0407.FILE_NUMBER, ALTRANAH0407.FIELD_NUMBER
FROM (ALTRANAH0407 INNER JOIN ALFHLIST ON
ALTRANAH0407.FILE_NUMBER = ALFHLIST.FILE_NUMBER) INNER
JOIN ALFDLIST ON (ALTRANAH0407.FILE_NUMBER =
ALFDLIST.FILE_NUMBER) AND (ALTRANAH0407.FIELD_NUMBER =
ALFDLIST.FIELD_NUMBER)
WHERE ((([NTD_DATE]-693596)>Now()-90) AND
((ALTRANAH0407.FILE_NUMBER)="!'") AND
((ALTRANAH0407.FIELD_NUMBER) In ("!0","!2","!3","!4","!
5","!6","!7","!9","!A","!B","!H","!M","!O","!S")) AND
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))
ORDER BY ALTRANAH0407.ACCOUNT_NUMBER, [NTD_DATE]-693596;

What I get when I run this query is:

AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 1156 1@ 1A Subscr DealerNo
123456 Jul-04 1156 1@ 1a Subscr Last Revision


among other records.

Note that both records do exist in the source table, but
that the '1a' record id is not in my query criteria.
The NTD_DATE is stored as a dateserial based on the number
of days since Jan 1, 0001, hence the -693596 to convert it
to access dateserial and then formatted to a medium date
for display.
 
D

Dirk Goldgar

Ernie said:
SELECT ALTRANAH0407.ACCOUNT_NUMBER AS AcctNo, [NTD_DATE]-
693596 AS [Date], [NTD_DATE]-693596 AS [Time],
ALFHLIST.FILE_NAME, ALFDLIST.FIELD_NAME,
ALTRANAH0407.FILE_NUMBER, ALTRANAH0407.FIELD_NUMBER
FROM (ALTRANAH0407 INNER JOIN ALFHLIST ON
ALTRANAH0407.FILE_NUMBER = ALFHLIST.FILE_NUMBER) INNER
JOIN ALFDLIST ON (ALTRANAH0407.FILE_NUMBER =
ALFDLIST.FILE_NUMBER) AND (ALTRANAH0407.FIELD_NUMBER =
ALFDLIST.FIELD_NUMBER)
WHERE ((([NTD_DATE]-693596)>Now()-90) AND
((ALTRANAH0407.FILE_NUMBER)="!'") AND
((ALTRANAH0407.FIELD_NUMBER) In ("!0","!2","!3","!4","!
5","!6","!7","!9","!A","!B","!H","!M","!O","!S")) AND
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))
ORDER BY ALTRANAH0407.ACCOUNT_NUMBER, [NTD_DATE]-693596;

What I get when I run this query is:

AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 1156 1@ 1A Subscr DealerNo
123456 Jul-04 1156 1@ 1a Subscr Last Revision


among other records.

Note that both records do exist in the source table, but
that the '1a' record id is not in my query criteria.
The NTD_DATE is stored as a dateserial based on the number
of days since Jan 1, 0001, hence the -693596 to convert it
to access dateserial and then formatted to a medium date
for display.

You left out the third argument (which Doug had specified) in your call
to the StrComp function. Instead of this:
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))

try this:

((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER], 0))=0))
 
E

Ernie

You left out the third argument (which Doug had specified) in your call
to the StrComp function. Instead of this:
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))

try this:

((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER], 0))=0))

--
Dirk Goldgar, MS Access MVP
www.datagnostics.com

(please reply to the newsgroup)


.
I tried it like that, I also put a 1 in there because
that's what the access help had as an example of StrComp,
finally I took it out and it still didn't work.

The only difference that I got between the various
attempts was that with a ,1 (where you have a ,0), the
query changes the '1a' to a '1A' when it displays.
e.g. from:

AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 1156 1@ 1A Subscr DealerNo
123456 Jul-04 1156 1@ 1a Subscr Last Revision

to:

AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 1156 1@ 1A Subscr DealerNo
123456 Jul-04 1156 1@ 1A Subscr Last Revision

My biggest problem with these results is that it is
possible for the "Last Revision" to change without
changing one of the fields that I'm actually interested
in. I don't want to know about changes to those other
fields, just changes to the fields listed in my "IN"
statement.

I do appreciate all the help that I am getting. Thank you
for your time.
 
D

Douglas J. Steele

I'm surprised you're getting anything. Why the exclamation marks in the
criteria?
 
E

Ernie

That's the way the code is stored. Any ascii printable
character from ! to ~ including letters (upper and lower),
numbers and symbols (chr(33) to chr(127)).

I changed the "!" to "1" in my original post so as to try
and not confuse the issue. It shouldn't make a difference,
should it?

-----Original Message-----
I'm surprised you're getting anything. Why the exclamation marks in the
criteria?

--
Doug Steele, Microsoft Access MVP

(no e-mails, please!)



SELECT ALTRANAH0407.ACCOUNT_NUMBER AS AcctNo, [NTD_DATE]-
693596 AS [Date], [NTD_DATE]-693596 AS [Time],
ALFHLIST.FILE_NAME, ALFDLIST.FIELD_NAME,
ALTRANAH0407.FILE_NUMBER, ALTRANAH0407.FIELD_NUMBER
FROM (ALTRANAH0407 INNER JOIN ALFHLIST ON
ALTRANAH0407.FILE_NUMBER = ALFHLIST.FILE_NUMBER) INNER
JOIN ALFDLIST ON (ALTRANAH0407.FILE_NUMBER =
ALFDLIST.FILE_NUMBER) AND (ALTRANAH0407.FIELD_NUMBER =
ALFDLIST.FIELD_NUMBER)
WHERE ((([NTD_DATE]-693596)>Now()-90) AND
((ALTRANAH0407.FILE_NUMBER)="!'") AND
((ALTRANAH0407.FIELD_NUMBER) In ("!0","!2","!3","!4","!
5","!6","!7","!9","!A","!B","!H","!M","!O","!S")) AND
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))
ORDER BY ALTRANAH0407.ACCOUNT_NUMBER, [NTD_DATE]-693596;

What I get when I run this query is:

AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 1156 1@ 1A Subscr DealerNo
123456 Jul-04 1156 1@ 1a Subscr Last Revision


among other records.

Note that both records do exist in the source table, but
that the '1a' record id is not in my query criteria.
The NTD_DATE is stored as a dateserial based on the number
of days since Jan 1, 0001, hence the -693596 to convert it
to access dateserial and then formatted to a medium date
for display.


.
 
D

Douglas J. Steele

Hard to say. ! is a wildcard character: it matches any character not in the
brackets, so that LIKE "b[!ae]ll" would find bill, boll and bull, but not
bell or ball. While you're not using LIKE, it's possible that the
exclamation mark could be causing problems.

My point, though, was that your SQL statement included

((ALTRANAH0407.FILE_NUMBER)="!'") AND (ALTRANAH0407.FIELD_NUMBER) In
("!0","!2","!3","!4","!5","!6","!7","!9","!A","!B","!H","!M","!O","!S"))

yet your sample data indicated FileNo 1@ AND FieldNo of 1A and 1a. I don't
believe the conditions in that WHERE clause will return that data.

--
Doug Steele, Microsoft Access MVP

(no e-mails, please!)



Ernie said:
That's the way the code is stored. Any ascii printable
character from ! to ~ including letters (upper and lower),
numbers and symbols (chr(33) to chr(127)).

I changed the "!" to "1" in my original post so as to try
and not confuse the issue. It shouldn't make a difference,
should it?

-----Original Message-----
I'm surprised you're getting anything. Why the exclamation marks in the
criteria?

SELECT ALTRANAH0407.ACCOUNT_NUMBER AS AcctNo, [NTD_DATE]-
693596 AS [Date], [NTD_DATE]-693596 AS [Time],
ALFHLIST.FILE_NAME, ALFDLIST.FIELD_NAME,
ALTRANAH0407.FILE_NUMBER, ALTRANAH0407.FIELD_NUMBER
FROM (ALTRANAH0407 INNER JOIN ALFHLIST ON
ALTRANAH0407.FILE_NUMBER = ALFHLIST.FILE_NUMBER) INNER
JOIN ALFDLIST ON (ALTRANAH0407.FILE_NUMBER =
ALFDLIST.FILE_NUMBER) AND (ALTRANAH0407.FIELD_NUMBER =
ALFDLIST.FIELD_NUMBER)
WHERE ((([NTD_DATE]-693596)>Now()-90) AND
((ALTRANAH0407.FILE_NUMBER)="!'") AND
((ALTRANAH0407.FIELD_NUMBER) In ("!0","!2","!3","!4","!
5","!6","!7","!9","!A","!B","!H","!M","!O","!S")) AND
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))
ORDER BY ALTRANAH0407.ACCOUNT_NUMBER, [NTD_DATE]-693596;

What I get when I run this query is:

AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 1156 1@ 1A Subscr DealerNo
123456 Jul-04 1156 1@ 1a Subscr Last Revision


among other records.

Note that both records do exist in the source table, but
that the '1a' record id is not in my query criteria.
The NTD_DATE is stored as a dateserial based on the number
of days since Jan 1, 0001, hence the -693596 to convert it
to access dateserial and then formatted to a medium date
for display.


.
 
E

Ernie

That's a mis-type and I didn't even notice it, sorry. The
examples should read:
AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 11:56 !' !A Subscr DealerNo
123456 Jul-04 11:56 !' !a Subscr Last Revision

I'm going to try and narrow down my search criteria and
see if I can't get rid of the ! in these tables. Thanks
for your help so far.
 
E

Ernie

-----Original Message-----
That's a mis-type and I didn't even notice it, sorry. The
examples should read:
AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 11:56 !' !A Subscr DealerNo
123456 Jul-04 11:56 !' !a Subscr Last Revision

I'm going to try and narrow down my search criteria and
see if I can't get rid of the ! in these tables. Thanks
for your help so far.
.
It worked. I changed my query criteria to "Right
(field_number,1) in ( etc " and I got just the rows that
I was looking for. No more !a and !A being treated as the
same code. I am now looking for just "A" not "!A". I still
had to use the strcomp to isolate "A" from "a" but now
that I know how, it was easy to do.

Thank you for all of your help in pointing me in the right
direction.
 
M

marcco perazzolo

Dirk Goldgar said:
Ernie said:
SELECT ALTRANAH0407.ACCOUNT_NUMBER AS AcctNo, [NTD_DATE]-
693596 AS [Date], [NTD_DATE]-693596 AS [Time],
ALFHLIST.FILE_NAME, ALFDLIST.FIELD_NAME,
ALTRANAH0407.FILE_NUMBER, ALTRANAH0407.FIELD_NUMBER
FROM (ALTRANAH0407 INNER JOIN ALFHLIST ON
ALTRANAH0407.FILE_NUMBER = ALFHLIST.FILE_NUMBER) INNER
JOIN ALFDLIST ON (ALTRANAH0407.FILE_NUMBER =
ALFDLIST.FILE_NUMBER) AND (ALTRANAH0407.FIELD_NUMBER =
ALFDLIST.FIELD_NUMBER)
WHERE ((([NTD_DATE]-693596)>Now()-90) AND
((ALTRANAH0407.FILE_NUMBER)="!'") AND
((ALTRANAH0407.FIELD_NUMBER) In ("!0","!2","!3","!4","!
5","!6","!7","!9","!A","!B","!H","!M","!O","!S")) AND
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))
ORDER BY ALTRANAH0407.ACCOUNT_NUMBER, [NTD_DATE]-693596;

What I get when I run this query is:

AcctNo Date Time FileNo FieldNo FileName FieldName
123456 Jul-04 1156 1@ 1A Subscr DealerNo
123456 Jul-04 1156 1@ 1a Subscr Last Revision


among other records.

Note that both records do exist in the source table, but
that the '1a' record id is not in my query criteria.
The NTD_DATE is stored as a dateserial based on the number
of days since Jan 1, 0001, hence the -693596 to convert it
to access dateserial and then formatted to a medium date
for display.

You left out the third argument (which Doug had specified) in your call
to the StrComp function. Instead of this:
((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER]))=0))

try this:

((StrComp(UCase([ALTRANAH0407].[FIELD_NUMBER]),
[ALTRANAH0407].[FIELD_NUMBER], 0))=0))

--
Dirk Goldgar, MS Access MVP
www.datagnostics.com

(please reply to the newsgroup)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top