My database table is not ordered - asp.net

Sometimes when I insert a new row to a table in my database, it comes before the last row.
I will explain. If I have the following table:
ID Name
1 James
2 Terry
3. Miriam
4. Arthur
and I want to insert a new row with "Danny", sometimes this happens:
ID Name
1 James
2 Terry
3. Miriam
5. Danny
4. Arthur
My code works in 99 percent of the cases, but sometimes it just happens.
I do not know what to do? Is this normal?
I work with ASP.NET, VB.NET, .NET 3.5 and MySQL database with autoIncrement on the ID column.
I've seen it also happen in Access and SQL Server.
This is my code:
' insert to user_table
Dim connString As String = ConfigurationManager.ConnectionStrings("mysql_ConnString").ConnectionString
Dim conn As MySqlConnection = New MySqlConnection(connString)
Dim sqlCommand As String
sqlCommand = "INSERT INTO user_table (Nickname,Email,Pass,SubscriptionMode,SignupDate,LastVisitDate,VisitCounter) VALUES (#Nickname,#Email,#Pass,#SubscriptionMode,#SignupDate,#LastVisitDate,#VisitCounter)"
Dim cmd As New MySqlCommand(sqlCommand, conn)
Try
conn.Open()
cmd.Parameters.AddWithValue("#Nickname", txtNickname.Text)
cmd.Parameters.AddWithValue("#Email", txtEmail.Text)
cmd.Parameters.AddWithValue("#Pass", password)
cmd.Parameters.AddWithValue("#SubscriptionMode", 1)
cmd.Parameters.AddWithValue("#SignupDate", Date.Now)
cmd.Parameters.AddWithValue("#LastVisitDate", Date.Now)
cmd.Parameters.AddWithValue("#VisitCounter", 0)
cmd.ExecuteNonQuery()
Catch ex As Exception
GlobalFunction.sendToLog(ex, "problem in create profile page - sub: insertUser_table")
GlobalFunction.jsMessage(Me, "problem in create profile page - sub: insertUser_table")
Return False
Finally
conn.Close()
End Try

In general, when you do
select * from Users
you cannot rely on the order of records. if you need your records in some particular order, you'll have to explicitly specify an order by clause
select * from Users order by ID

MySql is a Relational Database Management System which means that it is based on the relational model. The physical order of the rows of a table (which represents a relation) is of no importance. You must think of tables as Unorder Sets. If you want to present your data in a specific order you must use the order by clause.
I think that if you use InnoDB you can use a clustered index to specify the order of the rows.

To correct your question: My database table is not ordered
Your database table is ordered, but your select statement is not ordered.
And because it is not that's why you're not getting an ordered result.
The result that you are getting is in undefined order!
If you want an ordered result you must always specify and order by clause in your query.

Make ID your primary key and make it indexed. No matter what your newly entered row will be the last one. For selecting use the suggestions above about order by.

As Bala R said, you can't have SQL determine how you want to organize your data, so you want to do something like this:
SELECT * FROM Users ORDER BY id ASC
ex: (1,2,3,4,5)
Or this:
SELECT * FROM Users ORDER BY id DESC
ex: (5,4,3,2,1)

Related

Oracle DataReader get sorted even with an ORDER BY clause in VB.NET

