Understanding a Microsoft Office Access SQL query with 'IIF' - sql

On a larger project, I am migrating dozens of queries from a Microsoft Office Access database (MDB) to Oracle.
While I was able to understand nearly all of the insane constructs that are possible to write in Access, I failed on a single one.
The (simplified) query is:
SELECT *
FROM SomeTable
WHERE
Left(SomeField,3)=IIf(SomeParameter="GYM",Mid(SomeField,2,1)<>'0')
AND
Left(SomeField,3)=IIf(SomeParameter="GYM",Left(SomeField,3)<>'110')
Here, SomeField is a column in the table and SomeParameter is an input to the query.
What I do not understand is the WHERE part:
Why is the else part missing from the IIF statement?
Why is a string compared to the result of an <> operation (i.e. a boolean)?
Since it successfully runs in Access, the query is valid. I failed to even generate some test data that will pass the comparison.
Any hints on how to interpret the comparison?

As I said in a comment, I share the original questioner's puzzlement over this expression:
WHERE Left(SomeField,3)=IIf(SomeParameter="GYM",Mid(SomeField,2,1)<>'0')
Let's unpack that:
If SomeParameter = "GYM" return this:
Mid(SomeField,2,1)<>'0'
This is testing the second character in SomeField against the string "0", so it means that there's a badly designed field, in that the second character in that field has independent meaning. This will return true for all values where the 2nd character is anything but 0.
Whatever it returns (True or Null in the False case), it will be compared to this string:
Left(SomeField,3)
If The first three characters of SomeField happen to be "Yes" then it might very well produce a true comparison, since in Access/Jet/ACE, Yes and True and -1 are all equivalent, and string representations can be implicitly coerced.
So, this might return rows that look like this:
SomeParameter SomeField
GYM Yes sir, that's my baby
However, it really makes not a lot of sense, as the test of SomeField is circular. That is, you're comparing to the first 3 characters of the field in an instance in which a true comparison can only happen when the first three characters are "Yes", but you're in turn comparing those first three characters to a test for whether or not the 2nd character in the same field <> 0. In all cases where the first three characters are "Yes" then the second character will definitely not be "0" so you really only need to test the value of the first three characters.
I vote for incompetence on the part of the original developer.

From http://www.techonthenet.com/access/functions/advanced/iif.php
iif ( condition, value_if_true, value_if_false )
So it's like a ternary operator in C++/C# etc.Looks like they don't care about if the value is false.
Also, I wonder if they didn't screw up the logic :)
EDIT
I believe it returns Null if the false condition isn't specified.
In which case it would appear that they're setting a field to either true (when the condition <> is true) or null, when it's false.
Seems like an odd design to me

The first iif will return Null if SomeParameter<>"GYM", otherwise it will return True or False depending on the boolean evaluation of the expression Mid(SomeField,2,1)<>'0'.
Same logic for the second iif.
Let me guess....is that a query in the finance industry ? ;-)

Related

What does it mean to have a valid record when the record contains nothing, not even a single space

