SQL function not displaying two decimal places although input parameter value is float - sql

I have a function that rounds to the nearest value in SQL as per below. When I pass my value in and run the function manually, it works as expected. However when I use it within a select statement, it removes the decimal places.
E.g. I expect the output to be 9.00 but instead I only see 9.
CREATE FUNCTION [dbo].[fn_PriceLadderCheck]
(#CheckPrice FLOAT,
#Jur VARCHAR(10))
RETURNS FLOAT
AS
BEGIN
DECLARE #ReturnPrice FLOAT
IF (#Jur = 'SE')
BEGIN
SET #ReturnPrice = (SELECT [Swedish Krona ]
FROM tbl_priceladder_swedishkrona
WHERE [Swedish Krona ] = #CheckPrice +
(SELECT MIN(ABS([Swedish Krona ] - #CheckPrice))
FROM tbl_priceladder_swedishkrona)
OR [Swedish Krona ] = #CheckPrice -
(SELECT MIN(ABS([Swedish Krona ] - #CheckPrice))
FROM tbl_priceladder_swedishkrona))
END
IF (#Jur = 'DK')
BEGIN
SET #ReturnPrice = (SELECT [Danish Krone ]
FROM tbl_priceladder_danishkrone
WHERE [Danish Krone ] = #CheckPrice +
(SELECT MIN(ABS([Danish Krone ] - #CheckPrice))
FROM tbl_priceladder_danishkrone)
OR [Danish Krone ] = #CheckPrice -
(SELECT MIN(ABS([Danish Krone ] - #CheckPrice))
FROM tbl_priceladder_danishkrone))
END
RETURN #ReturnPrice
END
Run SQL manually:
declare #checkprice float
set #checkprice = '10.3615384615385'
SELECT [Swedish Krona ]
FROM tbl_priceladder_swedishkrona
WHERE [Swedish Krona ] = #CheckPrice +
( SELECT MIN(ABS([Swedish Krona ] - #CheckPrice))
FROM tbl_priceladder_swedishkrona
)
OR [Swedish Krona ] = #CheckPrice -
( SELECT MIN(ABS([Swedish Krona ] - #CheckPrice))
FROM tbl_priceladder_swedishkrona
)
When I use this function with a SQL select statement for some reason it removes the 2 decimal points.
SELECT
Article, Colour,
dbo.fn_PriceLadderCheck([New Price], 'se') AS [New Price]
FROM
#temp2 t
[New Price] on its own is example output is 10.3615384615385
Any ideas?

Cast the result into a Decimal and specify the scale.
See the example below.
RETURN SELECT CAST(#ReturnPrice AS DECIMAL(16,2))

Related

Combine conditions in table expression?

I am using the line_index function and would like to search for two values, not only for carrid but also for connid. Is it possible? If so, in what way?
Because right now, this works:
lv_index = line_index( lt[ carrid = 'LH' ] ).
But after adding the code [ connid = '2407' ] like this:
lv_index = line_index( lt[ carrid = 'LH' ][ connid = '2407' ] ).
I get a syntax error:
LT[ ] is not an internal table
All fields (conditions) just one after the other inside one bracket:
lv_index = line_index( lt[ carrid = 'LH'
connid = '2407' ] ).
I'd like to comment about the chaining of Table Expressions.
So the answer corresponding to the OP example is that a single Table Expression must be used (itab[...]) with as many components as needed, and not a chain of table expressions as was done (itab[...][...]).
lt[ carrid = 'LH' ][ connid = '2407' ] can never be valid (because connid = '2407' would imply that each line of LT is itself an internal table but carrid = 'LH' is contradictory as it means that each line of LT is a structure).
But other syntaxes of chained table expressions can be valid, like e.g. (provided that the internal tables are defined adequately)
itab[ 1 ][ comp1 = 'A' ]
itab[ comp1 = 'A' ][ 1 ]
itab[ comp1 = 'A' ]-itabx[ compx = 42 ]
Here is an example that you can play with:
TYPES: BEGIN OF ty_structure,
connid TYPE c LENGTH 4,
END OF ty_structure,
ty_table TYPE STANDARD TABLE OF ty_structure WITH EMPTY KEY,
BEGIN OF ty_structure_2,
carrid TYPE c LENGTH 2,
table TYPE ty_table,
END OF ty_structure_2,
ty_table_2 TYPE STANDARD TABLE OF ty_structure_2 WITH EMPTY KEY,
ty_table_3 TYPE STANDARD TABLE OF ty_table_2 WITH EMPTY KEY.
DATA(lt) = VALUE ty_table_3( ( VALUE #( ( carrid = 'LH' table = VALUE #( ( connid = '2407' ) ) ) ) ) ).
DATA(structure) = lt[ 1 ][ carrid = 'LH' ]-table[ connid = '2407' ].

MDX Get a TopCount over multiple dimensions and add a rest/remainder (icCube)

I would like to create a TopCount over multiple dimensions, and include a "rest"/"remainder" and a sub-total.
I use the following MDX on the default Sales schema in icCube:
with
member [Product].[Product].[All Products].[rest] as "All Products - top 2"
SET [top] AS
Generate( { {[Customers].[Geography].[Region] } * [Time].[Calendar].[2010] } as s1,
TopCount( s1.CurrentMember * [Product].[Product].[Article].Members, 2, [Measures].[Amount] ) + s1.CurrentMember * {[Product].[Product].[All Products].[rest] , [Product].[Product].[All Products]} )
select
[Measures].[Amount] on 0
[top] on rows
from sales
The result is in the following picture.
How to get a value for "rest"? Using the formula: "All Products" -/- the Top 2
The answer will depend on whether the dimension includes many-to-many relations or not.
If there are no many-to-many, you can either use the SubCubeComplement function:
MEMBER [Product].[Product].[All Products].[rest] as Eval( SubCubeComplement( TopCount( [Product].[Product].[Article].Members, 2, [Measures].[Amount]) ) , [Product].[Product].defaultMember )
or calculate it (all minus the sum of the TopCount set):
MEMBER [Product].[Product].[All Products].[rest] as ([Product].[Product].defaultMember) - Sum( TopCount( [Product].[Product].[Article].Members, 2, [Measures].[Amount]), [Product].[Product].currentMember )
The risk here is that in case you have many-to-many relations, the two solutions above can be subtracting unwanted rows (as they may contain articles that should have been in the final set.)
Therefore, if you have many-to-many relations use the Eval function with the following syntax:
MEMBER [Product].[Product].[All Products].[rest] as Eval( [Product].[Product].[Article].Members - TopCount( [Product].[Product].[Article].Members, 2, [Measures].[Amount]), [Product].[Product].defaultMember )
The statement will therefore be (please note the adjustment on the [top] set definition):
with
// v1 (no many-to-many) - behaves like a FILTERBY
// MEMBER [Product].[Product].[All Products].[rest] as Eval( SubCubeComplement( TopCount( [Product].[Product].[Article].Members, 2, [Measures].[Amount]) ) , [Product].[Product].defaultMember )
//v2 (no many-to-many)
// MEMBER [Product].[Product].[All Products].[rest] as ([Product].[Product].defaultMember) - Sum( TopCount( [Product].[Product].[Article].Members, 2, [Measures].[Amount]), [Product].[Product].currentMember )
//v3 (many-to-many)
MEMBER [Product].[Product].[All Products].[rest] as Eval( [Product].[Product].[Article].Members - TopCount( [Product].[Product].[Article].Members, 2, [Measures].[Amount]), [Product].[Product].defaultMember )
SET [top] AS
Generate( { {[Customers].[Geography].[Region] } * [Time].[Calendar].[2010] } as s1,
s1.CurrentMember * TopCount( [Product].[Product].[Article].Members, 2, [Measures].[Amount] ) + s1.CurrentMember * {[Product].[Product].[All Products].[rest] , [Product].[Product].[All Products]} )
select
[Measures].[Amount] on 0
[top] on rows
from sales
Version 3 will also work if there are no many-to-many relations.
After some time puzzling I found the solution.
The solution is a combination of icCube's MDX++ functions, namely SubCubeMinus in combination with the category member.
Here's the answer:
with
SET [top 2] as
Generate( { {[Customers].[Geography].[Region] } * [Time].[Calendar].[2010] } as s1,
TopCount( s1.CurrentMember * [Product].[Product].[Article].Members, 2, [Measures].[Amount] ) )
category calculated member [Product].[Product].[All Products].[rest] as subcubeminus(([Customers].[Geography].[All Regions] , [Time].[Calendar].[2010], [Product].[Product].[All Products]) , [top 2])
SET [top 2] as
Generate( { {[Customers].[Geography].[Region] } * [Time].[Calendar].[2010] } as s1,
TopCount( s1.CurrentMember * [Product].[Product].[Article].Members, 2, [Measures].[Amount] ) )
SET [tuples_top2_rest_total] AS
Generate( { {[Customers].[Geography].[Region] } * [Time].[Calendar].[2010] } as s1,
TopCount( s1.CurrentMember * [Product].[Product].[Article].Members, 2, [Measures].[Amount] ) + s1.CurrentMember * {[Product].[Product].[All Products].[rest] , [Product].[Product].[All Products]} )
select
[Measures].[Amount] on 0
[tuples_top2_rest_total] on rows
from sales
Result
Explanation
Create the Top 2 using the Generate function;
Create the calculated category member "rest" (ie others) all the data in the cube for Total Region, 2010 and Total Product MINUS the TOP 2 per combination for region and 2010.

Collapse elements of array of structs in BigQuery

I have an array of structs in BigQuery that looks like:
"categories": [
{
"value": "A",
"question": "Q1",
},
{
"value": "B",
"question": "Q2",
},
{
"value": "C",
"question": "Q3",
}
]
I'd like to collapse the values "A", "B" and "C" into a separate column, and the value for this particular row should be something like "A - B - C".
How can I do this with a query in BigQuery?
Consider below
select id,
( select string_agg(value, ' - ')
from t.questions_struct) values
from questions t
if applied to sample data in your question/answer -
with questions as (
SELECT 1 AS id,
[
STRUCT("A" as value, "Q1" as question),
STRUCT("B" as value, "Q2" as question),
STRUCT("C" as value, "Q3" as question)
] AS questions_struct
)
output is
Assuming this is an array of structs, you can use:
select (select q.value from unnest(ar) q where q.question = 'q1') as q1,
(select q.value from unnest(ar) q where q.question = 'q2') as q2,
(select q.value from unnest(ar) q where q.question = 'q3') as q3
from t;
I think it can be done with the following code:
with questions as (
SELECT 1 AS id,
[
STRUCT("A" as value, "Q1" as question),
STRUCT("B" as value, "Q2" as question),
STRUCT("C" as value, "Q3" as question)
] AS questions_struct
), unnested as (
select * from questions, unnest(questions_struct) as questions_struct
) select id, string_agg(value, ' - ') from unnested group by 1

SQL Variable Changing Value

I'm trying to rewrite the following code to use a variable instead of magic numbers:
SELECT tokenId,
IIF(LEN(ref) < 4, ref, REPLICATE(CONVERT(NVARCHAR(20),'*'), LEN(ref)-4) + SUBSTRING(ref, (LEN(ref)-3), LEN(ref))) as refMasked
FROM tokenBase
WHERE (refMasked is null or refMasked = '') AND ref is not null AND ref <> ''
I tried doing it like this:
DECLARE #NumberOfCharsAtEndOfStringToNotMask INTEGER
SET #NumberOfCharsAtEndOfStringToNotMask = 4 --Why do I need to set this to 2 for it to work?
SELECT tokenId,
IIF(LEN(ref) < #NumberOfCharsAtEndOfStringToNotMask, ref, REPLICATE(CONVERT(NVARCHAR(20),'*'), LEN(ref)-#NumberOfCharsAtEndOfStringToNotMask) + SUBSTRING(ref, (LEN(ref)-#NumberOfCharsAtEndOfStringToNotMask-1), LEN(ref))) as refMasked
FROM tokenBase
WHERE (refMasked is null or refMasked = '') AND ref is not null AND ref <> ''
However it doesn't work if I use #NumberOfCharsAtEndOfStringToNotMask = 4, I need to use 2 instead. Why is this?
If I use 4 then the last 6 chars of the string are left unmasked, however I need the last 4 chars to be unmasked. Using a value of 2 fixes this but I have no idea why.
EDIT
Amit has suggested I use the following code which works:
IIF(LEN(ref) < #NumberOfCharsAtEndOfStringToNotMask, ref,REPLICATE(CONVERT(NVARCHAR(20),'*'), LEN(ref)-#NumberOfCharsAtEndOfStringToNotMask) + SUBSTRING(ref, (LEN(ref)-#NumberOfCharsAtEndOfStringToNotMask+1),#NumberOfCharsAtEndOfStringToNotMask)) as refMasked
Why does this work? Why can't I just replace the use of 4 with a variable storing the value of 4?
Try this Dave:
DECLARE #C INTEGER = 4;
SELECT bpayreference
, LEN(bpayreference) As LengthOfString
, LEN(bpayreference) - #C AS MinusC
, SUBSTRING(bpayreference , (LEN(bpayreference) - #C) + 1 , (LEN(bpayreference) ) - (LEN(bpayreference) - #C))
, CASE
WHEN (LEN(bpayreference) < #C) THEN REPLICATE('*' , LEN(bpayreference) - #C)
ELSE
REPLICATE('*' , LEN(bpayreference) - #C )
+ SUBSTRING(bpayreference , (LEN(bpayreference) - #C) + 1 , (LEN(bpayreference) ) - (LEN(bpayreference) - #C))
END
FROM tokenbase
Replace your iif block with this one and see how you go
IIF(LEN(ref) < #NumberOfCharsAtEndOfStringToNotMask, ref,REPLICATE(CONVERT(NVARCHAR(20),'*'), LEN(ref)-#NumberOfCharsAtEndOfStringToNotMask) + SUBSTRING(ref, (LEN(ref)-#NumberOfCharsAtEndOfStringToNotMask+1),#NumberOfCharsAtEndOfStringToNotMask)) as refMasked

Second MDX Query has to return result for each row returned by 1st MDX Query

I have a Situation where I am looking for MDX Guidance.
Environment: SQL Server 2008 R2,SSRS 2008 R2
Dimension:Columns
DimMainProvider :ProviderName
DimAcademicYear:AcademicYear
DimSectorSubjectArea:Estyn
DimLearningAim:LearningAimReference
Fact:Columns
Learnings:MainProviderKey,AgeBandKey,LearningAimKey,SuccessFlag
What I want is
1) For a particular MainProvider Get Top 10 LearningAims by Success Rate and show it in tablix
2) For a each Row on tablix also show Box plot graph which essentially needs Min,Max,Quartile1,Quartile3 success rates of that particular LearningAim across all Mainproviders
What I have is 2 MDX queries
a) one which gets top 10 Activities for a Main Provider (Simplified
Version of MDX below)
WITH
SET Top10LearningAimsForSuccessRate
AS
NonEmpty(
TOPCOUNT([ReportedLearningAims],10,[Measures].[SuccessRate]),
[Measures].[SuccessRate]
)
SELECT
{
[Measures].[SuccessRate]
} ON COLUMNS
,NON EMPTY
{
EXISTS(
Top10LearningAimsForSuccessRate
,,"Learnings")
} ON ROWS
FROM
(
SELECT {[Measures].[TerminatedAssessableLASum]
,[Measures].[SuccessfulLASum]} ON COLUMNS
,{(StrToSet("[DimMainProvider].[ProviderName].&[44]",CONSTRAINED))} On ROWS
FROM [FECube]
)
WHERE
( StrToSet("[DimAcademicYear].[AcademicYear].[AcademicYear].[2009/10]",CONSTRAINED),
StrToSet("[DimSectorSubjectArea].[Estyn].&[2]",CONSTRAINED)
)
b) Another query which accepts LearningAim as a Parameter and does
Statistical Calculations and gives me values (Simplified Version of
MDX below)
WITH
SET ProviderwideLearningAims
AS
ORDER(
NonEmpty( [DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]
)
,[Measures].[SuccessRate],BASC
)
MEMBER [Measures].[MaxValue]
AS
Max(ProviderwideLearningAims,[SuccessRate]),FORMAT_STRING = "Percent"
MEMBER [Measures].[MinValue]
AS
Min(ProviderwideLearningAims,[SuccessRate]),FORMAT_STRING = "Percent"
MEMBER [Measures].[MedianValue]
AS
Median(ProviderwideLearningAims,[SuccessRate]),FORMAT_STRING = "Percent"
Member [Measures].[ProviderCount] As [ProviderwideLearningAims].Count
MEMBER [Measures].[MeanValue]
AS
(SUM(ProviderwideLearningAims,[SuccessRate])/[Measures].[ProviderCount]),FORMAT_STRING = "Percent"
MEMBER [Measures].[LearningAimUniqueName]
AS
[DimLearningAim].[LearningAimReference].CurrentMember.UniqueName
Select
{ [Measures].[LearningAimUniqueName]
,[Measures].[MinValue]
,[Measures].[MaxValue]
,[Measures].[MedianValue]
,[Measures].[MeanValue]
} ON COLUMNS,
{
NonEmpty([DimLearningAim].[LearningAimReference].[LearningAimReference],ProviderwideLearningAims)
} ON ROWS
FROM
(
SELECT
StrToSet("[DimLearningAim].[LearningAimReference].&[50024991]",CONSTRAINED) ON COLUMNS
FROM [FECube]
)
WHERE
( StrToSet("[DimAcademicYear].[AcademicYear].[AcademicYear].[2009/10]",CONSTRAINED),
StrToSet("[DimSectorSubjectArea].[Estyn].&[2]",CONSTRAINED)
)
My original Idea is to fire 2nd query for each Learning Aim received
from 1st query,but I am not able to implement this in SSRS Dataset
Model.
So Now I am back at MDX level and want somehow to merge these
two.
Here is how I fixed it with help from Deepak Puri on MSDN forums
With Set [Top10LearningAims] as TOPCOUNT(
Filter(([ReportedLearningAims]*[DimMainProvider].[ProviderName].MEMBERS),[DimMainProvider].[ProviderName].CURRENTMEMBER
IS STRTOMEMBER("[DimMainProvider].[ProviderName].&[44]") )
,10,[Measures].[TerminatedAssessableLASum]
)
MEMBER [Measures].[MaxValue] AS
Max(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate]),FORMAT_STRING =
"Percent" MEMBER [Measures].[MinValue] AS
Min(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate]),FORMAT_STRING =
"Percent" MEMBER [Measures].[MedianValue] AS
Median(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate]), FORMAT_STRING =
"Percent"
MEMBER [Measures].[MeanValue] AS
Avg(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate]), FORMAT_STRING =
"Percent"
Member [Measures].[ProviderCount] as
Count(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate])) Member [Measures].[PercentileInt25] as
Int((([Measures].[ProviderCount] - 1) * 25) / 100) Member
[Measures].[PercentileFrac25] as (([Measures].[ProviderCount] - 1) *
25) / 100
- [Measures].[PercentileInt25] Member [Measures].[PercentileLo25] as
([Measures].[SuccessRate],
Order(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate],
BASC).Item([Measures].[PercentileInt25]).Item(0)), FORMAT_STRING =
"Percent" Member [Measures].[PercentileHi25] as
([Measures].[SuccessRate],
Order(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate],
BASC).Item([Measures].[PercentileInt25] + 1).Item(0)), FORMAT_STRING =
"Percent" Member [Measures].[Percentile25Value] as
([Measures].[PercentileLo25] * (1 - [Measures].[PercentileFrac25]))
+ ([Measures].[PercentileHi25] * [Measures].[PercentileFrac25]),
FORMAT_STRING = "Percent" Member [Measures].[PercentileInt75] as
Int((([Measures].[ProviderCount] - 1) * 75) / 100) Member
[Measures].[PercentileFrac75] as (([Measures].[ProviderCount] - 1) *
75) / 100
- [Measures].[PercentileInt75] Member [Measures].[PercentileLo75] as
([Measures].[SuccessRate],
Order(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate],
BASC).Item([Measures].[PercentileInt75]).Item(0)), FORMAT_STRING =
"Percent" Member [Measures].[PercentileHi75] as
([Measures].[SuccessRate],
Order(NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]), [Measures].[SuccessRate],
BASC).Item([Measures].[PercentileInt75] + 1).Item(0)), FORMAT_STRING =
"Percent" Member [Measures].[Percentile75Value] as
([Measures].[PercentileLo75] * (1 - [Measures].[PercentileFrac75]))
+ ([Measures].[PercentileHi75] * [Measures].[PercentileFrac75]),
FORMAT_STRING = "Percent"
select { [Measures].[TerminatedAssessableLASum]
,[Measures].[SuccessfulLASum]
,[Measures].[SuccessRate]
,[Measures].[SectorTerminatedAssessableLASum]
,[Measures].[SectorSuccessfulLASum]
,[Measures].[SectorSuccessRate]
,[Measures].[ProviderCount] ,[Measures].[MinValue]
,[Measures].[MaxValue] ,[Measures].[MeanValue]
,[Measures].[Percentile25Value] ,[Measures].[MedianValue]
,[Measures].[Percentile75Value]} on COLUMNS,
EXISTS(NonEmpty(([DimLearningAim].[LearningAimReference].[LearningAimReference],[DimLearningAim].[LearningAimTitle].[LearningAimTitle]),([Top10LearningAims],[Measures].[SuccessRate]))*NonEmpty([DimMainProvider].[ProviderName].[ProviderName],
[Measures].[SuccessRate]),,"Learnings") DIMENSION PROPERTIES
MEMBER_CAPTION,MEMBER_UNIQUE_NAME ON ROWS from FECube WHERE
( StrToSet("[DimAcademicYear].[AcademicYear].[AcademicYear].[2009/10]",CONSTRAINED),
StrToSet("[DimLearnerAgeBand].[AgeBand].[All]",CONSTRAINED),
StrToSet("[DimLearningCourseLength].[CourseLength].[All]",CONSTRAINED),
StrToSet("[DimLearnerEthnicity].[Ethnicity].[All]",CONSTRAINED),
StrToSet("[DimLearnerGender].[Gender].[All]",CONSTRAINED),
StrToSet("[DimDeprivationDecile].[Decile].[All]",CONSTRAINED),
StrToSet("[DimSectorSubjectArea].[Estyn].&[2]",CONSTRAINED),
StrToSet("[DimLearningActivityLevel].[ActivityLevel].[All]",CONSTRAINED),
StrToSet("[DimLearningActivityType].[ActivityType].[All]",CONSTRAINED)
) CELL PROPERTIES VALUE ,BACK_COLOR ,FORE_COLOR ,FORMATTED_VALUE
,FORMAT_STRING ,FONT_NAME ,FONT_SIZE ,FONT_FLAGS