I have a simple SELECT query :
SELECT id, name FROM myTable ORDER BY id
When I execute it in Oracle, I get it sorted letters first.
ID NAME
A ValueA
B ValueB
C ValueC
1 Value1
2 Value2
3 Value3
When I execute it in my VB project, the datareader sort it according to my CultureInfo even with the ORDER BY
Dim dictio As New Dictionary(Of String, String)
strQuery = "SELECT id, name FROM myTable ORDER BY id"
rs = New OracleCommand(strQuery, myConnection).ExecuteReader()
Do While (rs.Read())
dictio.Add(rs.Item(0), rs.Item(1))
Loop
I get my rows in the dictionary ordered like this:
ID NAME
1 Value1
2 Value2
3 Value3
A ValueA
B ValueB
C ValueC
I guess this issue come from .NET itself, sorting the rows when it put them into a list and using my CultureInfo.
Do you know how to get rid of it and tell it to use the raw data?
Regardless the actual technicalities of your query and why the data is coming out in different orders depending on the route you take to running the query, sorting data is generally the purview of the front end/visualization strategy rather than the database
Pull your data out of the DB in whatever order it comes, without an ORDER BY, and then sort it in your VB into whatever order you want to show it to the user:
Dim dictio As New SortedDictionary(Of String, String)
^^^^^^
sort by key
strQuery = "SELECT id, name FROM myTable"
rs = New OracleCommand(strQuery, myConnection).ExecuteReader()
Do While (rs.Read())
Dim id as String = rs.Item(0).ToString()
id = Char.IsDigit(id(0)).ToString()(0) + id
dictio.Add(, rs.Item(1))
Loop
Rather than make my own comparer here I chose the cheap and nasty route of modifying the key used for the sort; all the letters will return False from Char.IsDigit, and prepending the ID with the F will mean they sort before the T that is prepended to digits
Thank you for your answers.
I don't really want to sort the datas in my application.
In fact, this application is a migrated one from ASP(VB6) to ASP.NET(VB.NET) and there is a lot of datareaders like this one. So I'm hopping to find a solution resolving all the cases in one shot.
I tried the query you gave me, and it helped a lot. Now, I'm quite sure my issue come from this.
Here are the results:
In Oracle itself: FRENCH
In VB with culture set to en-US: BINARY
In VB with culture set to fr-FR: FRENCH
My dream goal is to keep my main culture to en-US (mostly for dates in the application), and executing my query as if it was the fr-FR one.
Do you know if I can, in some way, execute a query with a specified culture ? I couldn't find a easy solution to do it...

SQL server ##Identity issue

I'm using ##Identity to get identity of a particular row after successful insert on a table, but sometimes I'm getting someother identity other than what it created for a particular row.
Sample:
ID UserName Age Location
1 Andy 22 USA
2 Robert 24 Canada
3 James 26 Mexico
From above sample while getting identity for user 'Robert' some other created 'James' and I'm getting the lastest identity as '3' instead of '2'.
All this is happening in a ASP.NET website user registration, it's giving the latest identity for each connection object and the same connection object is using for all registrations.
Please some one help me this out how to get the exact identiy when some other people using same connection object to get the identity?
If i use SCOPE_IDENTITY() for the below query, I'm getting DBNULL exception while convertion.
cmd.Connection = conn;
conn.Open();
int intStatus = cmd.ExecuteNonQuery();
if (intStatus == 1)
{
SqlCommand cmd1 = new SqlCommand("Select SCOPE_IDENTITY()", conn);
id_package = Convert.ToInt32(cmd1.ExecuteScalar());
}
use SCOPE_IDENTITY() it will return the last identity value generated in your session.
##IDENTITY will return the last generated identity value in ANY session.
Also if you are inserting multiple rows you can use the OUTPUT clause too to get all the newly generated identity values in your session.
Use OUTPUT Clause
INSERT INTO YourTable (UserName, Age, Location)
OUTPUT inserted.ID
VALUES ("Andy", 22, "USA")
If ID is identity column, statement will return inserted ID by this query
I think you are looking for SCOPE_IDENTITY(). This will give you the identity value generated from your query or session
I don't know anything about asp.net, but it at least looks to me like you're creating a new database session to get the identity and that's why you get nulls. You'll have to fetch it in the same session where you have created the row (or use output clause).

How can I create a LINQ statement where the table name (FROM) and column name (SELECT) is variable?

