About currentmember in SSAS & MDX - ssas

I will show you my thoughts about an MDX request, these thoughts are wrong because I don't get the expected result, but why?
The select statement is as follow:
SELECT {nballPatsTransfusedOneSpe , nballPatsOneSpe,nballPatsTransfusedOfSameSpes ,nballPatsOfSameSpes ,localRate} ON 0
FROM [BDD PBM]
Only one variable is of interest: localRate.
It is defined as:
member localRate as ([Dim misc].[Speciality Id].&[{754EFA13-AA1B-4E57-AB73-893AF7C52127}], rate)
I think of localRate as a tuple containing 2 explicit informations : one for a Speciality Id, and the other as a measure(even it doesn't belong to [Measures]), the implicit dimensions of the cube being calculated following standard rules(Default member, All members, First member). Both produce a number, as rate produces an integer. And I think that until the end of the request, the defaultmember of the 'Speciality Id' attribute is the Guid shown above(the hexa number), anywhere it could appears in 'Dim misc'(in an attribute hierarchy, or in all the user hierarchies).
rate is defined as:
MEMBER rate AS (existing([Dim misc].[SpePats2].CurrentMember, allPatsOneSpe )).count
It filters the list of patients (allPatsOneSpe) by the speciality given in localRate, and then count the number of rows. Globally, it returns the number of patients in the given speciality. I can't set a request with the 'speciality Id' in rows and the rate in columns as I will have to compute percents with a set of speciality ids, so I must have a list of specialities and a member rate which, given a speciality id, returns a numerator divided by a denominator(only the denominator is given here).
allPatsOneSpe is as follow:
SET allPatsOneSpe AS Descendants([Dim misc].[SpePats].currentmember,2)
And this is surely where the error is located.
Do these ideas right?
thank you.
Here is the entire request:
with
MEMBER spename AS [DimTransfusion].[TransfusionPatients].[Speciality Id].&[{7XXXXXX7-AA1B-4E57-AB73-89XXXXXXXX27}].FirstChild.MemberValue
SET spesSame AS filter([Dim misc].[SpePats].[Speciality Id].MEMBERS
,[Dim misc].[SpePats].CurrentMember.FirstChild.MemberValue = spename)--filter
SET spesSameTransfusion AS filter([DimTransfusion].[TransfusionPatients].[Speciality Id].MEMBERS
,[DimTransfusion].[TransfusionPatients].CurrentMember.FirstChild.MemberValue = spename)--filter
SET allPatsOfSameSpes AS Generate(spesSame, Descendants([Dim misc].[SpePats].CurrentMember,2))
SET allPatsTransfusedOfSameSpes AS Generate(spesSameTransfusion , Descendants([DimTransfusion].[TransfusionPatients].CurrentMember,3))
MEMBER nballPatsOfSameSpes AS allPatsOfSameSpes.count
MEMBER nballPatsTransfusedOfSameSpes AS allPatsTransfusedOfSameSpes.count
SET allPatsOneSpe AS Descendants([Dim misc].[SpePats].CurrentMember,2)
SET allPatsTransfusedOneSpe AS Descendants([DimTransfusion].[TransfusionPatients].[Speciality Id].[{XXXXXXX7-AA1B-4E57-AB73-8XXXXXXXX}],2)
MEMBER nballPatsOneSpe AS allPatsOneSpe.count
MEMBER nballPatsTransfusedOneSpe AS allPatsTransfusedOneSpe.count
MEMBER rateOneSpe AS nballPatsTransfusedOneSpe / nballPatsOneSpe
MEMBER [Measures].rate AS --(existing([Dim misc].[SpePats2].CurrentMember, filter(allPatsTransfusedOneSpe ,true ) )).count
-- /
(existing([Dim misc].[SpePats2].CurrentMember, allPatsOneSpe )).count
SET OrderedData AS ORDER(
NONEMPTY(spesSame , [Measures].rate),[Measures].rate, BASC)
MEMBER [Measures].[RowCount] AS COUNT (OrderedData)
MEMBER [Measures].[i0p02] AS ( .02* ( [RowCount] - 1 ) ) + 1
MEMBER [Measures].[i0p02Lo] AS FIX([i0p02]) - 1
MEMBER [Measures].[i0p02Rem] AS ([i0p02] - FIX([i0p02]))
MEMBER [Measures].[n0p02Lo] AS (OrderedData.Item([i0p02Lo]), [Measures].[rate])
MEMBER [Measures].[n0p02Hi] AS (OrderedData.Item([i0p02Lo] + 1), [Measures].[rate])
MEMBER [Measures].[PCT0p02] AS [n0p02Lo] + ( [i0p02Rem] * ( [n0p02Hi] - [n0p02Lo] ))
MEMBER [Measures].[i0p2] AS ( .2* ( [RowCount] - 1 ) ) + 1
MEMBER [Measures].[i0p2Lo] AS FIX([i0p2]) - 1
MEMBER [Measures].[i0p2Rem] AS ([i0p2] - FIX([i0p2]))
MEMBER [Measures].[n0p2Lo] AS (OrderedData.Item([i0p2Lo]), [Measures].[rate])
MEMBER [Measures].[n0p2Hi] AS (OrderedData.Item([i0p2Lo] + 1), [Measures].[rate])
MEMBER [Measures].[PCT0p2] AS [n0p2Lo] + ( [i0p2Rem] * ( [n0p2Hi] - [n0p2Lo] ))
MEMBER [Measures].[i0p5] AS ( .5* ( [RowCount] - 1 ) ) + 1
MEMBER [Measures].[i0p5Lo] AS FIX([i0p5]) - 1
MEMBER [Measures].[i0p5Rem] AS ([i0p5] - FIX([i0p5]))
MEMBER [Measures].[n0p5Lo] AS (OrderedData.Item([i0p5Lo]), [Measures].[rate])
MEMBER [Measures].[n0p5Hi] AS (OrderedData.Item([i0p5Lo] + 1), [Measures].[rate])
MEMBER [Measures].[PCT0p5] AS [n0p5Lo] + ( [i0p5Rem] * ( [n0p5Hi] - [n0p5Lo] ))
--MEMBER [Measures].[PCT0p5] AS Median(OrderedData, [Measures].[Weight])
MEMBER [Measures].[i0p8] AS ( .8* ( [RowCount] - 1 ) ) + 1
MEMBER [Measures].[i0p8Lo] AS FIX([i0p8]) - 1
MEMBER [Measures].[i0p8Rem] AS ([i0p8] - FIX([i0p8]))
MEMBER [Measures].[n0p8Lo] AS (OrderedData.Item([i0p8Lo]), [Measures].[rate])
MEMBER [Measures].[n0p8Hi] AS (OrderedData.Item([i0p8Lo] + 1), [Measures].[rate])
MEMBER [Measures].[PCT0p8] AS [n0p8Lo] + ( [i0p8Rem] * ( [n0p8Hi] - [n0p8Lo] ))
MEMBER [Measures].[i0p98] AS ( .98* ( [RowCount] - 1 ) ) + 1
MEMBER [Measures].[i0p98Lo] AS FIX([i0p98]) - 1
MEMBER [Measures].[i0p98Rem] AS ([i0p98] - FIX([i0p98]))
MEMBER [Measures].[n0p98Lo] AS (OrderedData.Item([i0p98Lo]), [Measures].[rate])
MEMBER [Measures].[n0p98Hi] AS (OrderedData.Item([i0p98Lo] + 1), [Measures].[rate])
MEMBER [Measures].[PCT0p98] AS [n0p98Lo] + ( [i0p98Rem] * ( [n0p98Hi] - [n0p98Lo] ))
member Ecart1 as [Measures].[PCT0p2]-[Measures].[PCT0p02]
member Ecart2 as [Measures].[PCT0p5]-[Measures].[PCT0p2]
member Ecart3 as [Measures].[PCT0p8] - [Measures].[PCT0p5]
member Ecart4 as [Measures].[PCT0p98] -[Measures].[PCT0p8]
member localRate as ([Dim misc].[Speciality Id].&[{77-AA1B-4E57-AB73-27}], [Measures].rate)
SELECT{ PCT0p02, Ecart1, Ecart2, Ecart3, Ecart4 ,PCT0p98 ,localRate } on 0
--SELECT {nballPatsTransfusedOneSpe , nballPatsOneSpe,nballPatsTransfusedOfSameSpes ,nballPatsOfSameSpes ,localRate} ON 0
--SELECT {} ON 0, {OrderedData} ON 1
FROM [BDD PBM]
--[Dim misc].[SpePats].[Hospital Id].&[{274DED7-8605-EA4E741DF116}].&[CH de ABCD].&[{26FBAA2E661}]
--WHERE [Dim misc].[SpePats].&[{7-AA1B-4E57-AB73-89127}]

Related

Split data element based on delimiter

I have a database called Property with a table called Location. The data looks like this:
RecordID Location
-----------------------
1 1/21/s15
2 8/1/21c59
3 1//
4 9//72
I have a script that reads records from the table and inserts them into a second table called ExpandedLocation.
This is the code of my script:
INSERT INTO [Property].[dbo].[ExpandedLocation] (LocationA, LocationB, LocationC)
SELECT
dbo.fnBuildABC(Location, 1),
dbo.fnBuildABC(Location, 2),
dbo.fnBuildABC(Location, 3)
FROM
[Property].[dbo].[Location]
This code should call the function fnBuildABC and pass it 2 parameters, Location and a number. The function should take in the parameters and split the first parameter on the slash and return either the 1st, 2nd, or 3rd portion of the passed string.
So, for example, on the first read of the Location table, I pick up the value 1/21/s15.
The function should return the following:
Parameter Value Returned Value
---------------------------------
Location, 1 1
Location, 2 21
Location, 3 s15
On the second read of the Location table, I pick up the value 8/1/21c59. The function should return the following:
Parameter Value Returned Value
-----------------------------------
Location, 1 8
Location, 2 1
Location, 3 21c59
I'm at a loss as to how to split the passed string in the function without actually inspecting each character of the string one at a time.
Any suggestions on how to start this process would be greatly appreciated. Thank you.
I would build a function that splits your string and returns 3 columns as a table.
With just 3 columns you can comfortably do that with a combination of SQL Server's string functions.
An example of a function would be:
create or alter function fnBuildABC(#location varchar(10))
returns table
as
return
select
Left(location, p1.v - 1) A,
Substring(location, p1.v + 1, p2.v - p1.v - 1) B,
Stuff(location, 1, p2.v, '') C
from (select location = #Location)l
cross apply(values(CharIndex('/', location)))p1(v)
cross apply(values(CharIndex('/', location, p1.v + 1)))p2(v);
And then you can use it with your Location table:
insert into Property.dbo.ExpandedLocation (LocationA, LocationB, LocationC)
select A, B, C
from dbo.Location
cross apply fnBuildABC(Location);
Example DB<>Fiddle
Output:
You may try using XML method as the following:
CREATE FUNCTION fnBuildABC( #loc VARCHAR(MAX))
RETURNS #splitted TABLE
(
[Parameter Value] INT,
[Returned Value] VARCHAR(50)
)
AS
BEGIN
DECLARE #xml xml;
SET #xml = N'<root><p>' + replace(#loc, '/','</p><p>') + '</p></root>';
INSERT INTO #splitted
SELECT ROW_NUMBER() OVER (ORDER BY l_pos) AS pos,
l_pos.value('.', 'VARCHAR(50)') AS val
FROM
#xml.nodes('//root/p') AS Portions(l_pos)
RETURN;
END;
To get all portions of a location call the function as the following:
SELECT CONCAT('Location: ', [Parameter Value]) AS [Parameter Value], [Returned Value]
FROM
(
SELECT L.RecordID, P.* FROM ExpandedLocation L
OUTER APPLY
fnBuildABC(Location) P
) T
WHERE RecordID = 1;
To get specific portions, i.e. 1 & 2:
SELECT CONCAT('Location: ', [Parameter Value]) AS [Parameter Value], [Returned Value]
FROM
(
SELECT L.RecordID, P.* FROM ExpandedLocation L
OUTER APPLY
fnBuildABC(Location) P
) T
WHERE RecordID = 1 AND [Parameter Value] IN (1,2);
See demo.
SQL Server has a built in STRING_SPLIT function that you can probably use. It returns a table of split values.
SELECT value FROM STRING_SPLIT('1/21/s15', '/')
Example output:
Value
1
21
s15

Error converting data type nvarchar to int in multiple Pivot on same column SQL

I am trying to use multiple pivot in a single query on same column.
Since i am using same column "month" for all the pivot's, i have added column header to the select list and have added different alias name. Month column has int datatype value. Below is the code:
Select * FROM
(
SELECT
[team],
Count_O,
Count_Of_OA,
Avg,
[month]+ '_a' as month_a,
[month] + '_b' as month_b,
[users]
FROM [#Temp]
) AS X
PIVOT
(
MAX(Count_OA)
FOR [month_a] IN ([4_a], [5_a], [6_b])
) AS PivotTable1
PIVOT
(
MAX(Count_O)
FOR [month_b] IN ([4_b], [5_b], [6_b])
) AS PivotTable2
When i execute this, I get the below error:
Msg 8114, Level 16, State 1, Line 44
Error converting data type nvarchar to int.
Any inputs would be much appreciated.
Try this
Select * FROM
(
SELECT
[team],
Count_O,
Count_Of_OA,
Avg,
Convert(varchar(max),[month])+ '_a' as month_a,
Convert(varchar(max),[month]) + '_b' as month_b,
[users]
FROM [#Temp]
) AS X
PIVOT
(
MAX(Count_OA)
FOR [month_a] IN ([4_a], [5_a], [6_b])
) AS PivotTable1
PIVOT
(
MAX(Count_O)
FOR [month_b] IN ([4_b], [5_b], [6_b])
) AS PivotTable2

How to split value to another column?

I have data input and want output in picture. How do I to write it?
i can run in sql server for this but i get only width column( w_pacakaging) , but i dont know to write get value length or high from column text (db name : [Packing list text])
my code is
select [Packing list text],[Grade],[sales doc no],
case when [Packing list text] like'%:%' then
cast(Ltrim(Rtrim(SUBSTRING([Packing list text], charindex(':', [Packing list text]) + 1, charindex('"', [Packing list text])
- (charindex(':', [Packing list text]) + 1)))) as [nvarchar] )
END AS [W_packaging]
from [TPC_CRSYS].[dbo].[TotalOrder_Export]
the result from sql server
enter image description here
How could you advice me for write sql to get data for length and heigh from table [TotalOrder_Export] because it has more than one x in each record
could anyone advice me
the easy way using CTE and CHARINDEX:
;with
T AS ( -- select the base table, adding an index for performances pourpose
SELECT *, ROW_NUMBER() OVER (ORDER BY [sales doc no],[Packing list text]) ROW_IDX
FROM [TPC_CRSYS].[dbo].[TotalOrder_Export]
),
W AS (-- SELECT ONLY ROWS WITH VALID DIMENSIONS AND CALC WIDTH POSITION
SELECT *, CHARINDEX('(WXLXH): ', [Packing list text])+9 W_POS
FROM T
WHERE CHARINDEX('(WXLXH): ', [Packing list text])>0
),
L AS (-- CALC LENGTH POSITION
SELECT *, CHARINDEX('"', [Packing list text], W_POS)+2 L_POS
FROM W
),
H AS (-- CALC HEIGHT POSITION
SELECT *, CHARINDEX('"', [Packing list text], L_POS)+2 H_POS
FROM L
),
X AS (-- CALC
SELECT *, CHARINDEX('"', [Packing list text], H_POS) END_POS
FROM H
)
SELECT T.[Packing list text], T.grade, T.[sales doc no]
, SUBSTRING(T.[Packing list text], W_POS, L_POS-2-W_POS) W
, SUBSTRING(T.[Packing list text], L_POS, H_POS-2-L_POS) L
, SUBSTRING(T.[Packing list text], H_POS, END_POS-H_POS) H
FROM T
LEFT JOIN X ON T.ROW_IDX = X.ROW_IDX
alternatively, you can use OUTER APPLY and a split (FN_SPLIT) function to get w/h/l in rows for each [Packing list text], and then PIVOT them back to one single line:
;with
T AS ( -- select the base table, adding an index for performances pourpose
SELECT *, ROW_NUMBER() OVER (ORDER BY [sales doc no], [Packing list text]) ROW_IDX
FROM [TPC_CRSYS].[dbo].[TotalOrder_Export]
),
W AS (-- SELECT ONLY ROWS WITH VALID DIMENSIONS AND CALC WIDTH POSITION
SELECT *, CHARINDEX('(WXLXH): ', [Packing list text])+9 W_POS
FROM T
WHERE CHARINDEX('(WXLXH): ', [Packing list text])>0
),
spl as (
select W.ROW_IDX, d.*
from w
outer apply (
select ID, SUBSTRING(data,2,100) VAL
from FN_SPLIT(SUBSTRING(w.[Packing list text], w_pos-1, 100),'"') s
where s.id<=3
) d
),
X AS (
SELECT *
FROM spl
PIVOT (MIN(VAL) FOR ID IN ([1],[2],[3])) P
)
SELECT T.[Packing list text], T.grade, T.[sales doc no], X.[1] W, X.[2] L, X.[3] H
FROM T
LEFT JOIN X ON T.ROW_IDX = X.ROW_IDX
this second version is faster if you have many rows in your [TotalOrder_Export] table
for the split function, you will find many versions around, I made this:
CREATE FUNCTION [dbo].[FN_SPLIT]
(
#Line varchar(8000),
#SplitOn varchar(10) = ','
)
RETURNS #RtnValue table
(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, -- VERY USEFUL TO MAKE JOINS AND TO CREATE THE UNIQUE INDEX ON SPLITTED STRINGS
Data varchar(800) NOT NULL,
UNIQUE (DATA, ID) -- THIS WILL MAKE REALLY FASTER THE QUERIES USING THIS FUNCTION
)
AS
BEGIN
IF #Line IS NULL RETURN
DECLARE #split_on_len INT = LEN(#SplitOn+'X')-1 -- TO CATCH TRAILING SPACES PROBLEM WITH LEN()
DECLARE #line_len INT = LEN(#line+'X')-1
DECLARE #start_at INT = 1
DECLARE #end_at INT
DECLARE #data_len INT
WHILE 1=1
BEGIN
IF #start_at > #line_len BREAK;
SET #end_at = CHARINDEX(#SplitOn, #Line, #start_at)
SET #data_len = CASE #end_at WHEN 0 THEN #line_len ELSE #end_at-#start_at END
INSERT INTO #RtnValue (data) VALUES( SUBSTRING(#Line,#start_at,#data_len));
SET #start_at = #start_at + #data_len + #split_on_len
END
RETURN
END
I hope this helps

Table totals to scalar variable in HANA

I'm currently working with writing database procedures for HANA via ABAP objects. I'd like to return a scalar value which is calculated from a selection rather than a table which the other developer would have to read from a table. I'd prefer that I'm not declaring variables to use in the store procedure through the importing/exporting parameters.
methods: _amdp_previous_years
importing value(mandt) type mandt
value(in_object) type j_objnr
value(in_year) type gjahr
exporting value(out_results) type total_table
value(out_total) type f.
method _amdp_previous_years by database procedure for hdb
language sqlscript options read-only
using rpsco.
declare totals double array;
declare out_array double array;
-- begin of totals,
-- total type float,
-- end of totals,
-- out_results = type table of totals
out_results = select sum( wlp01 ) + sum( wlp02 ) + sum( wlp03 ) + sum( wlp04 ) + sum( wlp05 ) +
sum( wlp06 ) + sum( wlp07 ) + sum( wlp08 ) + sum( wlp09 ) + sum( wlp10 ) +
sum( wlp11 ) + sum( wlp12 ) + sum( wlp13 ) + sum( wlp14 ) + sum( wlp15 ) +
sum( wlp16 ) as total from rpsco
where objnr = :in_object
and gjahr = :in_year;
totals := array_agg( :out_results.total );
out_total := :totals[1];
-- Type not declared
-- in sap = wlp01 = curr(15,2)
-- total is not a decimal
-- total is not a double
-- total is not a float
-- total is not a int
-- total is not a real
-- what is total supposed to be then?
results = select sum( wlp01 ) + sum( wlp02 ) + sum( wlp03 ) + sum( wlp04 ) + sum( wlp05 ) +
sum( wlp06 ) + sum( wlp07 ) + sum( wlp08 ) + sum( wlp09 ) + sum( wlp10 ) +
sum( wlp11 ) + sum( wlp12 ) + sum( wlp13 ) + sum( wlp14 ) + sum( wlp15 ) +
sum( wlp16 ) as total from rpsco
where objnr = :in_object
and gjahr = :in_year;
out_array := array_agg( :results.total );
endmethod.
The first statement works ok, I'm guessing because the result of the selection gets placed into a field that is declared as an ABAP float.
The second selection works and results is populated, however I'm not sure how to access the columns. The SAP data element is a CURRENCY field (15,2). I've tried all of the scalar types in the documentation. I received the same error that it is not the correct type.
Is this not possible because the type isn't explicitly defined before hand? While looking around the internet at tutorials people suggest using CREATE TYPE or CREATE TABLE, but I receive syntax errors when trying to use these statements.
I can answer this myself in case anybody else stumbles upon this. You can typecast the columns via various functions such as to_double( ), to_integer( ), and so forth. Now the selection looks like:
results = select to_double( sum( wlp01 ) + sum( wlp02 ) + sum( wlp03 ) + sum( wlp04 ) + sum( wlp05 ) +
sum( wlp06 ) + sum( wlp07 ) + sum( wlp08 ) + sum( wlp09 ) + sum( wlp10 ) +
sum( wlp11 ) + sum( wlp12 ) + sum( wlp13 ) + sum( wlp14 ) + sum( wlp15 ) +
sum( wlp16 ) ) as total from rpsco
where objnr = :in_object
and gjahr < :in_year;

SQL - displaying row where the next numeric value is also available

I have the following query:
SELECT CAST(year_week AS NUMERIC) as year_week FROM web_details where location = ''JF'' AND property_id = ''FARM''
which produces the following results.
YEAR_WEEK
201035
201036
201037
201039
201041
201044
201045
201048
What I actually want is to produce a set of results which only displays values if the consecutive value is available - so producing the following results...
YEAR_WEEK
201035
201036
201044
To add another spanner into the works, the column year_week is not a numeric value so has needed to be converted.
Thanks
SELECT
CAST(year_week AS NUMERIC) as year_week
FROM
web_details wd
WHERE
EXISTS(
SELECT
year_week
FROM
web_details wd2
WHERE
wd2.year_week = CASE(RIGHT(wd.year_week, 2))
WHEN '48' THEN CAST((CAST(LEFT(wd.year_week,4) AS INT) + 1) AS VARCHAR(4)) + '01'
ELSE LEFT(wd.year_week,4) + CAST((CAST(RIGHT(wd.year_week,2) AS INT) + 1) AS VARCHAR(2))
END
)
Basically, my approach is that you calculate another column that contains the next year_week value, and the join it to itself.
WITH myCTE AS (
SELECT year_week, CONVERT(VARCHAR(4),DATEPART(year,CONVERT(datetime,LEFT(year_week,4)) + (RIGHT(year_week,2) + 1) * 7 )) + RIGHT( '000' + CONVERT(VARCHAR(2),DATEPART(MONTH,CONVERT(datetime,LEFT(year_week,4)) + (RIGHT(year_week,2) + 1) * 7)),2) next_year_week
FROM web_details
WHERE ..........
)
SELECT T1.year_week, T2.year_week
FROM myCTE T1
INNER JOIN myCTE T2 ON T1.next_year_week = T2.year_week