I was browsing the data for a particular column which looked like it had spaces because it did not say null
Upon trying to find what it was, I discovered the data does not have a single space but it is also not blank.
What is it then? -- something between two single quotations '' which is not space.
Tried to run this query with no results:
select column1 from table1 where column1 like '% %'
-- Single space
-> No records found
The second query I tried (see below) has no spaces mentioned. And that gave a result saying that there exist records which are like ->''
select column1 from table1 where column1 like '% %'
select column1 from table1 where column1= ''
I am trying to understand what is that record and what does it mean to be nothing?
What is it then? -- something between two single quotations '' which is not space.
It's a string of zero length. You're right, it's not a space - a space is ' ' - it has a length of one character. A string of length 0 is nothing like a string of length 1, no matter what character is in the string.
In any computer system we arbitrarily decide on the meaning of everything. Suppose you have a question that has an answer A, B, or C. You might also have situations where the person doesn't know, or knows but doesn't want to say. You might arbitrarily decide to have NULL means "don't know" and 0 length string as "don't want to say" in addition to all the people who do answer with a letter
This is an arbitrary decision, maybe you decide to store a space for "don't want to say", maybe an exclamation mark- whatever. Some database vendors think it is important to provide support for having strings of zero length, others (oracle) do not (oracle treats null and '' as the same)
Ultimately if your db supports zero length strings you have to understand what they are and in the context of your application you have to understand what they mean. What they are is like a glass with no water in it, or a bag of sweets with no sweets in it.. The statement of "there is no data" is different to "we don't know if there is any data or not" - the uncertainty here is more often associated with NULL
I am trying to understand what is that record and what does it mean to be nothing?
That record is a record with a zero length string in that column. However, we cannot tell you what it means because the decision to store a zero length string in it was taken by you or one of the other developers at your company, or a previous developer who quit. It could be that he wanted to record a difference between null and zero data. It could be that he couldn't be bothered checking if the data was null and wanted to avoid a typical null reference crash on the front end app. It could be that he wanted to count the data even though there was no data to put there
We cannot answer this part of your question
We can only tell you that zero length strings are possible, you can attach as much meaning to them as any other string, and they will never be equal to a string of non zero length so like '% %' will never find them. Do not assume that something you cannot see must be a space..
Nullable Text fields be either NULL or a string of length 0, i.e. '' or a non-empty string, eg. 'abc'
'' is not the same as NULL.
I was taught in my databases course that NULL signifies that the value is unkown, and an identity value, such as an empty string, would mean that we know the value and it is nothing, but often developers and applications don't respect this distinction.

SQL Server 2008 - Default column value - should i use null or empty string?

For some time i'm debating if i should leave columns which i don't know if data will be passed in and set the value to empty string ('') or just allow null.
i would like to hear what is the recommended practice here.
if it makes a difference, i'm using c# as the consuming application.
I'm afraid that...
it depends!
There is no single answer to this question.
As indicated in other responses, at the level of SQL, NULL and empty string have very different semantics, the former indicating that the value is unknown, the latter indicating that the value is this "invisible thing" (in displays and report), but none the less it a "known value". A example commonly given in this context is that of the middle name. A null value in the "middle_name" column would indicate that we do not know whether the underlying person has a middle name or not, and if so what this name is, an empty string would indicate that we "know" that this person does not have a middle name.
This said, two other kinds of factors may help you choose between these options, for a given column.
The very semantics of the underlying data, at the level of the application.
Some considerations in the way SQL works with null values
Data semantics
For example it is important to know if the empty-string is a valid value for the underlying data. If that is the case, we may loose information if we also use empty string for "unknown info". Another consideration is whether some alternate value may be used in the case when we do not have info for the column; Maybe 'n/a' or 'unspecified' or 'tbd' are better values.
SQL behavior and utilities
Considering SQL behavior, the choice of using or not using NULL, may be driven by space consideration, by the desire to create a filtered index, or also by the convenience of the COALESCE() function (which can be emulated with CASE statements, but in a more verbose fashion). Another consideration is whether any query may attempt to query multiple columns to append them (as in SELECT name + ', ' + middle_name AS LongName etc.).
Beyond the validity of the choice of NULL vs. empty string, in given situation, a general consideration it to try and be as consistent as possible, i.e. to try and stick to ONE particular way, and to only/purposely/explicitly depart from this way for good reasons and in few cases.
Don't use empty string if there is no value. If you need to know if a value is unknown, have a flag for it. But 9 times out of 10, if the information is not provided, it's unknown, and that's fine.
NULL means unknown value. An empty string means a known value - a string with length zero. These are totally different things.
empty when I want a valid default value that may or may not be changed, for example, a user's middle name.
NULL when it is an error if the ensuing code does not set the value explicitly.
However, By initializing strings with the Empty value instead of null, you can reduce the chances of a NullReferenceException occurring.
Theory aside, I tend to view:
Empty string as a known value
NULL as unknown
In this case, I'd probably use NULL.
One important thing is to be consistent: mixing NULLs and empty strings will end in tears.
On a practical implementation level, empty string takes 2 bytes in SQL Server where as NULLs are bitmapped. In some conditions and for wide/larger tables it makes a different in performance because it's more data to shift around.

MS-Access - why can't this update query fill empty cells?

