Expression to find value for previous year SSRS - sql-server

I need some help with expressions.I need a report that shows calcul of a field for current year as well as previous year respecting this rule expression(Last-Last Previous)/Last Previous*100. Also the report runs on a Year Parameter.
Below is an example for the result
for example i selected the years 2010 2011 2012
year
Data 2010 2011 2012
hp 14 25 30
Dell 17 18 20
and the result i want
year
Data 2010 2011 2012 2011/2012
hp 14 25 30 0.002 (Last -Last Previous)/(last Previous*100) =(30-25)/(25*100)
Dell 17 18 20 0.0040
How can i do this
SELECT
NON EMPTY
{[Measures].[Val]} ON COLUMNS
,NON EMPTY
{
[DimCAT].[lbl].[lbl].ALLMEMBERS * [DimDate].[Year].[Year].ALLMEMBERS
} ON ROWS
FROM [Data];

Via mdx you need to use a WITH clause.
The calculated member that is added is called 2011/12 but is actually the last member of the year hierarchy compared to the previous year - so maybe not exactly what you require:
WITH
MEMBER [DimDate].[Year].[2011/12] AS
(
Tail([DimDate].[Year].[Year].ALLMEMBERS).Item(0).Item(0)
-
Tail([DimDate].[Year].[Year].ALLMEMBERS).Item(0).Item(0).PrevMember
)
/
Tail([DimDate].[Year].[Year].ALLMEMBERS).Item(0).Item(0).PrevMember
* 100
SELECT
NON EMPTY
{
[DimDate].[Year].[Year].ALLMEMBERS
,[DimDate].[Year].[2011/12]
} ON COLUMNS
,NON EMPTY
{[DimCAT].[lbl].[lbl].ALLMEMBERS} ON ROWS
FROM [Data]
WHERE
[Measures].[Val];
Using the strToSet function you could get a single member set using the parameter:
WITH
SET [s] AS
StrToSet('{[DimDate].[Year].[Year].[' + #Yr + ']}')
MEMBER [DimDate].[Year].[LastVsPrev] AS
([s].Item(0).Item(0) - [s].Item(0).Item(0).PrevMember)
/
[s].Item(0).Item(0).PrevMember
* 100
SELECT
NON EMPTY
Union
(
{
[s].Item(0).Item(0).PrevMember.PrevMember : [s].Item(0).Item(0)
}
,{[DimDate].[Year].[LastVsPrev]}
) ON COLUMNS
,NON EMPTY
{[DimCAT].[lbl].[lbl].ALLMEMBERS} ON ROWS
FROM [Data]
WHERE
[Measures].[Val];

If you have the chance to change the source dataset i would bring the dataset with the year UNPIVOTed and with a Row_Number on Data with year descending order. That way you can filter the last two years you want.
(this was tested in SSRS 2008 there might be easier ways especially in later versions)
select
Data,[year],measure,ROW_NUMBER() over (partition by data order by [year] desc) i
from (values
('hp',2010,14),
('hp',2011,25),
('hp',2012,30),
('Dell',2010,17),
('Dell',2011,18),
('Dell',2012,20)) t (data,year,measure)
Data year measure i
hp 2010 14 3
hp 2011 25 2
hp 2012 30 1
Dell 2010 17 3
Dell 2011 18 2
Dell 2012 20 1
And do a Column Group on year and a row group on data.
Expression SUM(Field!Measure.Value) on the intersecting cell of the 2 groups.
Add Column after column group and add the Expression to the Header cell
=MAX(iif(Fields!i.Value = 2,Fields!year.Value.ToString(),""))+"/"+ MAX(iif(Fields!i.Value = 1,Fields!year.Value.ToString(),""))
and the next expression to the Cell
=iif(SUM(iif(Fields!i.Value = 2,Fields!measure.Value,0))=0,0,SUM(iif(Fields!i.Value = 1,Fields!measure.Value,0))-SUM(iif(Fields!i.Value = 2,Fields!measure.Value,0)) / (SUM(iif(Fields!i.Value = 2,Fields!measure.Value,0))*100))
I think the formula is OK, but it's returning different values than what you posted as expected.

Related

How to find integer values within a String in SQL Server

I am trying to calculate tenure in years based on data in this format 2 year(s), 11 month(s), 5 day(s). Below is the logic in oracle. I am trying to implement similar solution in SQL Server. Can you please help?
In this example 2 year(s), 11 month(s), 5 day(s) is converted to 2.93 years.
round(
(regexp_substr(tenure_in_current_job,'[^ ]+')
+ REGEXP_REPLACE(tenure_in_current_job,'(.*r\(s\), )(\d+)(.*)','\2')/12
+ REGEXP_REPLACE(tenure_in_current_job,'(.*h\(s\), )(\d+)(.*)','\2')/365),
2 )
select sum(num.val * 1.0 / case when trm.val like '%year%' then 1 when trm.val like '%month%' then 12 else 365 end)
from string_split('2 year(s), 11 month(s), 5 day(s)',',')
cross apply (select ltrim("value")) trm(val)
cross apply (select cast(left(trm.val,charindex(' ',trm.val)-1) as int)) num(val)
--------------
2.930365296802
Split the string on commas
Remove leading spaces on each of the 3 resulting rows
Remove everything from the first space onward, and cast as int
Divide the resulting int by 1, 12, or 365 as appropriate
Caveat: string_split was introduced in SQL Server 2016. If you're on SQL 2012 or older, this solution won't work.

Sum amount base from previous value on slicer power bi

I have a table like this:
Year Month Code Amount
---------------------------------------
2017 11 a 7368
2017 11 b 3542
2017 12 a 4552
2017 12 b 7541
2018 1 a 6352
2018 1 b 8376
2018 2 a 1287
2018 2 b 3625
I make slicer base on Year and Month (ignore the Code), and I want to show SUM of Amount like this :
If I select on slicer Year 2017 and Month 12, the value to be shown is SUM Amount base on 2017-11, and select on slicer Year 2018 and Month 1 should be SUM Amount base on 2017-12
I have tried this one for testing with, but this not allowed:
Last Month = CALCULATE(SUM(Table[Amount]); Table[Month] = SELECTEDVALUE(Table[Month]) - 1)
How to do it right?
I want something like this
NB: I use direct query to SQL Server
Update: At this far, I added Last_Amount column in SQL Server Table by sub-query, maybe you guys have a better way for my issue
The filters in a CALCULATE statement are only designed to take simple statements that don't have further calculations involved. There are a couple of possible remedies.
1. Use a variable to compute the previous month number before you use it in the CALCULATE function.
Last Month =
VAR PrevMonth = SELECTEDVALUE(Table[Month]) - 1
RETURN CALCULATE(SUM(Table[Amount]), Table[Month] = PrevMonth)
2. Use a FILTER() function. This is an iterator that allows more complex filtering.
Last Month = CALCULATE(SUM(Table[Amount]),
FILTER(ALL(Table),
Table[Month] = SELECTEDVALUE(Table[Month]) - 1))
Edit: Since you are using year and month, you need to have a special case for January.
Last Month =
VAR MonthFilter = MOD(SELECTEDVALUE(Table[Month]) - 2, 12) + 1
VAR YearFilter = IF(PrevMonth = 12,
SELECTEDVALUE(Table[Year]) - 1,
SELECTEDVALUE(Table[Year]))
RETURN CALCULATE(SUM(Table[Amount]),
Table[Month] = MonthFilter,
Table[Year] = YearFilter)

Finding the frequency of repetation of Material pairs in Sales order and order them by Frequency in SQL Server

my data looks like shown below.I want to create material pairs Sales Order Wise which is being ordered frequently in SQL Server I used the below code but I see duplicates in the output.
SALES_ORDER- ITEM_NO- MATERIAL_NUMBER<br>
160608048 10 EU-SAC-00820<br>
160608047 10 EU-174000-000200<br>
160608047 20 EU-174000-000180<br>
160608047 30 EU-174000-000220<br>
160608042 10 EU-A-6000-08LF<br>
160608040 10 EU-A-6000-08LF<br>
160608038 10 EU-4843<br>
160608038 20 EU-4844<br>
160608038 30 EU-4842<br>
SELECT A1.[Document],A1.[FINAL Material],A2.[Document],A2.[FINAL Material] FROM [dbo].[Sheet1$] A1,[dbo].[Sheet1$] A2 WHERE A1.[Document]= A2.[Document] AND A1.[FINAL Material] != A2.[FINAL Material]

In SSRS, how can I add a row to aggregate all the rows that don't match a filter?

I'm working on a report that shows transactions grouped by type.
Type Total income
------- --------------
A 575
B 244
C 128
D 45
E 5
F 3
Total 1000
I only want to provide details for transaction types that represent more than 10% of the total income (i.e. A-C). I'm able to do this by applying a filter to the group:
Type Total income
------- --------------
A 575
B 244
C 128
Total 1000
What I want to display is a single row just above the total row that has a total for all the types that have been filtered out (i.e. the sum of D-F):
Type Total income
------- --------------
A 575
B 244
C 128
Other 53
Total 1000
Is this even possible? I've tried using running totals and conditionally hidden rows within the group. I've tried Iif inside Sum. Nothing quite seems to do what I need and I'm butting up against scope issues (e.g. "the value expression has a nested aggregate that specifies a dataset scope").
If anyone can give me any pointers, I'd be really grateful.
EDIT: Should have specified, but at present the dataset actually returns individual transactions:
ID Type Amount
---- ------ --------
1 A 4
2 A 2
3 B 6
4 A 5
5 B 5
The grouping is done using a row group in the tablix.
One solution is to solve that in the SQL source of your dataset instead of inside SSRS:
SELECT
CASE
WHEN CAST([Total income] AS FLOAT) / SUM([Total income]) OVER (PARTITION BY 1) >= 0.10 THEN [Type]
ELSE 'Other'
END AS [Type]
, [Total income]
FROM Source_Table
See also SQL Fiddle
Try to solve this in SQL, see SQL Fiddle.
SELECT I.*
,(
CASE
WHEN I.TotalIncome >= (SELECT Sum(I2.TotalIncome) / 10 FROM Income I2) THEN 10
ELSE 1
END
) AS TotalIncomePercent
FROM Income I
After this, create two sum groups.
SUM(TotalIncome * TotalIncomePercent) / 10
SUM(TotalIncome * TotalIncomePercent)
Second approach may be to use calculated column in SSRS. Try to create a calculated column with above case expression. If it allows you to create it, you may use it in the same way as SQL approach.
1) To show income greater than 10% use row visibility condition like
=iif(reportitems!total_income.value/10<= I.totalincome,true,false)
here reportitems!total_income.value is total of all income textbox value which will be total value of detail group.
and I.totalincome is current field value.
2)add one more row to outside of detail group to achieve other income and use expression as
= reportitems!total_income.value-sum(iif(reportitems!total_income.value/10<= I.totalincome,I.totalincome,nothing))

