Convert "YYYYMMDD" format string to date in MDX? - sql-server-2012

I have some issue with applying date related functions on the "YYYYMMDD" format string in MDX. For example, if I have this query below:
with
member foo as WEEKDay("2013-03-21")
select
foo on 0
from
[Some Cube]
It will correctly output "5" for foo in SSMS. But if I change the second line to:
member foo as WEEKDay("20130321")
Unfortunately, it will throw "type mismatch" error.
So what I want to do is that converting the string to some recognizable date format and then applying the functions on it. Any ideas for the easiest way, e.g. using existing functions?
Please note that the string is actually inputted from members in any cube where the MDX is running on. So the string format could have been recognizable, e.g. "YYYY-MM-DD". So hard coded string converting algorithm may not be ok.

Topic is too old, but maybe this may help someone. Technique is quite brute, but scalable.
with
member foo_false as WeekDay("20130321")
member foo_true as WeekDay("2013-03-21")
member foo_brute as
case when IsError(WeekDay("20130321"))=False then WeekDay("20130321") else
case
/* YYYYMMDD */
when
IsError(WeekDay("20130321"))=True AND IsNumeric("20130321")=True
and IsError(WeekDay(Left("20130321",4)+'-'+Right(Left("20130321",6),2)+'-'+Right("20130321",2)))=False
then WeekDay(Left("20130321",4)+'-'+Right(Left("20130321",6),2)+'-'+Right("20130321",2))
/* DDMMYYYY */
when
IsError(WeekDay("20130321"))=True AND IsNumeric("20130321")=True
and IsError(WeekDay(Right("20130321",4)+'-'+Right(Left("20130321",4),2)+'-'+Left("20130321",2)))=False
then WeekDay(Right("20130321",4)+'-'+Right(Left("20130321",4),2)+'-'+Left("20130321",2))
/* MMDDYYYY */
when
IsError(WeekDay("20130321"))=True AND IsNumeric("20130321")=True
and IsError(WeekDay(Right("20130321",4)+'-'+Left("20130321",2)+'-'+Right(Left("20130321",4),2)))=False
then WeekDay(Right("20130321",4)+'-'+Left("20130321",2)+'-'+Right(Left("20130321",4),2))
/* Unsupported Message */
else "Unsupported Format" end
end
select
{foo_false,foo_true,foo_brute} on 0
from
[DATA Cube]
Adding supportable formats to the end before "Unsupported", use any input string instead of "20130321".
But the easiest way is to use another layer (e.g. SQL function CONVERT) before inserting to MDX if possible, sure thing.

The vba function isDate can be used to check if the passed date is well formatted. If not then format it first using dateserial and mid and use them.
with
member foo as "20130321"
member bar as
iif(vba!isdate(foo) = TRUE,
WEEKDay(foo), //--if the date is already well formatted, it can be used
WEEKday(vba!dateserial(vba!mid(foo, 0, 4), vba!mid(foo, 5, 2), vba!right(foo, 2))))
select
bar on 0
from
[some cube]
EDIT
The above code can be modified to accommodate other checks such as MMDDYYYY or DDMMYYYY, but the thing is it is impossible in lot of cases for the engine to intuitively know if the passed value is in YYYYMMDDDD or DDMMYYYY or MMDDYYYY. Take for example the string 1111111
This could easily be in any date format as it is a valid date howsoever you break it.
I would suggest that you have another member which can store the date format as well. That way looking at this member, string can be parsed.
e.g.
with
member foo as
// "20130321" //YYYYMMDD
// "03212013"//MMDDYYYY
"21032013"//DDMMYYYY
MEMBER dateformat as "ddmmyyyy"
member bar as
iif(vba!isdate(foo) = TRUE,
WEEKDay(foo),
IIF(dateformat = "yyyymmdd", //YYYYMMDD
WEEKday(vba!dateserial(vba!mid(foo, 0, 4), vba!mid(foo, 5, 2), vba!right(foo, 2))),
IIF(dateformat = "mmddyyyy", //MMDDYYYY
WEEKday(vba!dateserial(right(foo, 4), vba!mid(foo, 0, 2), vba!mid(foo, 3, 2))),
IIF(dateformat = "ddmmyyyy", //DDMMYYYY
WEEKday(vba!dateserial(right(foo, 4), vba!mid(foo, 3, 2), vba!mid(foo, 0, 2))),
null
)
)
)
)
select
bar on 0
from
[aw cube]