In MS-Access database, table called NewTable3
colname is a text column containing lot of empty cells or blanks.
i want to put ? character in empty cells . when i run the query
UPDATE NewTable3 SET colname = '?' WHERE ISNULL(colname) ;
This query updates 0 records why . what is wrong with this query
Two quick things:
1) Try putting the colname in square brackets.
2) Remember that empty cells (Nulls) and empty strings ("") are different.
Together:
UPDATE NewTable3 SET [colname] = "?" WHERE ISNULL([colname]) OR [colname] = "";
Also, are you running the query in Access itself, or just using the Access engine and using the data in another program/via a VBA script? It can make a difference.
EDIT:
Based on #onedaywhen's prodding, I now see that I never fully absorbed the original question, which was asking about replacing Nulls with the literal ? character. This is insane and not helpful or useful. If you don't have a meaningful default value for the field, then LEAVE IT NULL. If you want to distinguish between Null (unknown) and Blank (i.e., known to be blank), you can allow zero-length strings and change the Nulls to ZLS.
My original post follows, since I think it is useful for people who might get to this crazy question needing to do things properly:
In total, all the answers in this thread end up solving all the problems with the original SQL statement, but they do so incompletely, so I'll compile them all together in an attempt to create a comprehensive correct answer.
#Wim Hollebrandse wisely points out that a parameter needs brackets, but posts the SQL as:
UPDATE NewTable3 SET colname = '[?]' WHERE ISNULL(colname);
This is incorrect, in that the quotes will cause what's inside them to be treated literally, instead of evaluated as a paramter, so you'll end up with all your fields updated to the literal value "[?]". The correct syntax would be:
UPDATE NewTable3 SET colname = [?] WHERE ISNULL(colname);
#GuinnessFan points out a problem in the WHERE clause, suggesting out that the result of IsNull() needs to be compared to True in order for the WHERE clause to work. In other words, this:
WHERE IsNull(NewTable3.colname)
...should be this:
WHERE IsNull(NewTable3.colname)=True
But given that both statements evaluate the same, they are entirely equivalent. But #GuinnessFan is correct that this is the best syntax:
WHERE NewTable3.colname Is Null
#mavnn points out that the fields may be "empty" while not being Null, which is a very common problem. I believe on principle (and consistent with my understanding of the official SQL standards) that fields should be initialized as Null and should not allow zero-length strings. It is certainly possible in some applications that one might want to distinguish Null, i.e., value not yet supplied, from blank (zero-length string), i.e., value known to be blank. But if that's part of the application design, then the user should know that criteria on such fields need to consider whether one or both should be included (i.e., both Null and <>"" or one or the other).
From my point of view, it was unfortunate that the the old default for text fields (where AllowZLS defaulted to FALSE) was changed in Access 2003 to allow ZLS's by default. This means that many people who don't notice that AllowZLS is set to TRUE when they create their tables end up with ZLS's stored in their text fields without intending to do so (and importing a table from a previous version also defaults to TRUE).
While testing for Null and ="" will make the WHERE clause that is seeking all "empty" fields work as expected, the permanent fix is to change the field definition to disallow ZLS's. But do note that changing AllowZLS to FALSE does not clear the existing ZLS's -- you have to run a SQL UPDATE to remove them.
Last of all, in using parameters, it is better to declare them such that the values that the user can input are restricted to appropriate values. If the field is numeric, you to limit it to numeric values, if a date, date values, if text or memo, to text:
PARAMETERS [User Prompt] Long;
UPDATE MyTable SET LongIntegerColumn = [User Prompt]
PARAMETERS [User Prompt] DateTime;
UPDATE MyTable SET DateColumn = [User Prompt]
PARAMETERS [User Prompt] Text ( 255 );
UPDATE MyTable SET TextColumn = [User Prompt]
Note that with Text(255) as your parameter type, anything supplied by the user is truncated to 255 characters, even if it's longer than that (it would be a pretty unusual situation where'd you'd need that). For values longer than that (such as memo fields), you omit the text length declaration:
PARAMETERS [User Prompt] Text;
UPDATE MyTable SET TextColumn = [User Prompt]
In any event, I think so-called anonymous parameters are not too helpful, as you aren't leveraging the power of parameters to restrict data type of input criteria.
Try:
UPDATE NewTable3 SET colname = '[?]' WHERE ISNULL(colname);
The questionmark is used for anonymous parameters, so you need to escape it as above. Note that I have not tried this.
UPDATE NewTable3 SET NewTable3.colname = "?"
WHERE (((NewTable3.colname) Is Null));
To keep your function: WHERE (((IsNull([NewTable3.colname]))=True));
I don't believe that replacing the NULL value with your own 'magic' value ? will cause you anything but further pain.
Here's hoping you may draw inspiration from this article:
How To Handle Missing Information Without Using (some magic value)