Utilizing SQL datepart to indentify consecutive periods of time

I have a stored procedure that works correctly, but don't understand the theory behind why it works. I'm indentifying a consecutive period of time by utilizing a datepart and dense rank (found solution through help elsewhere).
select
c.bom
,h.x
,h.z
,datepart(year, c.bom) * 12 + datepart(month, c.bom) -- this is returning a integer value for the year and month, allowing us to increment the number by one for each month
- dense_rank() over ( partition by h.x order by datepart(year, c.bom) * 12 + datepart(month, c.bom)) as grp -- this row does a dense rank and subtracts out the integer date and rank so that consecutive months (ie consecutive integers) are grouped as the same integer
from
#c c
inner join test.vw_info_h h
on h.effective_date <= c.bom
and (h.expiration_date is null or h.expiration_date > c.bom)
I understand in theory what is happening with the grouping functionality.
How does multiplying year * 12 + month work? Why do we multiply the year? What is happening in the backend?
The year component of a date is an integer value. Since there are 12 months in a year, multiplying the year value by 12 provides the total number of months that have passed to get to the first of that year.
Here's an example. Take the date February 11, 2012 (20120211 in CCYYMMDD format)
2012 * 12 = 24144 months from the start of time itself.
24144 + 2 months (february) = 24146.
Multiplying the year value by the number of months in a year allows you to establish month-related offsets without having to do any coding to handle the edge cases between the end of one year and the start of another. For example:
11/2011 -> 24143
12/2011 -> 24144
01/2012 -> 24145
02/2012 -> 24146

Resources