Problems with sending DateTime to SQL Table - c#

I'm writing WinForms code in C# and basically have the following:
DateTime localDate = DateTime.UtcNow;
SqlConnection Conn = new SqlConnection("....[connection info]....");
Conn.Open();
SqlCommand sqlcomm = new SqlCommand("INSERT INTO dbo.Call VALUES(...., #Time,...);", Conn);
sqlcomm.Parameters.Add("#Time", SqlDbType.DateTime);
sqlcomm.Parameters["#Time"].Value = localDate;
Int32 o = sqlcomm.ExecuteNonQuery();
This throws an error of "When converting a string to DateTime, parse the string to take the date before putting each variable into the DateTime object." From what I gather, it thinks the localDate variable is a string but if I write to the console localDate.GetType() it says System.DateTime.
The column for "#Time" in the database is set up to DateTime, so that's not the issue. Any thoughts?

You're almost there. for Sql Server think among these lines
select cast(getdate() as time)
Problem is that in .net there is no such type as time, so you need to adapt
SqlCommand sqlcomm = new SqlCommand(
"INSERT INTO dbo.Call VALUES(...., cast(#Time as time),...);", Conn);
sqlcomm.Parameters.AddWithValue("#Time", localDate);
this is all you should need. Although, I think, you may not even need to add cast as DB engine itself will try cast it. The problem, I think, that you explicitly said your type SqlDbType.DateTime. But if you use AddWithValue, provider will do things for you.
since #Frédéric mentioned TimeSpan, you can try this as well
sqlcomm.Parameters.AddWithValue("#Time", localDate.TimeOfDay);
' and no cast(#Time as time)

The UTC format is not an sql date time format whuch you specified in the parameters.add
In the past I have formatted the utc time to that of yyyy-MM-dd.

Given this table schema:
create table dbo.call_history
(
id int not null identity(1,1) primary key clustered ,
my_date date null ,
my_time time null ,
my_datetime datetime null ,
)
This code works just fine:
using ( SqlConnection conn = new SqlConnection( connectString ) )
using ( SqlCommand cmd = conn.CreateCommand() )
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = #"
insert dbo.call_history ( my_date , my_time , my_datetime )
values ( #pDate , #pDate , #pDate )
select scope_identity()
";
cmd.Parameters.AddWithValue( "#pDate" , DateTime.UtcNow );
conn.Open();
// double downcast required herebecause scope_identity()
// returns numeric(38,0) which gets mapped to decimal
int id = (int)(decimal) cmd.ExecuteScalar() ;
conn.Close();
}

Related

Stored Procedure, Passing Array of Dates, comma delimited. Conversion Error