TSQL: No value instead of Null

Due to a weird request, I can't put null in a database if there is no value. I'm wondering what can I put in the store procedure for nothing instead of null.
For example:
insert into blah (blah1) values (null)
Is there something like nothing or empty for "blah1" instead using null?
I would push back on this bizarre request. That's exactly what NULL is for in SQL, to denote a missing or inapplicable value in a column.
Is the requester experiencing grief over SQL logic with NULL?
edit: Okay, I've read your reply with the extra detail about this job assignment (btw, generally you should edit your original question instead of posting more information in an answer).
You'll have to declare all columns as NOT NULL and designate a special value in the domain of that column's data type to signify "no value." The appropriate value to choose might be different on a case by case basis, i.e. zero may signify nothing in a person_age column, but it might have significance in an items_in_stock column.
You should document the no-value value for each column. But I suppose they don't believe in documentation either. :-(
Depends on the data type of the column. For numbers (integers, etc) it could be zero (0) but if varchar then it can be an empty string ("").
I agree with other responses that NULL is best suited for this because it transcends all data types denoting the absence of a value. Therefore, zero and empty string might serve as a workaround/hack but they are fundamentally still actual values themselves that might have business domain meaning other than "not a value".
(If only the SQL language supported a "Not Applicable" (N/A) value type that would serve as an alternative to NULL...)
Is null is a valid value for whatever you're storing?
Use a sentry value like INT32.MaxValue, empty string, or "XXXXXXXXXX" and assume it will never be a legitimate value
Add a bit column 'Exists' that you populate with true at the same time you insert.
Edit: But yeah, I'll agree with the other answers that trying to change the requirements might be better than trying to solve the problem.
If you're using a varchar or equivalent field, then use the empty string.
If you're using a numeric field such as int then you'll have to force the user to enter data, else come up with a value that means NULL.
I don't envy you your situation.
There's a difference between NULLs as assigned values (e.g. inserted into a column), and NULLs as a SQL artifact (as for a field in a missing record for an OUTER JOIN. Which might be a foreign concept to these users. Lots of people use Access, or any database, just to maintain single-table lists.) I wouldn't be surprised if naive users would prefer to use an alternative for assignments; and though repugnant, it should work ok. Just let them use whatever they want.
There is some validity to the requirement to not use NULL values. NULL values can cause a lot of headache when they are in a field that will be included in a JOIN or a WHERE clause or in a field that will be aggregated.
Some SQL implementations (such as MSSQL) disallow NULLable fields to be included in indexes.
MSSQL especially behaves in unexpected ways when NULL is evaluated for equality. Does a NULL value in a PaymentDue field mean the same as zero when we search for records that are up to date? What if we have names in a table and somebody has no middle name. It is conceivable that either an empty string or a NULL could be stored, but how do we then get a comprehensive list of people that have no middle name?
In general I prefer to avoid NULL values. If you cannot represent what you want to store using either a number (including zero) or a string (including the empty string as mentioned before) then you should probably look closer into what you are trying to store. Perhaps you are trying to communicate more than one piece of data in a single field.

Why does Oracle 9i treat an empty string as NULL?

