I am trying to generate a sql statement to be used in Oracle11g, using linq.
The problem arises when using dates:
C# code:
DateTime convertedMinStartDateForEvent = Convert.ToDateTime(minStartDateForEvent);
DateTime convertedMinEndDateForEvent = Convert.ToDateTime(minEndDateForEvent);
var query = (from myTableRec in uow.myTable
where myTableRec.startdate >= convertedMinStartDateForEvent && myTableRec.endDate < convertedMinEndDateForEvent
The SQL generated by linq gives
SELECT *
FROM <table>
WHERE start_date > '24/11/2012 00:00:00' and end_date < '28/11/2012 00:00:00'
This causes an oracle error: ORA-01830 - date format picture ends before converting entire input string
Adding TO_DATE to the query fixes the ORA-01830, as it is converting the string to a oracle date whilst now knowing the date format.
SELECT *
FROM <table>
WHERE start_date > TO_DATE('24/11/2012 00:00:00','DD/MM/YYYY HH24:MI:SS') and end_date < TO_DATE('28/11/2012 00:00:00','DD/MM/YYYY HH24:MI:SS')
So, is there a way to add TO_DATE to LINQ (for oracle)?
If not, please tell me how to work around this issue.
Thanks
I have no idea whether this will actually work, but this is what I'd try:
var query = from myTableRec in uow.myTable
where myTableRec.startdate >= convertedMinStartDateForEvent.Date
&& myTableRec.endDate < convertedMinEndDateForEvent.Date
(I've edited the query to refer to myTableRec - I suspect the code you posted wasn't your real code.)
You may even want to add the Date part to all references:
var query = from myTableRec in uow.myTable
where myTableRec.startdate.Date >= convertedMinStartDateForEvent.Date
&& myTableRec.endDate.Date < convertedMinEndDateForEvent.Date
Hopefully this will add the appropriate TO_DATE calls to the generated SQL. I agree with the comment that this sounds like a bug in the LINQ provider though.
Related
Following SQL query works fine (Give expected results) in SQL Server.
SELECT * FROM ImportedReportDataCRR IRD
INNER JOIN ImportedReport IR ON IRD.ImportedReportId = IR.Id
WHERE
IR.StartDate >= CONVERT(DATETIME, '7/1/2022 12:00:00 AM') AND IR.EndDate <= CONVERT(DATETIME, '7/31/2022 11:59:59 PM')
But when I use equivalent Linq (C# / ASP.Net) its not working as expected (Empty result set returned).
My Linq statement is
var ImportedReportDataList = DbContext.ImportedReportDataCRRs.Where(w =>
(w.ImportedReport.StartDate.Value >= StartDate && w.ImportedReport.EndDate.Value <= EndDate)).ToList();
-- Update Starts --
Linq converts into following SQL query
exec sp_executesql N'SELECT
[Extent1].*
FROM
[dbo].[ImportedReportDataCRR] AS [Extent1]
INNER JOIN [dbo].[ImportedReport] AS [Extent2] ON [Extent1].[ImportedReportId] = [Extent2].[Id]
WHERE
([Extent2].[StartDate] >= #p__linq__0) AND
([Extent2].[EndDate] <= #p__linq__1)',N'#p__linq__0 datetime2(7),#p__linq__1 datetime2(7)',#p__linq__0='2022-07-01 00:00:00.0010000',#p__linq__1='2022-07-31 23:59:59.9970000'
i.e. Linq is converting StartDate and EndDate into datetime2(7) which is creating issue.
-- Update Ends --
Variable StartDate = 7/1/2022 12:00:01 AM
Variable EndDate = 7/31/2022 11:59:59 PM
ImportedReport.StartDate = 2022-07-01 00:00:00.000 (DB field value)
ImportedReport.EndDate = 2022-07-31 00:00:00.000 (DB field value)
As mentioned in the comments, don't try to simulate BETWEEN where you find the end of a date range. This is problematic because different data types consider the "end" of a period differently. In this case, much better to say "greater than or equal to the first of July, and less than the first of August." Also using non-regional and unambiguous date formats:
SELECT <cols>
FROM dbo.ImportedReportData AS IRD
INNER JOIN dbo.ImportedReport AS IR ON IRD.ImportedReportId = IR.Id
WHERE IR.StartDate >= '20220701'
AND IR.EndDate < '20220801'
AND IRD.EmployeeName = 'test';
Please read all of the links at Dating Responsibly.
I suppose in Linq you could say:
&& w.ImportedReport.EndDate.Value
< { whatever you do in Linq to add a day to EndDate }
I have table that the value of dateime is like this
2021-12-08 10:10:54.657
2021-12-08 10:10:41.567
2021-12-08 10:09:51.960
2021-12-08 10:10:54.657
2021-12-08 10:10:41.567
2021-12-08 10:09:51.960
2021-12-08 10:10:54.657
and I want to get that day or today (now is 8 dec 2021) . So i have tried using EF in controller :
ViewBag.CByUserToday = _db.ArrayDatas.Where(a => a.CreatedBy == user && a.CreatedDate == DateTime.Today.Date).Count();
But i still did not get the rows. When i tried to debug DateTime.Today.Date , it's said DateTime.Today = {09/12/2021 00:00:00} . But when i tried to update that createddate to '2021-12-09 00:00:00.000' it can be retrieved.
So, how to retrieve that rows that i have created today(ignoring the time) ?
Check that the column is greater than or equal to today, and less than tomorrow:
DateTime today = DateTime.Today;
DateTime tomorrow = today.AddDays(1);
ViewBag.CByUserToday = _db.ArrayDatas
.Where(a => a.CreatedBy == user
&& a.CreatedDate >= today
&& a.CreatedDate < tomorrow)
.Count();
That way, your DBMS will be able to use a suitable index on the CreatedBy and CreatedDate columns to satisfy your query.
It's usually preferable to avoid calling functions on a column when you're trying to filter it, since this means the query is not SARGable. However, according to this thread on DBA, casting a datetime/datetime2 column to date is SARGable, at least in Microsoft SQL Server.
I have a table with two columns like BookingArrivedEnquiredTime with varchar datatype and datetime BookingArrivedEnquiredDateTime. When I execute this query in SQL Server the result give perfect with time sorted order
the sql query will be like
select BookingArrivedEnquiredTime from BookingArriveds where BookingArrivedEnquiredDateTime='2015-02-17 00:00:00.000'
order by CAST(('01/01/2000 ' + BookingArrivedEnquiredTime) AS DATETIME)
and it gives out put like this
11:27 AM
11:47 AM
11:53 AM
12:13 PM
12:50 PM
02:02 PM
02:47 PM
03:04 PM
03:16 PM
When i try this query into using linq
public ViewResult Index1(DateTime? Startdate)
{
Startdate = DateTime.Now.Date;
var fm = DateTime.Parse("01/01/2000");
var qr = from item in db.BookingArriveds
where item.BookingArrivedEnquiredDateTime == Startdate
orderby DateTime.Parse("01/01/2000 " +
item.BookingArrivedEnquiredTime.ToString())
select item;
return View(qr);
}
but it gives error like this
LINQ to Entities does not recognize the method 'System.DateTime Parse(System.String)' method, and this method cannot be translated
into a store expression.
where is wrong and I need help for how to rewrite above sql query to linq query also casting from varchar to datetime in linq?
As others have answered, this breaks because .ToString fails to translate to relevant SQL on the way into the database.
However, Microsoft provides the SqlFunctions class that is a collection of methods that can be used in situations like this.
For this case, what you are looking for here is SqlFunctions.StringConvert:
public ViewResult Index1(DateTime? Startdate)
{
Startdate = DateTime.Now.Date;
var fm = DateTime.Parse("01/01/2000");
var qr = from item in db.BookingArriveds
where item.BookingArrivedEnquiredDateTime == Startdate
orderby SqlFunctions.StringConvert("01/01/2000 " +
item.BookingArrivedEnquiredTime.ToString())
select item;
return View(qr);
}
Good when the solution with temporary variables is not desirable for whatever reasons.
You have two options:
you can do the casting and sorting on client:
db.BookingArriveds
.Where(item => item.BookingArrivedEnquiredDateTime == Startdate)
.AsEnumerable()
.OrderBy(item => DateTime.Parse("01/01/2000 " + item.BookingArrivedEnquiredTime);
or you can use SqlFunctions.DatePart to do the cast in Sql server: https://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions(v=vs.110).aspx
EDIT: DatePart function is not suitable, because it gives you only date part. To do the casting in SQL server, you should define your own sql function: https://msdn.microsoft.com/en-us/library/vstudio/dd456847(v=vs.100).aspx
The question is, why are you storing BookingArrivedEnquiredTime in a varchar column. I believe it should be part of BookingArrivedEnquiredDateTime or it should be stored as integer or numeric column
I have the following piece of code in C# that I use to select some rows from a SQL Server table based on a date criteria.
DateTime From, DateTime To
SqlParameter[] oParam = new SqlParameter[3];
oParam[0] = new SqlParameter("#From", From.Date);
oParam[1] = new SqlParameter("#To", To.Date);
DataTable dt = clsDatabaseHistory.ExecuteReader("SELECT * FROM tblHistory WHERE Date_Requested BETWEEN #From and #To", oParam);
If for example From=18/08/2011 and To=18/08/2011 and there is data in the table tblHistory that has the Date_Requested value as 18/08/2011 the query does not return it.
But if I change the value of To from 18/08/2011 to To=19/08/2011 the query returns me all the values from the table that have a Date_Requested value of 18/08/2011, but none from the 19/08/2011.
How can something like that be possible and what query should I use to return rows where the date field is between date1 and date2.
Something like :
select * rows where datevalue >= date1 and datevalue <= date2
Thank you.
Change your query to use >= and <
select * rows where datevalue >= date1 and datevalue < date2 + 1
I bet your Date_Requested in your table also has some time associated with it - so it probably really is 18/08/2011 14:37 or something like that.
The BETWEEN clause will be selecting anything between 18/08/2011 00:00:00 and 18/08/2011 00:00:00 - basically nothing.
What you need to take into account when working with DATETIME is the fact there's always also TIME involved!
If you want everything for today, you need to use:
BETWEEN `18/08/2011 00:00:00` AND `18/08/2011 23:59:59`
With those two values, you should get all rows with a Date_Requested of today.
OR: in SQL Server 2008 and newer, you could also use the DATE column type which stores date only - no time portion involved. In that case, you should be fine with your query values.
From.Date and To.Date gets the date portion on c# side ignoring the time portion; you need to do something similar on the database side.
Try
"SELECT * FROM tblHistory WHERE cast(Date_Requested as DATE) BETWEEN #From and #To"
to remove the time portion.
EDIT:
as explained in this answer, you could change #To param value to
oParam[1] = new SqlParameter("#To", To.Date.AddDays(1));
You need to account for time (not just date). One way I handle that is like this:
SELECT
...
WHERE CONVERT(varchar(8), date_begin, 112) <= convert(varchar(8), #to, 112)
This converts dates to YYYYMMDD format (with no time), which is very easy to use in <, >, = comparrisons.
Ok, thanks to you all, i've done the following thing
oParam[2] = new SqlParameter("#To", To.Date.AddDays(1));
and used the following select
SELECT * from MyTable WHERE CONVERT(varchar(8), Date_Requested, 112) >= CONVERT(varchar(8), #From, 112) and CONVERT(varchar(8), Date_Requested, 112) < CONVERT(varchar(8), #To, 112)
Datetime variables must be converted to be compared.
Thanks all!
I issued a SQL on SQL Server 2000:
select * from Employee where LastUpdateDate >=DateAdd(yyyy,-1,Getdate())
It works fine and got some records.
Then I write a Linq for the same purpose:
EntityQuery<Employee> query = from e in ctx.GetEmployeeQuery()
where e.DateCreated >= DateTime.Today.AddYears(-1)
but I got null from the result.
How to fix it?
Linq to Entities doesn't support the AddYear method. It does not know how to translate this into SQL. The solution is to precalc the value.
var targetDate = DateTime.Now.AddYears(-1)
EntityQuery<Employee> query = from e in ctx.GetEmployeeQuery()
where e.DateCreated >= targetDate