In my programming task I've gone down a dark alley and wished I hadn't, but there is no turning back now.
I'm building up a SQL statement where the table name, column name and id value are retrieved from query string parameters i.e. ("SELECT [{0}] FROM [{1}] WHERE [Id] = {2};", c, t, id)
But it isn't as bad as it looks, I'm protected:
Only authenticated users (i.e. signed in users) can execute the Page_Load
I'm checking that both the table and the column exists beforehand
(using GetSchema etc.)
I'm checking that the Id is an integer beforehand
All my tables have Id columns
The database connection is reasonably secure
The field value is expected to be of type NVARCHAR(4000) or NVARCHAR(MAX) so I'm avoiding ExecuteScalar and I'm trying out LINQ ExecuteQuery because I like LINQ. But I'm a bit out of my depth again.
I've got this far:
Dim db As New MyDataContext
Dim result = db.ExecuteQuery(Of ITable)("SELECT [{0}] FROM [{1}] WHERE [Id] = {2};", c, t, id)
Is this the right way to go?
How do I get first row and first column value?
Is there a better alternative?
P.S. It's a SQL Server 2005 database
Any help appreciated.
Thanks.
SQL Server requires the tables ans columns to be statically known. You can't provide them using command parameters. You can't say
select * from #tableName
because the table name can't be a variable.
You need to build the SQL string with C# ensuring proper escaping of identifiers. Escaping works like this:
var escaped = "[" + rawUntrustedUserInput.Replace("]", "]]") + "]";
This is safe.

How do I add a new column in between two columns?

I have a table with columns name, qty, rate. I need to add a new column COLNew in between the name and qty columns. How do I add a new column in between two columns?
You have two options.
First, you could simply add a new column with the following:
ALTER TABLE {tableName} ADD COLUMN COLNew {type};
Second, and more complicatedly, but would actually put the column where you want it, would be to create the new table with the missing column and a temporary new name:
CREATE TABLE {tempNewTableName} (name TEXT, COLNew {type} DEFAULT {defaultValue}, qty INTEGER, rate REAL);
And populate it with the old data:
INSERT INTO {tempNewTableName} (name, qty, rate) SELECT name, qty, rate FROM OldTable;
Then delete the old table:
DROP TABLE OldTable;
Then rename the new table to have the name of the OldTable:
ALTER TABLE {tempNewTableName} RENAME TO OldTable;
I'd much prefer the second option, as it will allow you to completely rename everything if need be.
You don't add columns between other columns in SQL, you just add them. Where they're put is totally up to the DBMS. The right place to ensure that columns come out in the correct order is when you select them.
In other words, if you want them in the order {name,colnew,qty,rate}, you use:
select name, colnew, qty, rate from ...
With SQLite, you need to use alter table, an example being:
alter table mytable add column colnew char(50)
You can add new column with the query
ALTER TABLE TableName ADD COLUMN COLNew CHAR(25)
But it will be added at the end, not in between the existing columns.
SQLite has limited ALTER TABLE support that you can use to add a column to the end of a table or to change the name of a table.
If you want to make more complex changes in the structure of a table, you will have to recreate the table. You can save existing data to a temporary table, drop the old table, create the new table, then copy the data back in from the temporary table.
For example, suppose you have a table named "t1" with columns names "a" and "c" and that you want to insert column "b" from this table. The following steps illustrate how this could be done:
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,c);
INSERT INTO t1_backup SELECT a,c FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b, c);
INSERT INTO t1 SELECT a,c FROM t1_backup;
DROP TABLE t1_backup;
COMMIT;
Now you are ready to insert your new data like so:
UPDATE t1 SET b='blah' WHERE a='key'
ALTER TABLE {tableName} ADD COLUMN COLNew {type};
UPDATE {tableName} SET COLNew = {base on {type} pass value here};
This update is required to handle the null value, inputting a default value as you require. As in your case, you need to call the SELECT query and you will get the order of columns, as paxdiablo already said:
SELECT name, colnew, qty, rate FROM{tablename}
and in my opinion, your column name to get the value from the cursor:
private static final String ColNew="ColNew";
String val=cursor.getString(cursor.getColumnIndex(ColNew));
so if the index changes your application will not face any problems.
This is the safe way in the sense that otherwise, if you are using CREATE temptable or RENAME table or CREATE, there would be a high chance of data loss if not handled carefully, for example in the case where your transactions occur while the battery is running out.
I was facing the same problem and the second method proposed in the accepted answer, as noted in the comments, can be problematic when dealing with foreign keys.
My workaround is to export the database to a sql file making sure that the INSERT statements include column names. I do it using DB Browser for SQLite which has an handy feature for that. After that you just have to edit the create table statement and insert the new column where you want it and recreate the db.
In *nix like systems is just something along the lines of
cat db.sql | sqlite3 database.db
I don't know how feasible this is with very big databases, but it worked in my case.
I seldom add Answers to 11 year old questions. That said the answer with a lot of votes has a misleading line of code. I say misleading because I tried it and had no success. Here is the line of code I am referencing.
ALTER TABLE {tableName} RENAME TO TempOldTable
This is the line I tried in my first try at adding a Column into a DB Table that had already been created. It FAILED but WHY might be a better question. Any way here is the failing line of code.
Dim tb As String = "IncomeTable"
Dim sqlCmd As String = "$ALTER TABLE" '{tb}' "ADD COLUMN itNumVisit INTEGER"
So here is the final code that adds a new Column in my case an INTEGER type.
Private Sub btnCopyTable_Click(sender As Object, e As EventArgs) Handles btnCopyTable.Click
Dim sqlCmd As String = "ALTER TABLE IncomeTable ADD COLUMN itNumVisit INTEGER"
Try
Using conn As New SQLiteConnection($"Data Source = '{gv_dbName}';Version=3;")
conn.Open()
Using cmd As New SQLiteCommand(sqlCmd, conn)
cmd.ExecuteNonQuery()
End Using
End Using
Catch ex As Exception
MsgBox("It Failed")
End Try
End Sub
Notice the STRING sqlCmd is all one String. Just in case someone tried the accepted Answer!

