Dataset column always returns -1 - asp.net

I have a SQL stored proc that returns a dataset to ASP.NET v3.5 dataset. One of the columns in the dataset is called Attend and is a nullable bit column in the SQL table. The SELECT for that column is this:
CASE WHEN Attend IS NULL THEN -1 ELSE Attend END AS Attend
When I execute the SP in Query Analyzer the row values are returned as they should be - the value for Attend is -1 is some rows, 0 in others, and 1 in others. However, when I debug the C# code and examine the dataset, the Attend column always contains -1.
If I SELECT any other columns or constant values for Attend the results are always correct. It is only the above SELECT of the bit field that is behaving strangely. I suspect it has something to do with the type being bit that is causing this. So to test this I instead selected "CONVERT(int, Attend)" but the behavior is the same.
I have tried using ExecuteDataset to retrieve the data and I have also created a .NET Dataset schema with TableAdapter and DataTable. Still no luck.
Does anyone know what is the problem here?

Like you, I suspect the data type. If you can change the data type of Attend, change it to smallint, which supports negative numbers. If not, try changing the name of the alias from Attend to IsAttending (or whatever suits the column).
Also, you can make your query more concise by using this instead of CASE:
ISNULL(Attend, -1)

You've suggested that the Attend field is a bit, yet it contains three values (-1,0,1). A bit, however, can only hold two values. Often (-1, 0) when converted to an integer, but also possible (0, 1), depending on whether the BIT is considered signed (two's compliment) or unsigned (one's compliment).
If your client (the ASP code) is converting all values for that field to a BIT type then both -1 and 1 will likely show as the same value. So, I would ensure two things:
- The SQL returns an INTEGER
- The Client isn't converting that to a BIT
[Though this doesn't explain the absence of 0's]
One needs to be careful with implicit conversion of types. When not specifying explicitly double check the precidence. Or, to be certain, explicitly specify every type...
Just out of interest, what do you get when using the following?
CASE [table].attend
WHEN NULL THEN -2
WHEN 0 THEN 0
ELSE 2
END

Related

Skip assigning if found duplicates

I have a procedure that assigns values and sends it back. I need to implement a change that it would skip the assigning process whenever it finds duplicate iban code. It would be in this FOR EACH. Some kind of IF or something else. Basically, when it finds an iban code that was already used and assigned it would not assign it for the second or third time. I am new to OpenEdge Progress so it is really hard for me to understand correctly the syntax and write the code by myself yet. So if anyone could explain how I should implement this, give any pieces of advice or tips I would be very thankful.
FOR EACH viewpoint WHERE viewpoint.cif = cif.cif AND NOT viewpoint.close NO-LOCK:
DEFINE VARIABLE cIban AS CHARACTER NO-UNDO.
FIND FIRST paaa WHERE paaa.cif EQ cif.cif AND paaa.paaa = viewpoint.aaa AND NOT paaa.close NO-LOCK NO-ERROR.
cIban = viewpoint.aaa.
IF AVAILABLE paaa THEN DO:
cIban = paaa.vaaa.
CREATE tt_account_rights.
ASSIGN
tt_account_rights.iban = cIban.
END.
You have not shown the definition of tt_account_rights but assuming that "iban" is a uniquely indexed field in tt_account_rights you probably want something like:
DEFINE VARIABLE cIban AS CHARACTER NO-UNDO.
FOR EACH viewpoint WHERE viewpoint.cif = cif.cif AND NOT viewpoint.close NO-LOCK:
FIND FIRST paaa WHERE paaa.cif EQ cif.cif AND paaa.paaa = viewpoint.aaa AND NOT paaa.close NO-LOCK NO-ERROR.
cIban = viewpoint.aaa.
IF AVAILABLE paaa THEN DO:
cIban = paaa.vaaa.
find tt_account_rights where tt_account_rights.iban = cIban no-error.
if not available tt_account_rights then
do:
CREATE tt_account_rights.
ASSIGN
tt_account_rights.iban = cIban.
end.
END.
Some bonus perspective:
1) Try to express elements of the WHERE clause as equality matches whenever possible. This is the most significant contributor to query efficiency. So instead of saying "NOT viewpoint.close" code it as "viewpoint.close = NO".
2) Do NOT automatically throw FIRST after every FIND. You may have been exposed to some code where that is the "standard". It is none the less bad coding. If the FIND is unique it adds no value (it does NOT improve performance in that case). If the FIND is not unique and you do as you have done above and assign a value from that record you are, effectively, making that FIRST record special. Which is a violation of 3rd normal form (there is now a fact about the record which is not related to the key, the whole key and nothing but the key). What if the 2nd record has a different iBan? What if different WHERE clauses return different "1st" records?
There are cases where FIRST is appropriate. The point is that it is not ALWAYS correct and it should not be added to every FIND statement without any thought about why you are putting it there and what the impact of that keyword really is.
3) It is clearer to put the NO-LOCK (or EXCLUSIVE-LOCK or SHARE-LOCK) immediately after the table name rather than towards the end of the statement. The syntax works either way but from a readability perspective it is better to have the lock phrase right by the table.

database column not compared