I know that it does consider ' ' as NULL, but that doesn't do much to tell me why this is the case. As I understand the SQL specifications, ' ' is not the same as NULL -- one is a valid datum, and the other is indicating the absence of that same information.
Feel free to speculate, but please indicate if that's the case. If there's anyone from Oracle who can comment on it, that'd be fantastic!
I believe the answer is that Oracle is very, very old.
Back in the olden days before there was a SQL standard, Oracle made the design decision that empty strings in VARCHAR/VARCHAR2 columns were NULL and that there was only one sense of NULL (there are relational theorists that would differentiate between data that has never been prompted for, data where the answer exists but is not known by the user, data where there is no answer, etc. all of which constitute some sense of NULL).
By the time that the SQL standard came around and agreed that NULL and the empty string were distinct entities, there were already Oracle users that had code that assumed the two were equivalent. So Oracle was basically left with the options of breaking existing code, violating the SQL standard, or introducing some sort of initialization parameter that would change the functionality of potentially large number of queries. Violating the SQL standard (IMHO) was the least disruptive of these three options.
Oracle has left open the possibility that the VARCHAR data type would change in a future release to adhere to the SQL standard (which is why everyone uses VARCHAR2 in Oracle since that data type's behavior is guaranteed to remain the same going forward).
Tom Kyte VP of Oracle:
A ZERO length varchar is treated as
NULL.
'' is not treated as NULL.
'' when assigned to a char(1) becomes
' ' (char types are blank padded
strings).
'' when assigned to a varchar2(1)
becomes '' which is a zero length
string and a zero length string is
NULL in Oracle (it is no long '')
Oracle documentation alerts developers to this problem, going back at least as far as version 7.
Oracle chose to represent NULLS by the "impossible value" technique. For example, a NULL in a numeric location will be stored as "minus zero", an impossible value. Any minus zeroes that result from computations will be converted to positive zero before being stored.
Oracle also chose, erroneously, to consider the VARCHAR string of length zero (the empty string) to be an impossible value, and a suitable choice for representing NULL. It turns out that the empty string is far from an impossible value. It's even the identity under the operation of string concatenation!
Oracle documentation warns database designers and developers that some future version of Oracle might
break this association between the empty string and NULL, and break any code that depends on that association.
There are techniques to flag NULLS other than impossible values, but Oracle didn't use them.
(I'm using the word "location" above to mean the intersection of a row and a column.)
I suspect this makes a lot more sense if you think of Oracle the way earlier developers probably did -- as a glorified backend for a data entry system. Every field in the database corresponded to a field in a form that a data entry operator saw on his screen. If the operator didn't type anything into a field, whether that's "birthdate" or "address" then the data for that field is "unknown". There's no way for an operator to indicate that someone's address is really an empty string, and that doesn't really make much sense anyways.
According to official 11g docs
Oracle Database currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases, and Oracle recommends that you do not treat empty strings the same as nulls.
Possible reasons
val IS NOT NULL is more readable than val != ''
No need to check both conditions val != '' and val IS NOT NULL
Empty string is the same as NULL simply because its the "lesser evil" when compared to the situation when the two (empty string and null) are not the same.
In languages where NULL and empty String are not the same, one has to always check both conditions.
Example from book
set serveroutput on;
DECLARE
empty_varchar2 VARCHAR2(10) := '';
empty_char CHAR(10) := '';
BEGIN
IF empty_varchar2 IS NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_varchar2 is NULL');
END IF;
IF '' IS NULL THEN
DBMS_OUTPUT.PUT_LINE(''''' is NULL');
END IF;
IF empty_char IS NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
ELSIF empty_char IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
END IF;
END;
Because not treating it as NULL isn't particularly helpful, either.
If you make a mistake in this area on Oracle, you usually notice right away. In SQL server, however, it will appear to work, and the problem only appears when someone enters an empty string instead of NULL (perhaps from a .net client library, where null is different from "", but you usually treat them the same).
I'm not saying Oracle is right, but it seems to me that both ways are approximately equally bad.
Indeed, I have had nothing but difficulties in dealing with Oracle, including invalid datetime values (cannot be printed, converted or anything, just looked at with the DUMP() function) which are allowed to be inserted into the database, apparently through some buggy version of the client as a binary column! So much for protecting database integrity!
Oracle handling of NULLs links:
http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/
http://jeffkemponoracle.com/2006/02/empty-string-andor-null.html
First of all, null and null string were not always treated as the same by Oracle. A null string is, by definition, a string containing no characters. This is not at all the same as a null. NULL is, by definition, the absence of data.
Five or six years or so ago, null string was treated differently from null by Oracle. While, like null, null string was equal to everything and different from everything (which I think is fine for null, but totally WRONG for null string), at least length(null string) would return 0, as it should since null string is a string of zero length.
Currently in Oracle, length(null) returns null which I guess is O.K., but length(null string) also returns null which is totally WRONG.
I do not understand why they decided to start treating these 2 distinct "values" the same. They mean different things and the programmer should have the capability of acting on each in different ways. The fact that they have changed their methodology tells me that they really don't have a clue as to how these values should be treated.