I am trying to send a comma delimited string of dates to my stored procedure, to be used in an IN clause.
However, I am getting the error "Conversion failed when converting date and/or time from character string."
I am trying to use these dates to find prices that match.
C#:
StringBuilder LastDaysOfEveryMonth = new StringBuilder();
DataAccess da = new DataAccess();
SqlCommand cm = new SqlCommand();
cm.CommandType = CommandType.StoredProcedure;
var pList = new SqlParameter("#DateList", DbType.String);
pList.Value = LastDaysOfEveryMonth.ToString();
cm.Parameters.Add(pList);
...
cm.CommandText = "spCalculateRollingAverage";
DataSet ds = da.ExecuteDataSet(ref cm);
When debugging it, the value of the passed string is :
'2013-07-31','2013-08-30','2013-09-30','2013-10-31','2013-11-29','2013-12-31',
'2014-01-31','2014-02-28','2014-03-31','2014-04-03',
with the DbType String and SQLDbType NvarChar.
Any advice would be much appreciated!
SQL:
CREATE PROCEDURE [dbo].[spCalculateRollingAverage]
#StartDate DateTime,
#EndDate DateTime,
#Commodity nvarchar(10),
#PeakType nvarchar (10),
#BaseID int,
#NumberOfMonths int,
#DateList nvarchar(MAX)
AS
BEGIN
select TermDescription,ContractDate,Price,SortOrder into #tbtp from BaseTermPrice
inner hash join Term
on
Term.TermID = BaseTermPrice.TermID
where
BaseID = #BaseID and ((#PeakType IS NULL and PeakType is null) or
(#PeakType IS NOT NULL and PeakType=#PeakType))
and ((#DateList IS NULL and ContractDate between #StartDate and #EndDate)
or (#StartDate IS NULL and ContractDate in (#DateList)))
order by
ContractDate,SortOrder
You cannot use a varchar variable in an IN clause like this. You have to either add it to a dynamic SQL to execute, or - split it into temp table/temp variable.
For example using this SplitString function you can do something like this:
or (#StartDate IS NULL and ContractDate in
(SELECT Name from dbo.SplitString(#DateList))))

Scope_Identity not working with GUID on c#

I've been trying to insert some data on a database and at the same time get the identifier.
The identifier type is a Guid.
I already tried some resolutions.
I was searching but I couldn't found any that worked with a Guid in C#.
The last one I tried was like this:
dbAccess db = new dbAccess();
SqlConnection con = db.openConnection();
Guid retVal = Guid.Empty;
try
{
SqlCommand cmd = new SqlCommand(#"insert into Comment(IdDiscussion,UserId,Description,DateTime)
values(#IdDiscussion,#UserId,#description,#dateTime);
set #ret=SCOPE_IDENTITY();", con);
cmd.Parameters.AddWithValue("#IdDiscussion", discussionId);
cmd.Parameters.AddWithValue("#UserId", userId);
cmd.Parameters.AddWithValue("#description", comment);
cmd.Parameters.AddWithValue("#dateTime", dateTime);
SqlParameter retParameter = new SqlParameter("#ret", SqlDbType.UniqueIdentifier);
retParameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(retParameter);
cmd.ExecuteNonQuery();
retVal = (Guid)retParameter.Value;
}
catch (Exception e)
{
//doesn't really matter
}
db.closeConnection();
return retVal;
In this case I get the following error on executeNonQuery(): "Operand type clash: numeric is incompatible with uniqueidentifier".
Any suggestion that can help?
scope_identity() only returns the last (scoped) identity value - this value datatype has to be numeric.
So unfortunetly only fix that comes to my mind would be something like this:
declare #op table
(
ColGuid uniqueidentifier
)
insert into Comment(IdDiscussion,UserId,Description,DateTime)
output inserted.CommentId -- GUID column
into #op
values (#IdDiscussion,#UserId,#description,#dateTime)
select top 1 o.ColGuid
from #op o
and then in your code:
var guid = (Guid)cmd.ExecuteScalar();
One more mention: this solution should work in SQL Server 2005 and above
I tried to use SCOPE_IDENTITY() to retrieve Guid values, but not worked with me. You can try declare a SQL variable and generate a new guid with the command NEWID() and in the end do a SELECT command in this variable executing ExecuteScalar method on the command object.
DECLARE #Id UNIQUEIDENTIFIER; SET #Id = NEWID();
INSERT INTO [tablename] ([Id], [Field1], [Field2]) VALUES (#Id, #Field1, #Field2);
You must add your parameters on the command normally.
cmd.Parameters.AddWithValue("#Field1", "Field 1 Value");
cmd.Parameters.AddWithValue("#Field2", "Field 2 Value"));
So, execute and retrieve the value.
var obj = cmd.ExecuteScalar();
Guid guid = (Guid)obj;

DateTime from .NET to smalldatetime in SQL - how to do queries?

I have a DateTime component in my code, and I want to use it for a query in my SQL Server database.
When inserting this component, there seems to be no problem, but when querying for smalldatetime values, I just don't know how to do it. The dataset is always empty.
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "ReadDates";
dataset = new DataSet();
SqlParameter parameter = new SqlParameter("#date", SqlDbType.SmallDateTime);
parameter.Value = DateTime.Now();
cmd.Parameters.Add(parameter);
dataAdapter = new SqlDataAdapter(cmd);
dataAdapter.Fill(dataset);
return dataset;
And this is in my stored procedure:
select * from TableDates
where ValueDate <= #date
So I have no problems running the procedure in SQL Server Management Studio, when entering a parameter in this format: '2000-03-03 04:05:01', but when passing a DateTime, the query is always empty. Any suggestions?
I tried it by using SQL Server 2008 R2 Express.
Here is the example stored procedure i wrote:
CREATE PROCEDURE [dbo].[ShowGivenSmallDateTimeValue]
#givenSmallDateTime smalldatetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Simply return the given small date time value back to sender.
SELECT #givenSmallDateTime
END
And here is the C# code to execute the procedure:
var connectionBuilder = new SqlConnectionStringBuilder();
connectionBuilder.DataSource = "localhost\\sqlexpress";
connectionBuilder.IntegratedSecurity = true;
var now = DateTime.UtcNow;
using (var connection = new SqlConnection(connectionBuilder.ConnectionString))
using (var command = new SqlCommand())
{
command.Connection = connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "ShowGivenSmallDateTimeValue";
command.Parameters.Add(new SqlParameter("#givenSmallDateTime", SqlDbType.SmallDateTime) { Value = now });
connection.Open();
var result = (DateTime)command.ExecuteScalar();
var difference = result - now;
Console.WriteLine("Due to the smalldatetime roundings we have a difference of " + difference + ".");
}
And it simply works.
Here's my code for creating the SqlParameter for a Datetime; For SQL Server 2008 we pass the value as datetime2 since SQL will implicity convert from datetime2 to every other date type so long as it is within the range of the target type...
// Default conversion is now DateTime to datetime2. The ADO.Net default is to use datetime.
// This appears to be a safe change as any datetime parameter will accept a datetime2 so long as the value is within the
// range for a datetime. Hence this code is acceptable for both datetime and datetime2 parameters, whereas datetime is not
// (because it doesn't handle the full range of datetime2).
SqlParameter sqlParam = new SqlParameter(name, SqlDbType.DateTime2);
Since Your parameter includes zeros in day and month parts...sql server converts it but doest match to your date.... i.e.,
if DATETIME.now() returns '2000-03-03 04:05:01'... it is casted into 2000-3-3 Without including zeros...so u need to specify zeros also to match your date.

compare DateTime in SqlCommand

I have a simple SqlCommand in which I want to return all records within a specified DateTime range. (both Date and Time are involved)
var dataReader = new SqlCommand(
#"Select RecordID from RecordTable
where RecordTable.WorkingDT between '"+ _startDt +"' and '"+ _endDt +"'",
_sqlConnection).ExecuteReader();
how do I have to set the values for _startDt and _endDt?
You can try this:
var dataReader = new SqlCommand(
#"Select RecordID from RecordTable
where RecordTable.WorkingDT between '"+ _startDt.ToString("yyyy-MM-dd HH:mm:ss") +"' and '"+ _endDt.ToString("yyyy-MM-dd HH:mm:ss") +"'",
_sqlConnection).ExecuteReader();
Where _startDt and _endDt are type of DateTime.
If you add them as proper parameters in your command, you don't need to worry about formatting. The added benefit of getting into the habit of using these is that you don't have to worry about SQL injection when you were to supply strings as parameters.
Have a look at http://www.csharp-station.com/Tutorial/AdoDotNet/lesson06
It shows how to use parameters in your queries. I don't think it needs to be spelled out completely.
An example (copy/pasted from the site):
// 1. declare command object with parameter
SqlCommand cmd = new SqlCommand(
"select * from Customers where city = #City", conn);
// 2. define parameters used in command object
SqlParameter param = new SqlParameter();
param.ParameterName = "#City";
param.Value = inputCity;
// 3. add new parameter to command object
cmd.Parameters.Add(param);
// get data stream
reader = cmd.ExecuteReader();
And yes, defining the parameters can be done shorter that 3 lines per parameter. But that's left up to the reader.
#kmatyaszek, While commonly used, the "yyyy-mm-dd HH:mm:ss" date format is not guaranteed to be unambiguously parsed by SQL server. If you must create SQL from concatenating strings (not necessary in this case as René has shown) then you should use the ISO8601 format, which is just the same but with a T in the middle: "yyyy-mm-ddTHH:mm:ss".
http://msdn.microsoft.com/en-us/library/ms190977%28v=sql.90%29.aspx
"The advantage in using the ISO 8601 format is that it is an
international standard. Also, datetime values that are specified by
using this format are unambiguous. Also, this format is not affected
by the SET DATEFORMAT or SET LANGUAGE settings."
For a demonstration why, try this rerunnable Sql script.
if object_id('tempdb..#Foo') is not null drop table #Foo;
create table #Foo(id int, d datetime)
-- Intend dates to be 12th Jan.
set dateformat ymd
insert into #Foo(id, d) values (1, '2012-01-12 01:23:45') -- ok
insert into #Foo(id, d) values (2, '2012-01-12T01:23:45') -- ok
set dateformat ydm
insert into #Foo(id, d) values (3, '2012-01-12 01:23:45') -- wrong!
insert into #Foo(id, d) values (4, '2012-01-12T01:23:45') -- ok
select * from #Foo order by id
if object_id('tempdb..#Foo') is not null drop table #Foo;

Displaying Date (c# winforms)

I have a SQL Table with the following columns:
PROFILE
----------------------------------
Name | DateOfBirth | Address | ID
----------------------------------
| | |
| | |
[Name] is a required field while the ID is an autoincrement column.
The remaining fields are not required.
When it comes to displaying again the information of a user in my form, since the DateOfBirth field is not required I always got this value in my textBox 1900-01-01 00:00:00.000 even if it not supplied upon registration.
What I'm trying to accomplish is to display an empty string inthe textBox if the there's no date of birth.
With my naive way of thinking, I wrote a method where it checks first the DateOfBirth column, if it is null, it will return an empty string, else, return the date of birth as a string ex. txtDateOfBirth.Text = GetDateOfBirth();
but it always return the value `1900-01-01 00:00:00.000' cause the field in the database always inserts this value even the user leaves this field as blank.
Can you please help me... thanks...
I also tried this but still don't work:
SELECT BIRTHDATE = CASE BIRTHDATE
WHEN CAST('1900-01-01' AS DATETIME) THEN ''
ELSE BIRTHDATE END
FROM USER
My psychic debugging skills tell me that you're mistakenly setting the birthdate when you insert the row. A good check for that is to hook up a profiler (one comes with SQL Server, if that's what you're using), and watch what's actually getting inserted when you create a new user.
Check the code that's inserting a new user. If you're using DataSets, for instance, check that you don't have a default constraint set on the Birthdate column (click on the cell in the DataSet designer, and check the Properties grid).
It's also possible that the database itself has a default constraint set on that column, but that feels less likely.
Any reason why you don't want to do this?
string theDate = GetDateOfBirth().ToString();
txtDateOfBirth.Text = theDate == "1900-01-01 00:00:00.000" ? "" : theDate;
I got it already! :)
Here's my original code:
protected void SaveUser()
{
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlCommand cmd = new SqlCommand("INSERT_USER");
cmd.Parameters.Add(new SqlParameter("#NAME", txtName.Text.Trim()));
cmd.Parameters.Add(new SqlParameter("#ADDRESS", txtAddress.Text.Trim()));
cmd.Parameters.Add(new SqlParameter("#DATEOFBIRTH", txtDateOfBirth.Text.Trim()));
cmd.Connection = conn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
}
In my original code, even though txtDateofBirth is empty, it will always pass an empty string to the parameter causing the database to insert '1900-01-01 00:00:00.00', not the NULL value. Here's the modified code. I check first if txtDateOfBirth is not empty (assuming the value entered is a valid date) if true, add cmd.Parameters.Add(new SqlParameter("#DATEOFBIRTH", txtDateOfBirth.Text.Trim())); as a parameter to INSERT_USER stored procedure. Else, #DATEOFBIRTH parameter is not being created and passed at all.
protected void SaveUser()
{
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlCommand cmd = new SqlCommand("INSERT_USER");
cmd.Parameters.Add(new SqlParameter("#NAME", txtName.Text.Trim()));
cmd.Parameters.Add(new SqlParameter("#ADDRESS", txtAddress.Text.Trim()));
if(txtDateOfBirth.Text.Trim() != String.Empty)
{
cmd.Parameters.Add(new SqlParameter("#DATEOFBIRTH", txtDateOfBirth.Text.Trim()));
}
cmd.Connection = conn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
}
SP:
CREATE PROCEDURE [dbo].[INSERT_USER]
(
#NAME AS VARCHAR(25),
#ADDRESS AS VARCHAR(50) = NULL,
#DATEOFBIRTH AS DATETIME = NULL
)
AS
BEGIN
INSERT INTO [USER] ([NAME], ADDRESS, DATEOFBIRTH) VALUES (#NAME, #ADDRESS, #DATEOFBIRTH)
END

Categories