I am saving all kinds of usernames and passwords in one table, however to differentiate the category there is third column that represents either he is clerk or administrator or teacher etc....the code is comparing username and password well but the third comparison is always returning false
here is my code
if (reader.GetString(0).Equals(password.Text))
{
if (reader.GetString(1).ToString().Equals("Clerk"))
Response.Redirect("clerkmain.aspx");
else
status.InnerHtml="You are not Allowed to Login";}
while the third column in this row is exactly named "Clerk" with datatype of varchar
With SQL you will find that the Equal operator and for that matter (even Select distinct) will not properly distinguish between a value and the same value with trailing spaces. In certain cases, you may need to do some further checking / processing (Trim, len, etc.) OR use LIKE, which follows a different process. You can look at https://stackoverflow.com/a/28682838/1662973 for more info and background.
Glad it so sorted.

Issue with simple sorting. Should I fix at database or in code?

I am working on a sort function for a table column that holds desk numbers and names.
This is a legacy program and was designed so that this column is nvarchar.
Because of this, the sort function cannot sort numerically as shown below:
Should I go into the database and alter this column to add leading zeros to number-only entries? Is this even do-able since the column is nvarchar?
Or should I add code at the object-level to add leading zeros just before the data is presented?
I would add one getter property in my class so it look like
public int Ordering
{
get
{
return int.Parse(CharColumn);
}
}
and when getting list of those objects simply order by that new property.
SQL Server is built upon SET Theory which states that, if you order your result set, you get non-relational data.
I would create another database column with the numeric value (there may be some columns that don't convert well, make sure you identify these and work to convert them). Then I would work to convert your application to use the new values. If the conversion is too great you could make sure all new development uses the new column and old code is migrated the next time someone touches it.
The risk to your approach is too fold, storing them in varchar is inefficient with both memory and processing power. Adding zeroes will help with the sorting but not fix the root issue.
Here is another question that I think will help you: SQL Server : error converting data type varchar to numeric

Is this normal behavior for a unique index in Sqlite?

I'm working with SQLite in Flash.
I have this unique index:
CREATE UNIQUE INDEX songsIndex ON songs ( DiscID, Artist, Title )
I have a parametised recursive function set up to insert any new rows (single or multiple).
It works fine if I try to insert a row with the same DiscID, Artist and Title as an existing row - ie it ignores inserting the existing row, and tells me that 0 out of 1 records were updated - GOOD.
However, if, for example the DiscId is blank, but the artist and title are not, a new record is created when there is already one with a blank DiscId and the same artist and title - BAD.
I traced out the disc id prior to the insert, and Flash is telling me it's undefined. So I've coded it to set anything undefined to "" (an empty string) to make sure it's truly an empty string being inserted - but subsequent inserts still ignore the unique index and add a brand new row even though the same row exists.
What am I misunderstanding?
Thanks for your time and help.
SQLite allows NULLable fields to participate in UNIQUE indexes. If you have such an index, and if you add records such that two of the three columns have identical values and the other column is NULL in both records, SQLite will allow that, matching the behavior you're seeing.
Therefore the most likely explanation is that despite your effort to INSERT zero-length strings, you're actually still INSERTing NULLs.
Also, unless you've explicitly included OR IGNORE in your INSERT statements, the expected behavior of SQLite is to throw an error when you attempt to insert a duplicate INDEX value into a UNIQUE INDEX. Since you're not seeing that behavior, I'm guessing that Flash provides some kind of wrapper around SQLite that's hiding the true behavior from you (and could also be translating empty strings to NULL).
Larry's answer is great. To anyone having the same problem here's the SQLite docs citation explaining that in this case all NULLs are treated as different values:
For the purposes of unique indices, all NULL values are considered
different from all other NULL values and are thus unique. This is one
of the two possible interpretations of the SQL-92 standard (the
language in the standard is ambiguous). The interpretation used by
SQLite is the same and is the interpretation followed by PostgreSQL,
MySQL, Firebird, and Oracle. Informix and Microsoft SQL Server follow
the other interpretation of the standard, which is that all NULL
values are equal to one another.
See here: https://www.sqlite.org/lang_createindex.html

tSQLt AssertEqualsTable does not check ordering

I have two tables defined for actual and expected with exactly the same schema. I insert two rows into the expected table with say Ids of 2, 1.
I run
INSERT INTO actual EXEC tSQLt.ResultSetFilter 1, '{statement}'
to populate the actual then
EXEC tSQLt.AssertEqualsTable #expected = 'expected' , #actual = 'actual'
to compare the results.
Even though the data is in a different order (Ids are 1, 2 in the actual), the test passes.
I confirmed that the data was different by adding SELECT * FROM actual and SELECT * FROM expected in the test and running the test on its own with tSQLt.Run '{test name}'.
Does anyone know if this is a known bug? Apparently it is supposed to check per row so the ordering should be checked. All the other columns are NULL that are returned it is just the ID column that contains a value.
Unless an order by clause is specified in the select statement, the order isn't guaranteed by SQL server (see the top bullet point at this MSDN page) - although in practice it is often ordered as you might expect.
Because of this, I believe that tSQLt looking for non-identical and identical rows makes sense - but checking the order doesn't - otherwise the answer could change at the whim of SQL server and the test would be meaningless (and worse - intermittently failing!). The tSQLt user guide on AssertEqualsTable states that it checks the content of the table, but not that it checks the ordering therein. What leads you to conclude that the order should be being checked as well? I couldn't find mention of it.
If you need the order to be checked, you could insert both expected and actual results into a temporary table with an identity column (or use ROW_NUMBER) and check the resultant table - if the order is different then the identity cols would be different.
There is a similar method documented here on Greg M Lucas' blog.
Relying on the order returned from the table without an order by clause is not recommended (MSDN link) - so I'd suggest including one in your application's call to the statement, or if an SP within it if the order of returned rows is important.

Resources