With FooMember being an int here, representing a yyyyMMdd date I could convert it to Date using the following code
=Format(CDate(Left(CSTR(Fields!FooMember.Value),4)
+ "-" + Mid(CSTR(Fields!FooMember.Value), 5, 2)
+ "-" + Right(CSTR(Fields!FooMember.Value), 2)),
"dd/MM/yyyy")
use it in a cube using the following code
Format(CDate(Left([Measures].[FooMember],4)
+ "-" + Mid([Measures].[FooMember], 5, 2)
+ "-" + Right([Measures].[FooMember], 2)),"yyyy/MM/dd")

Related

SSRS Group Sort Using Group Variable

I'm looking to sort group Part using variable Coverage. The variable's expression:
=( IIF(ISNOTHING( SUM(Fields!OnhandQty.Value) ), 0, SUM(Fields!OnhandQty.Value)) +
IIF(ISNOTHING( Fields!WIP.Value ), 0, Fields!WIP.Value)
) / IIF(ISNOTHING( SUM(Fields!RequiredQuantity.Value) ), 0, SUM(Fields!RequiredQuantity.Value) )
I'm able to save report (using Report Builder) with no errors, but I get the error:
The processing of SortExpression for the table ‘TablixCustomer’ cannot be performed. The comparison failed. Please check the data type returned by the SortExpression. (rsProcessingError)
Why?
Your expression SUM(...Value) will fail if .Value is ever null and becomes a String value of #error. So try changing your expressions to this: Note that it checks the value before aggregating the value instead of aggregating before checking for null.
=( SUM(IIF(ISNOTHING(Fields!OnhandQty.Value), 0, Fields!OnhandQty.Value)) +
IIF(ISNOTHING( Fields!WIP.Value ), 0, Fields!WIP.Value)
) / SUM(IIF(ISNOTHING(Fields!RequiredQuantity.Value), 1, Fields!RequiredQuantity.Value))

MDX Date Formatting

Can any one please tell me how to format date in MDX queries? We dont use SSRS to generate report ,we have our own customised reporting tool built on SSAS.Date filter sends date in yyyy/mm/dd format . As of now we dont have a date dimension. My date member looks like:
[CNB_DimSampleInfo].[COAReleasedON].&[2013-01-02T03:20:00].
How can I format date in STRTOmemeber? I have tried doing this. My question is how will the value coming from user suit my member format as below. I know ssrs does it easily but we are not using SSRS. Below is my Code
my code
SELECT
[Measures].[Result] ON COLUMNS
,NON EMPTY
{
[CNB_DimProduct].[ProductUcode].[ProductUcode].ALLMEMBERS*
[CNB_DimProduct].[ProductDesc].[ProductDesc].ALLMEMBERS*
[CNB_DimTest].[TestUcode].[TestUcode].ALLMEMBERS*
[CNB_DimTest].[TestName].[TestName].ALLMEMBERS*
[CNB_DimSampleInfo].[LotNo].[LotNo].ALLMEMBERS*
[CNB_DimSampleInfo].[BatchNo].[BatchNo].ALLMEMBERS*
[CNB_DimSampleInfo].[COAReleasedBy].[COAReleasedBy].ALLMEMBERS*
[CNB_DimSampleInfo].[COAReleasedON].[COAReleasedON].ALLMEMBERS*
[CNB_DimSampleInfo].[SampleReferenceNo].[SampleReferenceNo].ALLMEMBERS*
[CNB_DimSampleInfo].[AnalysedBy].[AnalysedBy].ALLMEMBERS*
[CNB_DimSampleInfo].[AnalysedOn].[AnalysedOn].ALLMEMBERS
} ON ROWS
FROM
(
SELECT
StrToMember
(
"[CNB_DimSampleInfo].[COAReleasedON].[" + Format("2013-01-02","yyyy MM")
+ "]:STRTOMember([CNB_DimSampleInfo].[COAReleasedON].["
+
Format
("2013-01-02"
,"yyyy MM"
)
+ "]"
) ON COLUMNS
FROM Cube001
);
There is also StrToSet which is better in your circumstance as you're using the : operator which returns a set:
...
...
FROM
(
SELECT
StrToSet
(
"[CNB_DimSampleInfo].[COAReleasedON].[" + Format("2013-01-02","yyyy MM")
+ "]:[CNB_DimSampleInfo].[COAReleasedON].["
+
Format
("2013-01-02"
,"yyyy MM"
)
+ "]"
,CONSTRAINED
) ON COLUMNS
FROM Cube001
);
does the following definitely return the date formatted the same as your key values?
Format("2013-01-02","yyyy MM")
Do your key values for dates look like this?...
[CNB_DimSampleInfo].[COAReleasedON].[2013 01]
Your date member
[CNB_DimSampleInfo].[COAReleasedON].&[2013-01-02T03:20:00]
looks like a bad candidate for a user date parameter, as it's precise down to the minute (perhaps the second). Unless the user exactly matches the time, they'll get nothing. But perhaps you're enforcing exact matches by using a LimitToList select list in the UI.
To get this member name, you can format the input string like this:
format([Your Input Parameter],'yyyy-MM-ddThh:mm:ss')
I have tried out using filter as below
SELECT
[Measures].[Result] ON COLUMNS
,NON EMPTY
{
filter([CNB_DimSampleInfo].[COAReleasedON].members,instr([CNB_DimSampleInfo].[COAReleasedON].currentmember.member_caption,"2013-01-02")>0 or instr([CNB_DimSampleInfo].[COAReleasedON].currentmember.member_caption, "2013-04-01")>0)
*[CNB_DimProduct].[ProductUcode].[ProductUcode].ALLMEMBERS*
[CNB_DimProduct].[ProductDesc].[ProductDesc].ALLMEMBERS*
[CNB_DimTest].[TestUcode].[TestUcode].ALLMEMBERS*
[CNB_DimTest].[TestName].[TestName].ALLMEMBERS
} ON ROWS
FROM Cube002

