Compare C# Date with SQL Date within a Query - c#

I'm trying to compare a C# DateTime with a SQL-server DateTime in a Stored Procedure but it keeps giving me convert-errors.
At first someone else made the Oracle function for this:
'Select blabla from bla WHERE (TO_DATE (''' + cast(#dateEnd as varchar(50)) + ''',''yyyy/mm/dd'') >= SPOT_ENDDAT)
And I'm trying to change this to SQL but in SQL you don't have the TO_DATE function.
Any ideas? Or should I make the changes at the level of my .net program itself? If yes, what should I do?
EDIT:
Calling my function Stored Procedure with this parameter :
DateTime EndDate = DateTime.Today;
ParamList.Add(new <class>.Parameter("EndDate", ParameterDirection.Input, EndDate, DbType.Date));
Stored Procedure:
ALTER PROCEDURE dbo.uspGetValues
#EndDate = null;
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL as NVARCHAR(4000)
Set #SQL = 'SELECT * FROM T_SPOTSHOP_DATA WHERE SPOT_ENDDATE IS NOT NULL'
if(#EndDate is not null)
Set #SQL = #SQL + 'AND (' + #EndDate +' <= SPOT_ENDDATE'
EXEC(#SQL)
Edit Solution:
For those who have the same problem I fixed it the other-way around. In C# I would used :
DateTime EndDate = DateTime.Today.toString(yyyy-MM-dd);
ParamList.Add(new <class>.Parameter("EndDate", ParameterDirection.Input, EndDate, DbType.Date));
and I catch it up in my stored procedure as:
EndDate Varchar(50)
SET #SQL = #SQL + 'WHERE CONVERT(DATETIME, '''+ #EndDate +''', 121) >= SPOT_ENDDATE
It's a quite ugly way to do it but it works. Hopes it helps you guys!

try this:
Select
blabla
from
bla
WHERE CAST(#dateEnd AS DATETIME) >= CAST(SPOT_ENDDAT AS DATETIME)

You can perform the conversion in T-SQL using CONVERT, but I wouldn't.
I would strongly recommend avoiding string conversions as far as possible. Just use parameterized SQL, and specify the parameter as a DateTime:
// Assuming dateEnd is a DateTime variable
string sql = "SELECT blabla FROM bla WHERE #dateEnd >= SPOT_ENDDAT";
using (var command = new SqlCommand(conn, sql))
{
command.Parameters.Add("#dateEnd", SqlDbType.DateTime).Value = dateEnd;
// Execute the command here
}
I'd do the equivalent for Oracle as well - unless your task really inherently involves converting between text and the "native" data type, don't do it.
Or use a LINQ provider of course, at which point you'll have a more readable query to start with :)

Just pass the .Net DateTime value as a parameter to the Sql Command. The database driver will handle the conversion to an Sql Server date time automatically.

Related

How to get Multiple OUTPUT parameters from stored procedure EF Core 3.1

I have been trying to modify the accepted answer here which seems to leverage RelationalDataReader in order to get back 2 OUTPUT parameters for some calculated dates from an API that the Product Owners wished to be as much database driven as possible.
I have a stored procedure that calculates begin and end dates from the SQL queries I have stored in a table so that all they have to to to add another date range is to add it to the table and the rest will fall into place on the UI and the rest of the pipeline.
The first part is the same for the RDFacadeExtensions class but I thought that I could simply add more parameters and get them back, but I seem to be missing something.
var ID = new SqlParameter("ID", 5)
{
Direction = ParameterDirection.Input,
DbType = DbType.Int32,
Size = 500
};
var _beginDate = new SqlParameter("BeginDate", "")
{
Direction = ParameterDirection.Output,
DbType = DbType.String,
Size = 500
};
var _endDate = new SqlParameter("EndDate", "")
{
Direction = ParameterDirection.Output,
DbType = DbType.String,
Size = 500
};
This all seems normal and then I do the following:
string begin;
string end;
var sql = $"exec [dbo].[GetDateRange] #ID, #BeginDate OUTPUT, #EndDate OUTPUT";
using (var dr = context.Database.ExecuteSqlQuery(sql, ID, _beginDate, _endDate))
{
while (dr.DbDataReader.Read())
{
var thing = dr.DbDataReader[0].ToString();
}
dr.DbDataReader.Close();
begin = _beginDate.Value.ToString();
end = _endDate.Value.ToString();
}
Before the end of the using I briefly get the first date but I never seem to be able to get the second date. I also have empty strings once the datareader is closed.
If it matters, my stored procedure is simply this:
#ID INT,
#BeginDate DATE OUTPUT,
#EndDate DATE OUTPUT
BEGIN
SET NOCOUNT ON;
DECLARE #Query1 NVARCHAR(1000)
DECLARE #Query2 NVARCHAR(1000)
SELECT #Query1 = BeginDate,
#Query2 = EndDate
FROM DateRange
WHERE ID = #ID
DECLARE #ParmDefinition1 NVARCHAR(50) = N'#BeginDateOUT DATE OUTPUT';
DECLARE #ParmDefinition2 NVARCHAR(50) = N'#EndDateOUT DATE OUTPUT';
EXEC sp_executesql #Query1, #ParmDefinition1, #BeginDateOUT = #BeginDate OUTPUT
EXEC sp_executesql #Query2, #ParmDefinition2, #EndDateOUT = #EndDate OUTPUT
END
Or perhaps my stored procedure is the issue. I get one date but can only hold it for a short time. The issue with sp_executesql is that it has to go to an OUTPUT parameter and I can't assign the result to anything but an INT variable. I need two dates from the stored code in the table.
If there is a way to do that and only return what essentially amounts to a small table result that would be ideal.
Thanks you any that can point me in the right direction.
So, at least in ADO, if you don't close your data reader you will never get back your output parameters.
In your sample this should suffice your needs:
string begin;
string end;
var sql = $"exec [dbo].[GetDateRange] #ID, #BeginDate OUTPUT, #EndDate OUTPUT";
using (var dr = context.Database.ExecuteSqlQuery(sql, ID, _beginDate, _endDate))
{
while (dr.DbDataReader.Read())
{
var thing = dr.DbDataReader[0].ToString();
}
dr.DbDataReader.Close();
begin = _beginDate.Value.ToString();
end = _endDate.Value.ToString();
}
However there is one interesting solution mentioned in here which seems to tackle exactly your pain point.
So it would appear I don't need to use sp_executesql nor do I require any OUT parameters.
So I changed the stored procedure to this and minor change to the underlying queries held in the table to remove the select within them to basically allow the construction of the sql within the stored procedure.
ALTER PROCEDURE [dbo].[GetDateRange]
#ID INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Query1 NVARCHAR(1000)
DECLARE #Query2 NVARCHAR(1000)
SELECT #Query1 = BeginDate, #Query2 = EndDate FROM DateRange WHERE ID = #ID
DECLARE #Test NVARCHAR(1000) = 'SELECT ' + #Query1 + ' AS BeginDate, ' + #Query2 + ' AS EndDate'
EXECUTE (#Test)
END
Then I was able to do the following with the existing code:
var ID = new SqlParameter("ID", 1)
{
Direction = ParameterDirection.Input,
DbType = DbType.Int32,
Size = 500
};
DataTable dates = new DataTable();
var sql = $"exec [dbo].[GetDateRange] #ID";
using (var dr = context.Database.ExecuteSqlQuery(sql, ID))
{
dates.Load(dr.DbDataReader);
}

Conversion failed when converting date and/or time from character string SQL Server stored procedure

While trying to execute the following procedure from a C# Winforms project I am getting the following error:
Conversion failed when converting date and/or time from character string
This is my stored procedure:
CREATE PROCEDURE DisplayTime
#name VARCHAR(50),
#fromdate date,
#todate date
AS
BEGIN
DECLARE #VTIME TIME(7)
SELECT
#VTIME = CAST(SUM(DATEDIFF(SECOND, 0, time)) /60/60 AS TIME)
+':'+CAST(SUM(DATEDIFF(SECOND, 0, time)) /60%60 AS TIME)
+':'+ CAST(SUM(DATEDIFF(SECOND, 0, time)) % 60 AS TIME)
FROM
(SELECT time
FROM time
WHERE [user] = '#name'
AND date BETWEEN '#fromdate' AND '#todate') AS T
SELECT #VTIME AS count_down_sec
END
This is my C# code:
private void button1_Click(object sender, EventArgs e)
{
if (txt_UserName.Text != "")
{
con.Open();
cmd = new SqlCommand("DisplayTime",con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#name", txt_UserName.Text);
cmd.Parameters.AddWithValue("#fromdate",dateTimePicker1.Value.Date);
cmd.Parameters.AddWithValue("#todate",dateTimePicker2.Value.Date);
cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show(txtTotal.Text);
}
}
Not sure what you are trying to do in this procedure. But, parameter names need not to be enclosed in single quotes unless you use
Execute(). Remove the quotes around #name, #fromdate and #todate
Also, you will need to come up with proper naming so that, other developers aren't confused with datatype name and column/table names.
CREATE PROCEDURE DisplayTime
#name VARCHAR(50),
#fromdate date,
#todate date
AS
BEGIN
DECLARE #VTIME TIME(7)
SELECT
#VTIME = CAST(SUM(DATEDIFF(SECOND, 0, time)) /60/60 AS TIME)
+':'+CAST(SUM(DATEDIFF(SECOND, 0, time)) /60%60 AS TIME)
+':'+ CAST(SUM(DATEDIFF(SECOND, 0, time)) % 60 AS TIME)
FROM
(SELECT time
FROM time
WHERE [user] = #name
AND date BETWEEN #fromdate AND #todate) AS T
SELECT #VTIME AS count_down_sec
END

String was not recognized as a valid DateTime, stored procedure empty parameter

I wrote a stored procedure in SQL Server. I have a parameter of type smalldatetime. I want to send this parameter blank when I run it with LINQ. When I want to send it, I get this error.
String was not recognized as a valid DateTime.
How can I send the date format blank?
C#, LINQ;
var query = ctx.onayListele(Convert.ToDateTime(dataList.olusturulmaTarihi)).ToList();
SQL:
ALTER PROCEDURE [dbo].[onayListele]
#in_olusturmaTarihi smalldatetime = NULL
AS
BEGIN
SELECT
Onay.onayID, alep.olusturulmaTarihi, TalepTuru.talepTuruAdi,
TalepDurumu.talepDurumuAciklamasi
FROM
Onay
WHERE
(#var_olusturmaTarihi IS NULL OR
CONVERT(DATE, Talep.olusturulmaTarihi) = CONVERT(DATE, #var_olusturmaTarihi))
END
At first, I thought you needed to change your stored procedure.
Now that I've read the question again, I've realized that the error message comes from the c# side, not from the stored procedure (that I still think you should change).
Attempting to convert a null or empty string to DateTime will result with the error in your question. To avoid that, you need to make sure the string can in fact be converted to DateTime before sending it to the stored procedure:
DateTime datetime;
DateTime? olusturulmaTarihi = null;
if(DateTime.TryParse(dataList.olusturulmaTarihi, out datetime))
{
olusturulmaTarihi = (DateTime?)datetime;
}
var query = ctx.onayListele(olusturulmaTarihi).ToList();
This way, you will send null to the stored procedure if the string can't be parsed as DateTime, and avoid the error.
As to the stored procedure, I would suggest writing it like this instead:
ALTER PROCEDURE [dbo].[onayListele]
#in_olusturmaTarihi date = NULL
AS
BEGIN
SELECT Onay.onayID,
alep.olusturulmaTarihi,
TalepTuru.talepTuruAdi,
TalepDurumu.talepDurumuAciklamasi
FROM Onay
WHERE #var_olusturmaTarihi IS NULL
OR CONVERT(date,Talep.olusturulmaTarihi) = #var_olusturmaTarihi
END
Please note that if you have an index on Talep.olusturulmaTarihi, this stored procedure will not be able to use it. In that case, you better use something like this instead:
ALTER PROCEDURE [dbo].[onayListele]
#in_olusturmaTarihi date = NULL
AS
BEGIN
SELECT Onay.onayID,
alep.olusturulmaTarihi,
TalepTuru.talepTuruAdi,
TalepDurumu.talepDurumuAciklamasi
FROM Onay
WHERE #var_olusturmaTarihi IS NULL
OR
(
Talep.olusturulmaTarihi >= CAST(#var_olusturmaTarihi as datetime) -- or whatever the data type of the column is
AND Talep.olusturulmaTarihi < DATEADD(DAY, 1, CAST(#var_olusturmaTarihi as datetime)) -- or whatever the data type of the column is
)
END

C# web service convert string to DateTime and insert into SQL

Been trying to insert a date, along with some other string data, into SQL via C#, as such:
OperationResponse ICommon.addUser(userRequest request)
{
int? result = 0;
Guid countryGUID;
string requestParent = request.parent;
string requestName = request.name;
string requestSchool = request.school;
int requestGender = request.gender;
DateTime dateTimeDOB = DateTime.ParseExact(request.DOB, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture);
string requestEmail = request.email;
string requestMobile = request.mobile;
Guid.TryParse(request.countryID, out countryGUID);
string requestInstitution = request.institution;
try
{
result = s2u.AddUser(request.parent, request.name, request.school, request.gender, dateTimeDOB, request.email, request.mobile, countryGUID, request.institution);
}
catch (Exception ex)
{
if (isDebug() == true)
{
return new OperationResponse(ex.Message);
}
else
{
return new OperationResponse("Error: Database inaccessible.");
}
}
if (result == 1)
{
return new OperationResponse();
}
else
{
return new OperationResponse("Error: User could not be added.");
}
}
However whenever I try to run it in Fiddler it's been unsuccessful thus far, since the result always ends up being -1.
I suspect this may have something to do with the DOB not being inserted correctly, but I can't be sure. The request.DOB that I'm trying to parse is a string, the DOB column in the SQL table has the date datatype, and I'm trying to pass in dates in the format of "yyyy-MM-dd", but on the C# side I have to pass in the time too, being 12.00.00 AM by default. I don't know if this is causing problems. Any help is appreciated, and I'll provide further details if needed.
EDIT: The AddUser stored procedure is as such:
ALTER PROCEDURE [dbo].[AddUser]
-- Add the parameters for the stored procedure here
#parent nvarchar(300),
#name nvarchar(300),
#school nvarchar(500),
#gender int,
#DOB datetime2(7),
#email nvarchar(500),
#mobile nvarchar(20),
#countryID uniqueidentifier,
#institution nvarchar(500)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO [dbo].[Users] ([parent], [name], [school], [gender], [DOB], [email], [mobile], [countryID], [institution])
VALUES (#parent, #name, #school, #gender, #DOB, #email, #mobile, #countryID, #institution);
END
Check your string date time is in correct format or not. I believe it's not in correct format.
Moreover, why didn't you use the following method?
DateTime dt = Convert.ToDateTime(dateTime);
With EF, datetime is mostly handle as a datetime2 type, so it won't make much difference or cause any trouble.
In addition, write transaction handles in stored procedure with try & catch and try to find out if sp is giving any problems or not.

Stored procedure not running correctly with dynamic sql text

For some reason my stored procedure is executed without any error from the code-behind in C# but it is not deleting anything at all that the stored procedure has written. I have all the correct parameters and everything. I ran the query from SQL Server with all the same parameters from the C# code and it works perfectly. I don't get why it works when I run from SQL Server but it doesn't work when I run it from my C# code in Visual Studio.
Here is my C# code that is passing the data through to the stored procedure.
string reportType = "PostClaim";
string GRNBRs = "925','926','927";
string PUNBRs = "100','100','100";
string beginningDates = "20120401";
string endDates= "20120430";
try
{
conn = new SqlConnection(ConnectionInfo);
conn.Open();
SqlDataAdapter da = new SqlDataAdapter("RemoveReport", conn);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("#ReportType", reportType);
da.SelectCommand.Parameters.AddWithValue("#GRNBR", GRNBRs);
da.SelectCommand.Parameters.AddWithValue("#PUNBR", PUNBRs);
da.SelectCommand.Parameters.AddWithValue("#DATE1", beginningDates);
da.SelectCommand.Parameters.AddWithValue("#DATE2", endDates);
da.SelectCommand.CommandTimeout = 360;
}
catch (SqlException ex)
{
//something went wrong
throw ex;
}
finally
{
if (conn.State == ConnectionState.Open)
conn.Close();
}
Here is my stored procedure. It's executing with dynamic SQL text.
ALTER PROCEDURE [dbo].[RemoveReport] (
#ReportType NVARCHAR(20),
#GRNBR VARCHAR(4000),
#PUNBR VARCHAR(4000),
#DATE1 DATETIME,
#DATE2 DATETIME
)
AS
DECLARE #SQLTEXT VARCHAR(4000)
BEGIN
SET #SQLTEXT = 'DELETE FROM TestingTable
WHERE Report='''+#ReportType+''' AND
PUNBR IN ('''+#PUNBR+''') AND
[Group] IN ('''+#GRNBR+''') AND
StartedAt BETWEEN '''+CONVERT(VARCHAR(10),#DATE1,121)+'''
AND '''+CONVERT(VARCHAR(10),#DATE2,121)+''''
PRINT #SQLTEXT <---I'll print this out to show you what exactly it is executing.
EXECUTE (#SQLTEXT)
END
Here is what the PRINT #SQLTEXT is running:
DELETE FROM MonthlyReportSchedule
WHERE Report='PostClaim' AND
PUNBR IN ('100','100','100') AND
[Group] IN ('925','926','927') AND
StartedAt BETWEEN '2012-04-01' AND '2012-04-30'
When I actually go into SQL Server to run this query, it works perfectly. But why does it not work on when executed from the C# code. Any help?
Avoid concatenating parameters to your sql, use parameterised query,
Try this...
Just noticed that you have some comma delimited lists in params.....
ALTER PROCEDURE [dbo].[RemoveReport]
#ReportType NVARCHAR(20),
#GRNBR VARCHAR(4000),
#PUNBR VARCHAR(4000),
#DATE1 DATETIME,
#DATE2 DATETIME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQLTEXT NVARCHAR(MAX);
Declare #GRNBR_xml xml,#PUNBR_xml xml;
SET #GRNBR_xml = N'<root><r>' + replace(#GRNBR, ',','</r><r>') + '</r></root>';
SET #PUNBR_xml = N'<root><r>' + replace(#PUNBR, ',','</r><r>') + '</r></root>';
SET #SQLTEXT = N'DELETE FROM TestingTable
WHERE Report = #ReportType
AND PUNBR IN (select r.value(''.'',''varchar(max)'') as item
from #PUNBR_xml.nodes(''//root/r'') as records(r))
AND [Group] IN (select r.value(''.'',''varchar(max)'') as item
from #GRNBR_xml.nodes(''//root/r'') as records(r))
AND StartedAt BETWEEN #DATE1 AND #DATE2'
EXECUTE sp_executesql #SQLTEXT
,N'#ReportType NVARCHAR(20) , #GRNBR_xml xml,
#PUNBR_xml xml,#DATE1 DATETIME,#DATE2 DATETIME'
,#ReportType
,#GRNBR_xml
,#PUNBR_xml
,#DATE1
,#DATE2
END
Note
Make sure you pass the comma delimited list as 925,926,927 and not as '925','926','927'
Try adding this line in order to be executed
da.SelectCommand.ExecuteNonQuery();
This will execute a call to your stored procedure.
good luck

Categories