\I have three columns in an access database table (DATA) as shown below
I just want to delete some rows based of two conditions in the WHERE clause in the SQL query ; for ex, delete row when NAME = "A" and Date = "1/1/2017"
I used DELETE from DATA Where Name='A' and Date='1/1/2017'
This gives "type mismatch error"!
Here is the code in C#:
using (OleDbConnection thisConnection = new OleDbConnection(connectionname))
{
string deletequery = " DELETE FROM DATA WHERE [Name] = 'A' And [Date] = '1/1/2017';
OleDbCommand myAccessCommandDelete = new OleDbCommand(deletequery, thisConnection);
thisConnection.Open();
myAccessCommandDelete.ExecuteNonQuery();
thisConnection.Close();
}
The best way to pass values to a database engine that will be used in a query is through the parameters collection specifying exactly the type of the parameter
using (OleDbConnection thisConnection = new OleDbConnection(connectionname))
{
string deletequery = #"DELETE FROM DATA WHERE [Name] = #name And
[Date] = #date";
OleDbCommand myAccessCommandDelete = new OleDbCommand(deletequery, thisConnection);
thisConnection.Open();
myAccessCommandDelete.Parameters.Add("#name", OleDbType.VarWChar).Value = "A";
myAccessCommandDelete.Parameters.Add("#date", OleDbType.Date).Value = new DateTime(2017,1,1);
myAccessCommandDelete.ExecuteNonQuery();
// not needed -> thisConnection.Close();
}
In this way you don't leave space to interpretation (conversion from string to date) of your values but you tell exactly to your db engine what your value is. And of course if you specify the correct type you can't have a Type Mismatch error
Related
I have a simple table on SQL Server 2016:
CREATE TABLE AgentDownload
(
Download VARCHAR(max)
)
I'm using the below code to populate this table using the SqlBulkCopy class in C#.
var agentDataTable = new DataTable();
agentDataTable.Clear();
agentDataTable.Columns.Add("Download");
var agentDownloadRow = agentDataTable.NewRow();
var veryLongString = "aaa..." // 200,000 a's repeated
agentDownloadRow["Download"] = veryLongString;
agentDataTable.Rows.Add(agentDownloadRow);
using (var connection = new SqlConnection("Data Source=Server;Initial Catalog=Database;Integrated Security=True;"))
{
connection.Open();
var transaction = connection.BeginTransaction();
using (var sbCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.CheckConstraints, transaction))
{
sbCopy.BulkCopyTimeout = 0;
sbCopy.BatchSize = 10000;
sbCopy.DestinationTableName = "AgentDownload";
sbCopy.WriteToServer(agentDataTable);
}
transaction.Commit();
}
On the database when I retrieve this entry, the cell value is truncated at 65,535 characters. This is a limit of some sort but I'm not sure where this is coming from or if there is any way around this? The column can contain far more characters and a string type in C# can also contain far more characters. Is there any to do this operation?
I thought this might be a limitation of SqlBulkCopy class but using alternative code such as below also produces the same result:
using (var connection = new SqlConnection("Data Source=Server;Initial Catalog=Database;Integrated Security=True;"))
{
connection.Open();
var transaction = connection.BeginTransaction();
var cmd = connection.CreateCommand();
cmd.Transaction = transaction;
cmd.CommandText = "insert into AgentDownload (Download) values (CAST('' AS VARCHAR(MAX)) + #testVariable)";
var parameter = new SqlParameter
{
ParameterName = "testVariable",
DbType = DbType.String,
Size = -1,
Value = veryLongString
};
cmd.Parameters.Add(parameter);
cmd.ExecuteNonQuery();
transaction.Commit();
}
It seems you are using SSMS to view the bulk inserted data. SSMS truncates large values by default to 65535 characters.
To see the entire value in the results grid for the current query window, change the Max Characters Retrieved value from the SSMS menu under Query-->Query Options-->Results-->Grid.
One can also specify the value for all new query windows under Tools-->Options-->Query Results-->SQL Server-->Results to Grid. However, consider the implications on client memory requirements with many rows containing large values. I suggest one change the global option judiciously.
Is there a way to retrieve the latest inserted guid in access with C#?
I tried this: Created a table Cars with a field Id of type autonumber, replicationID and a field Name varchar(250).
var command = myConnection.CreateCommand();
command.Connection.Open();
command.CommandText = "INSERT INTO Cars(Name) VALUES ('Pagani')";
command.ExecuteNonQuery();
command = context.Database.Connection.CreateCommand();
command.CommandText = "SELECT ##Identity";
Console.WriteLine(command.ExecuteScalar());
command.Connection.Close();
The issue which I am getting is:
Console.WriteLine(command.ExecuteScalar());
always shows 0
EDIT
To create the table you can use this statement over the C# OleDb connection (I think that from MS Access query does not work)
CREATE TABLE [Cars] (
[Id] guid not null DEFAULT GenGUID(),
[Name] text null
);
ALTER TABLE [Cars] ADD CONSTRAINT [PK_Cars_6515ede4] PRIMARY KEY ([Id])
I know this is not exactly what you are asking for, but let me suggest an alternative solution which might solve your underlying problem.
Create the GUID in C# and pass it to your insert:
var newGuid = Guid.NewGuid();
var command = myConnection.CreateCommand();
command.Connection.Open();
command.CommandText = "INSERT INTO Cars(Id, Name) VALUES (?, 'Pagani')";
command.Parameters.AddWithValue("#Id", newGuid); // Note: OleDb ignores the parameter name.
command.ExecuteNonQuery();
Console.WriteLine(newGuid);
GUIDs are unique. It really doesn't matter whether it is generated by your application or by the Access database driver.
This option is in all respects superior to reading the GUID afterwards:
You only need one database access.
It's less code.
It's easier.
And you can still omit the GUID in your INSERT in cases where you don't need to know the GUID - no need to change existing code.
If SELECT ##IDENTITY does not work for "ReplicationID" AutoNumber fields then the most likely way to retrieve such a value for a new record is to use an Access DAO Recordset insert, like this:
// required COM reference:
// Microsoft Office 14.0 Access Database Engine Object Library
var dbe = new Microsoft.Office.Interop.Access.Dao.DBEngine();
Microsoft.Office.Interop.Access.Dao.Database db = dbe.OpenDatabase(
#"C:\Users\Public\Database1.accdb");
Microsoft.Office.Interop.Access.Dao.Recordset rst = db.OpenRecordset(
"SELECT [Id], [Name] FROM [Cars] WHERE FALSE",
Microsoft.Office.Interop.Access.Dao.RecordsetTypeEnum.dbOpenDynaset);
rst.AddNew();
// new records are immediately assigned an AutoNumber value ...
string newReplId = rst.Fields["Id"].Value; // ... so retrieve it
// the returned string is of the form
// {guid {1D741E80-6847-4CB2-9D96-35F460AEFB19}}
// so remove the leading and trailing decorators
newReplId = newReplId.Substring(7, newReplId.Length - 9);
// add other field values as needed
rst.Fields["Name"].Value = "Pagani";
// commit the new record
rst.Update();
db.Close();
Console.WriteLine("New record added with [Id] = {0}", newReplId);
which produces
New record added with [Id] = 1D741E80-6847-4CB2-9D96-35F460AEFB19
You can try like this using the OUTPUT :
INSERT INTO myTable(myGUID)
OUTPUT INSERTED.myGUID
VALUES(GenGUID())
You can try like this:
string str1 = "INSERT INTO Cars(Name) VALUES ('Pagani')";
string str2 = "Select ##Identity";
int ID;
using (OleDbConnection conn = new OleDbConnection(connect))
{
using (OleDbCommand cmd = new OleDbCommand(str1, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
cmd.CommandText = str2;
ID = (int)cmd.ExecuteScalar();
}
}
When I want to update row with type 'date' in oracle database through asp.net C# method it gives the following error:
error:
ORA-00932: inconsistent datatypes: expected NUMBER got TIMESTAMP
code:
string query = String.Format("update mms_meetings m set m.end_date = :end_date where m.id = :id");
OracleCommand cmd = new OracleCommand("", GetDBConnection());
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
OracleParameter opId = new OracleParameter();
opId.DbType = DbType.Int32;
opId.Value = meetId;
opId.ParameterName = "id";
cmd.Parameters.Add(opId);
OracleParameter opDateEnd = new OracleParameter();
opDateEnd.DbType = DbType.DateTime;
opDateEnd.Value = dateEnd;
opDateEnd.ParameterName = "end_date";
cmd.Parameters.Add(opDateEnd);
cmd.ExecuteNonQuery();
cmd.Dispose();
CloseDBConnection();
1) You must send the exact format for your date as specified in your table column. Check default format for your date column. Like
'yyyy/MM/dd'
2) If you are using OleDb or ODBC Connection, they both use positional parameters so order of adding the parameters is very important. Try changing the order of your parameter to see if it helps.
I need to retrieve a value from a field in database. I have the used following code. but the value checkOrderId (which I need) shows the SQL string instead of the value from database. I don't know why it is doing so. Could somebody help me please?
string connectionString = "Data Source = xxyyzz;Initial Catalog = xyz; Integrated Security = True";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
string tableName = "[GIS].[SecondaryTraffic].[PotentialBackHauls]";
string checkOrderId = "Select TOP 1 OrderID From" + tableName + "ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
//cmd.ExecuteNonQuery();
OpenPop.Pop3.Pop3Client popConn = new OpenPop.Pop3.Pop3Client();
if (orderIdentity == checkOrderId)
{
popConn.DeleteMessage(messageNumber);
}
connection.Close();
I am new and dont have reputation to answer my question immediately. With everybody's help, i got this one solved...Great help, thanx everybody...following is my code.
string connectionString = "Data Source = EAEDEV;Initial Catalog = GIS; Integrated Security = True";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string tableName = "[GIS].[SecondaryTraffic].[PotentialBackHauls]";
string checkOrderId = "Select TOP 1 OrderID From " + tableName + " ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
string valueReturned = (string)cmd.ExecuteScalar();
OpenPop.Pop3.Pop3Client popConn = new OpenPop.Pop3.Pop3Client();
if (orderIdentity == valueReturned)
{
popConn.DeleteMessage(messageNumber);
}
connection.Close();
}
You need to execute the query and check the results, here you are just comparing a string with the query SQL.
Please see here
http://www.csharp-station.com/Tutorial/AdoDotNet/lesson03
for a tutorial.
Your expectation of the result being set into checkOrderId is incorrect. In this instance checkOrderId is just the query to execute and not the actual result.
You need to read the value back from executing the command:
using (var connection = new SqlConnection(connectionString))
using (var comm = new SqlCommand("Select TOP 1 OrderID From [GIS].[SecondaryTraffic].[PotentialBackHauls] ORDER BY InsertDate DESC", connection))
{
connection.Open();
object result = comm.ExecuteScalar(); // This is the key bit you were missing.
if (result != null)
{
// You can cast result to something useful
int orderId = (int)result;
}
} // Both comm and connection will have Dispose called on them here, no need to Close manually.
ExecuteScalar returns the value in the first cell (ie, column 1 row 1) as an object that you can cast to a better type (depending on what type it was in the result-set schema).
If you need to read multiple values, you need to look at ExecuteReader.
There are also other ways of doing this using output parameters, but that would pollute the point of the answer.
You can add space to your query
"Select TOP 1 OrderID From " + tableName + " ORDER BY InsertDate DESC";
Nota : I suggest you to use AddWithValue method with your parameter
string checkOrderId = "Select TOP 1 OrderID From #tableName ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
cmd.Parameters.AddWithValue("#tableName", tableName );
Link : http://msdn.microsoft.com/fr-fr/library/system.data.sqlclient.sqlparametercollection.addwithvalue.aspx
You don't actually run your command anywhere. Instead of the commented-out cmd.ExecuteNonQuery, you should look into the ExecuteScalar method, which allows you to read back a single result value from a query - which is what your query returns.
Add
int i = (Int32) cmd.ExecuteScalar();
right after
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
then the variable i will contain the order id
No, this is not correct. You are comparing the variable orderId to your query string. I doubt that's what you want to do. I imagine you'd be better off calling cmd.ExecuteScalar() to retrieve the actual OrderID value. As noted by other answers, your query string is missing a space. But most importantly, it is bad practice to construct SQL queries in code. Although I can't see a security issue with this code, if you continue to use this method you will probably write code that is vulnerable to SQL injection. I recommend you learn to either use parameters or LINQ to build your queries.
I'm trying to determine at runtime what the SqlDbType of a sql server table column is.
is there a class that can do that in System.Data.SqlClient or should I do the mapping myself? I can get a string representation back from
SELECT DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG = '{0}' AND TABLE_SCHEMA = '{1}'
AND TABLE_NAME = '{2}' AND COLUMN_NAME = '{3}'
EDIT: I can't use SMO as I have no control over the executing machine so I can't guarantee it will be installed. (Sorry for not making that clear rp).
EDIT: In answer to Joel, I'm trying to make a function that I can call that will return me a SqlDBType when passed a SqlConnection, a table name, and a column name.
In SQL Server you can use the FMTONLY option. It allows you to run a query without getting any data, just returning the columns.
SqlCommand cmd = connection.CreateCommand();
cmd.CommandText = "SET FMTONLY ON; select column from table; SET FMTONLY OFF";
SqlDataReader reader = cmd.ExecuteReader();
SqlDbType type = (SqlDbType)(int)reader.GetSchemaTable().Rows[0]["ProviderType"];
You can use enum System.Data.CommandBehavior as paramter for method SqlCommand.ExecuteReader(System.Data.CommandBehavior.KeyInfo):
SqlCommand cmd = connection.CreateCommand();
cmd.CommandText = "select column from table";
SqlDataReader reader = cmd.ExecuteReader(System.Data.CommandBehavior.KeyInfo);
SqlDbType type = (SqlDbType)(int)reader.GetSchemaTable().Rows[0]["ProviderType"];
This example looks like the example with using sql: SET FMTONLY ON; SET FMTONLY OFF. But you haven't to use SET FMTONLY. And in this case you don't
receive data from the table. You receive only metadata.
Old question, but if all you are trying to do is get from the string DATA_TYPE to the SqlDbType enum, the query presented in the original question combined with one line of code will do the trick:
string dataType = "nvarchar"; // result of the query in the original question
var sqlType = (SqlDbType)Enum.Parse(typeof(SqlDbType), dataType, true);
For SQL Server, use the SMO (SQL Server Management Objects).
http://www.yukonxml.com/articles/smo/
For example, you can use this code to traverse over all of the columns of a table.
Server server = new Server();
Database database = new Database( "MyDB" );
Table table = new Table( database, "MyTable" );
foreach ( Column column in table.Columns )
{
WriteLine( column.Name );
}
Here are all of the column properties available to you:
http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.column_members.aspx
If you are eventually going to read the data, you can do this:
SqlCommand comm = new SqlCommand("SELECT * FROM Products", connection);
using (SqlDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
Type type = reader.GetSqlValue(0).GetType();
// OR Type type = reader.GetSqlValue("name").GetType();
// yields type "System.Data.SqlTypes.SqlInt32"
}
}