How do I get day number from a date in abap?

I need to convert a date in 'MM/DD/YYYY' format to a number that say which day in the year it is. I.E '01/01/YYYY'=1 and '12/31/YYYY'=365. Is there any built in function to do this in ABAP? I've tried googling but I couldn't find any functions which did this
Here you go in one line of code:
DATA(g_day) = p_date - CONV d( p_date(4) && '0101' ) + 1.
It is absolutely unnecessary to rely on any function module that may or may not be present in your system. Just use basic built-in language elements:
DATA: l_my_date TYPE d, " note that the data type D is YYYYMMDD
l_jan_01 TYPE d, " This will be jan 1 of the needed year
l_day TYPE i.
l_my_date = ...whatever...
l_jan_01 = l_my_date.
l_jan_01+4 = '0101'. " or any other means to get the first day of the year.
l_day = l_my_date - l_jan_01 + 1.
You can use this function module: HR_AUPBS_MONTH_DAY.
You have to pass an initial date and an end date, and it will return the number of days in between (this is what you want):
CALL FUNCTION 'HR_AUPBS_MONTH_DAY'
EXPORTING BEG_DA = P_BEGDA " Here you should put the first day of the year
END_DA = P_ENDDA " Here you put the date
IMPORTING NO_CAL_DAY = P_CAL_DAY. " This is what you want

NHibernate varying the way it creates DateTime based queries based on the day of the month

I am getting some weird behaviour on how NHibernate is sending queries to the database on DateTimeOffset fields. Given the following example:
DateTimeOffset? myDate = new DateTimeOffset(2012, 3, 17, 0, 0, 0, new TimeSpan(1, 0, 0));
var test = HibernateSession.Query<ExampleEntity>().Where(c => c.DateTimeOffsetField > myDate).ToList();
DateTimeOffset? myDate2 = new DateTimeOffset(2012, 3, 1, 0, 0, 0, new TimeSpan(1, 0, 0));
var test2 = HibernateSession.Query<ExampleEntity>().Where(c => c.DateTimeOffsetField > myDate2).ToList();
Using NHibernate Profiler to look at the SQL generated, the first query shows up as
exampleentity0_.[DateTimeOffsetField] > '17/03/2012 00:00:00 +01:00' /* #p0 */
the second as
exampleentity0_.[DateTimeOffsetField] > '2012-01-02T23:00:00.00' /* #p0 */
Notice the different formatting on the dates? If the day of the month is greater than 12, it uses the first format, if it is less than 12 it uses the second. This is causing errors when we have dates in the first format as SQL server cannot convert the string to a valid Date as it is looking for month 17 (as this example). This is driving me nuts!!
Has anyone seen this behaviour before?
Is it possible to tell NHibernate to always use the yyyy-MM-dd format?
Thanks
Tom
p.s. using FluentNHibernate for the mapping and configuration. An example of the mapping would be
Map(a => a.DateTimeOffsetField).Not.Nullable();
...i.e nothing unusual..
I have "fixed" this issue by changing the sql server instance to use a British time culture so that is accepts both values created by NHibernate... still be interested to know why these differences occur though.

