I have a portion of my data that has been parsed incorrectly (due to earlier mistakes in handling Culture) so that the month and the day should be flipped. Is there an easy way to do this in SQL Server? Fortunately, it is still early enough in the dataset that it is easy to locate the bad data.
Update I think this will work:
SELECT seen, DATEADD(DAY, DATEDIFF(DAY, seen,
CONVERT(DATETIME, CAST(YEAR(seen) AS VARCHAR(4))
+ RIGHT('0'+CAST(DAY(seen) AS VARCHAR(2)),2) +
+ RIGHT('0'+CAST(MONTH(seen) AS VARCHAR(2)),2), 112)), seen)
FROM TermStats
WHERE seen < '2011-09-01' AND DAY(seen) <= 12
But I think I can do better. All good dates are after 9/1. (You can tell I really lucked out here... lol)
SELECT DISTINCT YEAR(seen), MONTH(seen), DAY(seen)
FROM TermStats
ORDER BY YEAR(seen), MONTH(seen), DAY(seen)
2006 2 13
2011 3 9
2011 4 9
2011 5 9
2011 6 9
2011 9 3
2011 9 4
2011 9 5
2011 9 6
Personally I wouldn't do it through string manipulation. It's entirely possible that you can do it nicely in a stored procedure, but I'd personally (as someone with little SQL experience) write a client side tool to fix it:
Fetch the ID and date of every row you need to fix (fetching the date/time value as a date/time value, not as a string)
Create the correct date, e.g. in C# using new DateTime(dt.Year, dt.Day, dt.Month); to flip the fields of the wrong date
Update the database with a parameterized query - again, not converting the dates into strings
Basically, wherever you can, avoid conversion between text and other formats. It only leads to the kind of pain you've already discovered.
Related
A couple of years ago I wrote a proof of concept function to date strings to calculate the end date from the string. This never made it to production for a number of reasons but all the functions worked. For example the string
999 years less 1 day from 16 August 2000
should evaluate to 15th August 2999. I wrote this function using the Microsoft Recognizers library (V1.3.2) and it all worked.
var culture = Culture.MapToNearestLanguage("en-gb");
DateTimeOptions dateTimeOptions;
dateTimeOptions = DateTimeOptions.ExtendedTypes;
var results = DateTimeRecognizer.RecognizeDateTime(leaseTermPhrase, culture, dateTimeOptions);
results would return 3 elements derived from the string, a duration of 999 years, a duration of 1 day and a date of 16 August 2000, and using that data I was able to calculate the end date (I made an assumption that any second duration should be taken away from the end date).
I am now revisiting this code as the need for it has come back into scope. I updated the Recognizer packages to the latest version (1.8.2) and now the unit test that tests this particular format of string fails (other string formats still pass).
Upon investigation I find that the results variable now only contains two parts; a duration of 999 years and a Date 0f 15 August 2000. So the new library is parsing '1 day from 16 August 2000' as a single date entity instead of two separate ones (a duration and a date)
Does anyone know if it is possible to get the Recognizer to produce the same results as previously?
My Accounting Period Date is using a Numeric data type
1990-01-01
2008-08-01
2008-07-01
So I applied CAST function in the data item.
And the results appeared like this.
Jan 1, 1990
Aug 1, 2008
Jul 1, 2008
Is there a way to make it appear like this?
Jan 1990
Aug 2008
Jul 2008
I tried using a new data item using Replace Function like this but it does not work.
This is the error I get.
Could someone help me please.
Part of the problem you will run into is Cognos's auto formatting of date types. That's what you are seeing with the Jan 1, 1990 format. The data still exists as a date but Cognos chooses to reformat it when running. Thus, you cannot use a substring function to extract out the components you want as it doesn't exist as a string. Straight casting to a string reverts it to the 'YYYY-MM-DD' format in string form, obviously not what you want.
There are three options.
If you just want the date to display in the desired format on the report, then the simplest solution is to use the 'Data Format' property on the column itself in the report definition (list, crosstab, singleton etc). Within the Data Format property sheet there is a property called 'Pattern'. You can use this property to define how you want the column displayed. Enter 'MMM YYYY' in this property to create the output you desire.
If you need the actual data item to change to match the format you require then you will have to build a string:
CASE extract(month,[Date])
WHEN 1 THEN 'Jan'
WHEN 2 THEN 'Feb'
WHEN 3 THEN 'Mar'
WHEN 4 THEN 'Apr'
WHEN 5 THEN 'May'
WHEN 6 THEN 'Jun'
WHEN 7 THEN 'Jul'
WHEN 8 THEN 'Aug'
WHEN 9 THEN 'Sep'
WHEN 10 THEN 'Oct'
WHEN 11 THEN 'Nov'
WHEN 12 THEN 'Dec'
END || ' ' || cast(extract(year,[Date]),char(4))
Your last option is to use a data source vendor-specific cast function. For example, DB2's to_Char() function allows you to precisely define how the date is converted to a char. Other database servers have their own functions that do similar things. You'll have to figure out if there is an equivalent in your data source vendor's solution.
The down side to this approach is that if you change data sources to another vendor you will have to adjust the report as well or it will likely throw an error. When you use Cognos's own functions, Cognos automatically converts the function to the equivalent vendor-specific function for you. You gain portability and maintenance at the possible expense of flexibility and power.
Maybe something like this?
SELECT CAST(DATENAME(MONTH,GETDATE()) AS VARCHAR(3)) + ' ' + CAST(DATEPART(YEAR,GETDATE()) AS VARCHAR(4)) AS mystring
I have a numeric field in my Oracle database that represents the number of days since Dec 28, 1800. However I am trying to select it (for another application) as the current date it represents. I'm not too familiar with Oracle commands (I'm used to SQL), so I was wondering if anyone could provide some assistance. Thanks.
ex: 77650 = Saturday, August 3, 2013
Firstly, get this out of the way, your life would be easier if you stored dates in a date data-type.
However, to answer your question to add days to a date in Oracle you can use the + operator.
Firstly though you have to have a date so I'll convert the 28th December 1800 into a date using to inbuilt to_date function then add the number. In your case you would want:
select to_date('1800/12/28','yyyy/mm/dd') + 77650 from dual
I've set up a little SQL Fiddle to demonstrate for you.
I have a datetime field in SQL Server 2008 which stores the date and time in military format (or international format if you prefer)
examples:
2011-02-15 10:00:00.000
2011-02-15 15:30:00.000
2011-02-15 17:30:00.000
I need to retrieve the time only portion of this in standard U.S. time format.
So
2011-02-15 10:00:00.000 needs to become 10:00 AM
2011-02-15 15:30:00.000 needs to become 3:30 PM
2011-02-15 17:30:00.000 needs to become 5:30 PM
I am looking for the best way to accomplish this in T-SQL please.
One way is:
Convert to varchar, which will give you:
Select CONVERT(varchar, #dt, 100) -- where #dt is your date time
Feb 15 2011 3:30PM
Subsequently, to remove the date, and get 7 chars from the right, which is the most, and TRIM is added just for extra safety, but probably isn't needed.
Select LTRIM(RIGHT(CONVERT(varchar, #dt, 100),7))
Will give you 3:30PM
Side Note: Denali makes this easier, no more magic numbers
As you requested this in T-SQL, you might want to look at the CAST and CONVERT syntax which specifically lists various date and time formats.
For example:
select convert(varchar, getdate(), 100)
Would give you:
Feb 3 2012 3:26PM
DateTime is stored in an internal representation - there is no format associated. When you need to display the DateTime, specify the formatting you want for converting the DateTime into a string.
It is much better to let the application decide on formatting than formatting in SQL.
See standard and custom Date and Time Format Strings for more information.
I'm working with a bit of an older code base where conciseness is not found in many places.
One piece of code we are constantly using in the database is to determine if two dates are within the same program year. For instance, Program Year 2011 begins on July 1st, 2011 and ends on July 1st, 2012(or technically the day before)
The usual way I see that this problem is solved is by using this kind of code:
if Month(#EnrollmentDate)>=7 begin
set #StartDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)))
set #EndDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)+1))
end else begin
set #StartDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)-1))
set #EndDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)))
end
...
where (ENROLLMENTDATE >= #StartDate and ENROLLMENTDATE < #EndDate)
I recently happened to have to solve this problem and the instant thing that popped in my head was something much more concise:
where year(dateadd(mm,-6,ENROLLMENTDATE)) = year(dateadd(mm,-6,#EnrollmentDate))'
Before I go introducing new bugs into a system that "just works", I'd like to ask SO about this. Are these two pieces of code exactly the same? Will they always give the same output(assuming valid dates)?
the problem I see is that, depending on the optimizer, your solution (that looks better) may not use an index defined on ENROLLMENTDATE since you're doing operations on it, while the original solution would. If there are no indexes on that field, then I don't see an issue
An even easier way to handle this situation is to create a calendar table with a column for the program year. Then there is no logic at all, you just query the values and compare them:
if
(select ProgramYear from dbo.Calendar where BaseDate = #StartDate) =
(select ProgramYear from dbo.Calendar where BaseDate = #EndDate)
begin
-- do something
end
There are many posts on this site about creating calendar tables and using them for many different purposes. In my experience, using a table in this way is always clearer and more maintainable than creating formulas in code.
As it happens, December has 31 days, so no matter how many months you need to subtract, you will always be able to align the resulting date range with a whole year, and therefore your expression will always be true whenever the original one was, even in the general case for an enrolment year starting on other dates.
I once used a dialect of SQL with a range of date manipulation functions that made this slightly easier than string twiddling, something like this:
WHERE enrolmentdate >= #YearBeg(:enrolmentdate + 6 MONTHS) - 6 MONTHS
AND enrolmentdate < #YearBeg(:enrolmentdate + 6 MONTHS) + 6 MONTHS