I'm using LINQ-to-SQL and need to order by a date field. The date field is stored as text and could have anything in it since it is user entered data. I need to handle cases where an invalid date was placed in there.
For example, a date of "02/23/0000" returns:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
I need to avoid errors and I don't care where an invalid date like this gets sorted to. The parameters of the project mean I can't modify my source data, only read from it.
Here is an example LINQ statement.
from x in dbo_myTable
orderby Convert.ToDateTime(x.MyDateField)
select x
Do you definitely need to perform the ordering in the database? In this situation I would strongly consider pulling all of the data, then performing some conversion in .NET code where you have a great deal more control over what's going on, and then order it still in .NET code.
Ultimately, dealing with screwed up data in this sort of situation is tricky - the more control you have, the better.
You can do something like this (Based on your comment that they are all 10 characters)
from x in dbo_myTable
orderby x.MyDateField.Substring(6, 4), x.MyDateField.Substring(0, 2), x.MyDateField.Substring(3, 2)
select x
First is first; why cant you change the database to fix you obviously brokes table structure? Why cant you sanitize input when its going into the database? Why are you not validating user input?
Now for the answer; your only option is attempt to parse the date (with DateTime.TryParse or DateTime.TryParseExact) and set a default value of your choosing if it fails to parse:
from x in dbo_myTable
orderby TryConvertToDateTime(x.MyDateField)
select x
private DateTime TryConvertToDateTime(string dt)
{
DateTime rtn = DateTime.MinValue; // or whatever you want your default to be
DateTime.TryParse(dt,out rtn);
return rtn;
}
Related
I have a String field in a Dataset in (mmddyyyy) format.
I am trying to convert it into a Date field in SSRS.
I already tried using the below command but I am getting error.
CDate(Fields!LocalTXNDate.Value)
Can anyone please suggest.
While Larnu is correct, the way to do it is to correct the database, sometimes we lowly report makers have no say in making these changes - much less getting a DBA to do it in a reasonable amount of time.
If you can't change the data to be correct, the easiest way to convert and use the field as a date is to add a Calculated Field to the Dataset. Open the dataset properties, click on the Fields tab, Add a Calculated field.
For the Expression, use string functions to parse the field into a generic date format and then CDATE to convert to a date type. Then use the new field for dates. You could also use this in your text box if it's not being reused but it's easier to manipulate the Calculated field.
=CDATE(
RIGHT(Fields!LocalTXNDate.Value, 4) & "-" &
LEFT(Fields!LocalTXNDate.Value, 2) & "-" &
MID(Fields!LocalTXNDate.Value, 3, 2)
)
The problem here isn't SSRS but your data, and that you are using a string based data type to store the data. You need to fix the problem at the source, not at the report level.
The string format you have chosen, MMddyyyy isn't a format that is recognised by default in any of the languages in SQL Server, nor if you explicitly use SET DATEFORMAT, nor does it appear as a style. SET DATEFORMAT MDY; SELECT CONVERT(date,'11172022'); will fail. Therefore you'll need to first do some string manipulation on the data first to be an unambiguous format (yyyyMMdd):
UPDATE YT
SET YourDateColumn = CONVERT(varchar(8),V.DateValue,112)
FROM dbo.YourTable YT
CROSS APPLY (VALUES(TRY_CONVERT(date,CONCAT(RIGHT(YT.YourDateColumn,4),LEFT(YT.YourDateColumn,4)))))V(DateValue);
For any bad values you have, such as '17112022' this will UPDATE the value to NULL; as such you may want to create a new column for the new value, or perhaps a new column to store the value of dates that couldn't be converted.
After you've changed the value to an unambiguous format, then you can ALTER the column:
ALTER TABLe dbo.YourTable ALTER COLUMN YourDateColumn date NULL;
Note that if you have any constraints, you will need to DROP those first, and then reCREATE them afterwards.
Now that the data type of the column is correct, you need not do anything in SSRS, as the data type is correct.
I have a datatable in which I have datetime column, in Database DateTime is set as null so it fills with default datetime. Now when I view this datatable in WPF it shows me these dates. Where as I want to make it empty if date is less than 2000-01-01.
foreach (DataRow row in table.Rows)
{
if (row["PROCESSED__DATE"].ToString() != "")
{
string s = Convert.ToDateTime(row["PROCESSED__DATE"].ToString()).ToString("MM/dd/yyyy HH:mm:ss");
if (DateTime.ParseExact(s, "MM/dd/yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture)<
DateTime.ParseExact("01/01/2000 00:00:00", "MM/dd/yyyy
HH:mm:ss",System.Globalization.CultureInfo.InvariantCulture
{
row["PROCESSED__DATE"] = "";
}
}
}
I am using this following code to replace datetime column value to empty but I am getting an error on the following line:
row["PROCESSED__DATE"] = "";
The error is String was not recognized as a valid DateTime.Couldn't store, I know this is causing because I am trying to save empty string in DATETIME column. But what I don't know is how can I achieve this without changing datacolumn datatype.
I don't really came up with your code but i'll give you leads to find a solution.
What is your database engine, in almost all you can define the column as Nullable, which mean you will be able to set no value. When you go to find the value you have to use somethig like the FirstOrDefault so if there is no value it is null otherway you get the value
Let's imagine you don't like the first solution, you are using a datatable, not bad but if you want to do a little more and have much more possibilities try using DataGrid, not much complicated, you just need to make something that contains the data and go for the binding magic. With this solution you can do much more and with the Object you'll be able to handle many future potential problems.
If you have any further questions ask it, i'll try the best to help you.
Hoping my answer will help you.
Have a nice day.
Dates are not stored with time zone or format information in the database, it is simply stored as two integers which represent an offset from a zero date.
Your code converts a column that you say is a DateTime to a string and then converts this back to a DateTime and then back to a string again.
string s = Convert.ToDateTime(row["PROCESSED__DATE"].ToString()).ToString("MM/dd/yyyy HH:mm:ss");
This is a pointless exercise, just use the date in its native format and if you want to compare use the DateTime data type.
Additionally, if you can't make the column nullable in the database, then you might want to consider using a constant to represent the empty date.
You can create a date using the date constructors without parsing it from a string.
var baseDate = new Date time(1, 1, 2000);
if (row["PROCESSED__DATE"] < baseDate) { // ... Etc
But still, you aren't going to be able to push anything but a date into the database unless you make the column nullable.
Can you not change the schema to make the column nullable?
I have a spreadsheet that gets all values loaded into SQL Server. One of the fields in the spreadsheet happens to be money. Now in order for everything to be displayed correcctly - i added a field in my tbl with Money as DataType.
When i read the value from spreadsheet I pretty much store it as a String, such as this... "94259.4". When it get's inserted in sql server it looks like this "94259.4000". Is there a way for me to basically get rid of the 0's in the sql server value when I grab it from DB - because the issue I'm running across is that - even though these two values are the same - because they are both compared as Strings - it thinks that there not the same values.
I'm foreseeing another issue when the value might look like this...94,259.40 I think what might work is limiting the numbers to 2 after the period. So as long as I select the value from Server with this format 94,259.40 - I thin I should be okay.
EDIT:
For Column = 1 To 34
Select Case Column
Case 1 'Field 1
If Not ([String].IsNullOrEmpty(CStr(excel.Cells(Row, Column).Value)) Or CStr(excel.Cells(Row, Column).Value) = "") Then
strField1 = CStr(excel.Cells(Row, Column).Value)
End If
Case 2 'Field 2
' and so on
I go through each field and store the value as a string. Then I compare it against the DB and see if there is a record that has the same values. The only field in my way is the Money field.
You can use the Format() to compare strings, or even Float For example:
Declare #YourTable table (value money)
Insert Into #YourTable values
(94259.4000),
(94259.4500),
(94259.0000)
Select Original = value
,AsFloat = cast(value as float)
,Formatted = format(value,'0.####')
From #YourTable
Returns
Original AsFloat Formatted
94259.40 94259.4 94259.4
94259.45 94259.45 94259.45
94259.00 94259 94259
I should note that Format() has some great functionality, but it is NOT known for its performance
The core issue is that string data is being used to represent numeric information, hence the problems comparing "123.400" to "123.4" and getting mismatches. They should mismatch. They're strings.
The solution is to store the data in the spreadsheet in its proper form - numeric, and then select a proper format for the database - which is NOT the "Money" datatype (insert shudders and visions of vultures circling overhead). Otherwise, you are going to have an expanding kluge of conversions between types as you go back and forth between two improperly designed solutions, and finding more and more edge cases that "don't quite work," and require more special cases...and so on.
I need to store schedule date and times. Scheduale contains one date field and two time fields.
Is there any possibility to store schedule in one db field and not in two (datetime + datetime)?
I am using SQL Server 2005.
Thanks!
Whether it is "start"+"stop", or "start"+""duration", you have 2 pieces of information = store 2 pieces of information.
Using a string or XML makes no sense: this requires take more space, more processing, more code to search and use.
Why would you want to store what are effectively two datetimes in one field rather than two? Are there no cases where the schedule might have times that cross days? (ie. 01/03/2011 23:59, 02/03/2011 01:35)? Do you not mind having to parse out the information rather than having it immediately ready for query?
If you really want to, there's no reason you can't store it as a string type, comma separated possibly, maybe XML as suggested, but I can't say it's recommended as date/time fields are more space efficient, nice and fast/flexible for searching purposes, and there are many useful T-SQL functions which can easily be used on date/time types which you'd be hard pushed to use on a string without some parsing and casting/converting.
If you can come up with a good reason for not using two datetime fields, I'll have another Donut! (ps. happy Fat Thursday).
One quick, and horribly evil thought ... you could use part of the datetime to store the "difference" ... sneak it into the "seconds" and "milliseconds" values, and apply it to the main date/time to get the new value. A bit hacky, but it'd could do the job, depending on your range requirements.
-- Example: 01/03/2011 12:30:02
-- Translates into - first of March 2011, 12:30 to 14:30 (12:30 + (seconds * hours))
set #ModifiedDatetime =
DATEADD(hour, DATEPART(second, #originalDateTime), #originalDateTime);
Beware of rounding errors with milliseconds ... and please think about the consequences of what you're doing. God kills a kitten each time someone abuses a type :)
You can try using the XML field type and store an XML snippet in there, similar to the following:
<schedule date="2011-01-01" fromTime="12:00" toTime="14:00" />
You can then use XQuery in a select to transform the result set back to a "normal" row-based result set. A sample query implementing XQuery, based on my example's XML schema, could be as follows:
SELECT
[...]
, Schedule.value('(/schedule/#date)[1]','datetime') as [Date]
, Schedule.value('(/schedule/#fromTime)[1]','char(5)') as [FromTime]
, Schedule.value('(/schedule/#toTime)[1]','char(5)') as [ToTime]
FROM [TABLE]
I'm not saying that storing it as XML is the best way to do it (as the other answers rightfully state), but you asked IF it is possible and I propose a solution...
I have a problem.
I have an application in C# with SQL SERVER 2005 as backend.
The problem is in fetching the correct record based on the date.
The frontend code is
if (string.IsNullOrEmpty(txtFromDate.Text))
SelectCmd.Parameters[0].Value = DBNull.Value;
else
SelectCmd.Parameters[0].Value = txtFromDate.Text;
Now if I run usp_NewGetUserDetail '03/04/2010' in the query analyser, I am able to get the correct record.
So I am preety confident that my SP is correct(I have tested with many variations).
But if the same value is passed from front end code(SelectCmd.Parameters[0].Value = "03/04/2010";), I am getting some unexpected record. By that I mean , the records which are not in the date range.
I guess that there is some mismatch in date format of backend and frontend.
Kindly let me know if I missed out some information that I need to provide for solving this
Please help.
Dealing with dates on SQL Server is a tricky business, since most formats are language- and locale-dependent. As Adam already mention - you should try to avoid dealing with dates as strings - it does get messy, and using DateTime (both in .NET and in T-SQL) is much safer and easier.
But if you must use strings, then be aware of these points: a date like 02/05/2010 will be interpreted as Feb 5, 2010 in some places, or as May 2, 2010 in others. So whatever you're doing - you'll always run into someone who has a different setting and gets different results.
The way to do here is to use the ISO-8601 format which is independent of all locale and language settings and just always works.
So for your dates, always use the YYYYMMDD format - first of all, it always works, and second of all, with that format, you get a "natural" sort behavior - sorted by Year, then Month, then Day.
There's no need to pass the date as a string, nor should you. Set the value of the parameters to a DateTime object that represents the date you want, not the string representation of it.
Try something like this:
DateTime fromDate;
if (DateTime.TryParse(txtFromDate.Text, out fromDate))
{
SelectCmd.Parameters[0].Value = fromDate
}
else
{
SelectCmd.Parameters[0].Value = DBNull.Value;
}