How to check a SQL database table to see if a record exists

I have a SQL database that creates a record for every document uploaded by the user to the server. I want to check this table before a user uploads a document to ensure they don't upload a file with name that already exists.
I know how to make the connection and make the SqlCommand to query the table for an existing record. But I don't know how to check the record count from the sqlCommand I made.
Does that make sense?
Using myConnectionCheck As New SqlConnection(myConnectionStringCheck)
Dim myCommandCheck As New SqlCommand()
myCommandCheck.Connection = myConnectionCheck
myCommandCheck.CommandText = "SELECT * FROM Req_Docs WHERE Doc_Name =" & DocName
myConnectionCheck.Open()
myCommandCheck.ExecuteNonQuery()
End Using
Thanks in advance,
Anthony
use if exists for this issue
create procedure isDocExists
#DocName varchar(255),
#isExists bit output
as
set #isExists = 0
if exists (SELECT Doc_Name FROM Req_Docs WHERE Doc_Name =#DocName)
begin
set #isExists=1
end
to check where record is there or not
So many things wrong here:
Race condition between when you check and when you upload
Multiple Documents should legitimately be allowed to have the same name. Use tags, folders, timestamps, or other means to distinguish them.
Sql Injection vulnerability on the name parameter
ExecuteNonQuery() on a SELECT query.
I'll give you the benefit of the doubt on the first two points that you're still gonna allow the upload, and this is just so you can ask the user how they want to relate the documents. Given that, here's how you fix the other two:
Using cn As New SqlConnection(myConnectionStringCheck), _
cmd As New SqlCommand("SELECT COUNT(*) FROM (SELECT TOP 1 1 FROM Req_Docs WHERE Doc_Name= #DocName) t", cn)
cmd.Parameters.Add("#DocName", SqlDbTypes.VarChar, 255).Value = DocName
cn.Open()
Return CInt(cmd.ExecuteScalar())
End Using
ExecuteNonQuery is a function, that returns an integer equal to the number of rows affected by the query.
However, it's usually used for updates.
You might consider ExecuteScalar, which returns the first column of the first row in the result set.
So if you change the query to select count(*) from..., the result of ExecuteScalar will be the number of rows, which you can then test.
if you want count:
SELECT COUNT(*) as count FROM Req_Docs WHERE Doc_Name = 'DocName'

Resources