DateTime comparison in ObjectQuery.Where

I'm using Entity Framework, and I have a COMMENT entity. A COMMENT has a DATEMODIFIED property, which is a Nullable Date. I'm trying to build a query that will filter COMMENTs by date, so I create a startDate object, and do the following:
Dim q As ObjectQuery(Of COMMENT) = _
(From c In model.COMMENT Select c)
If startDate.HasValue Then
q = q.Where(Function(c) startDate.Value <= c.DATEMODIFIED)
End If
The problem is that q.toList() is not returning any comments, even though I think it should. All comments in the database have DATEMODIFIED values, and even if I pass in DateTime.MinValue as the startDate, the query still doesn't match any entities.
I set a breakpoint before the If-Statement and used the Visual Studio Watch Window to try and see what's going on:
q.ToList()(0).DATEMODIFIED 'Returns the expected date
startDate.Value 'Returns the expected date
startDate.Value <= q.ToList()(0).DATEMODIFIED 'Returns True...
But once once it hits the q = q.Where(predicate) part, q.ToList() no longer returns any entries. I'm stumped.
UPDATE: Oops, I forgot that, with LINQ to Entities, all WHERE expressions are translated into SQL calls instead of being post-processed in code-- so the debugging suggestions below won't necessarily work.
Therefore, I'd start by running the same generated SQL statement against your database, and validating whether the SQL generated by your Entity Framework provider is actually returning the data you expect. #Craig Stuntz's comment above is definitely on the right track here to help you do this. Once you have the parameterized SQL, I'd try executing that SQL directly from your code (using System.Data.OracleClient) and validating that you actually get results back from that query. Remember to inject the same parameter values that you get from ObjectQuery.Parameters. Alternatively, you could stick the parameters in yourself and execute the query from your Oracle client app of choice.
If you don't get results from that SQL, then it's possible that devArt's provider is building the query incorrectly.
you can ignore what's below here, since it applies to troubleshooting LINQ-to-Objects but not LINQ-to-Entities
Some ideas to diagnose this:
first, try this in your watch window:
q.Where(Function(c) startDate.Value <= c.DATEMODIFIED).Count()
I'm assuming this will return zero, but it's worth eliminating as many other variables to make sure you're really not getting any results.
Next, I'd try is to define your LINQ query a bit differently-- instead of appending the Where() separately, try using two queries, like this:
Dim q As ObjectQuery(Of COMMENT)
If startDate.HasValue Then
q = (From c In model.COMMENT Where startDate.Value <= c.DATEMODIFIED Select c)
Else
q = (From c In model.COMMENT Select c)
End If
If this works, then there's something wrong with how the Where clause is being attached to your existing LINQ query-- perhaps a bug in your DBMS's entity-framework provider?
If that still doesn't work, the next step I'd take to diagnose would be to verify that the code inside the where clause is being called, and checking the values passed into that code. I couldn't figure out how to set intra-line breakpoints in VB like one can do in C#, but you can easily (temporarily) refactor your lambda into a separate function and set the breakpoint there. Like this:
Sub Main()
Dim testDate As Date = New Date(2005, 1, 1)
Dim x = New List(Of Date?)
x.Add(New Date(2009, 1, 1))
x.Add(New Date(2008, 1, 1))
x.Add(New Date(2007, 1, 1))
x.Add(New Date(2006, 1, 1))
x.Add(New Date(2005, 1, 1))
x.Add(New Date(2004, 1, 1))
x.Add(New Date(2003, 1, 1))
x.Add(New Date(2002, 1, 1))
x.Add(New Date(2001, 1, 1))
Dim y = From n In x Select n
y = y.Where(Function(val) test(val, testDate))
Dim z = y.ToArray()
End Sub
Function test(ByVal date1 As Date, ByVal date2 As Date) As Boolean
test = date1 >= date2
End Function
Check the values being sent into your comparison function-- are they valid? Does the comparison return what you expect it to?