Expression for - Row by row variance on grouped datasets - sql

I am having troubles with creating an expression in SSRS.
I'd like to calculate the difference between two figures. The columns are in separate datasets and are grouped. They also show a total at the end of each group.
Eg
Dataset 1 Dataset 2
Month Workshops which Ran Month Workshops which Ran Variance
Apr 40 Apr 30 10
May 50 May 40 10
Jun 45 Jun 35 10
Q1 Total 135 Q1 Total 105 30
The quarters then carry on but, you get the picture.
Is there a way to make an expression to calculate the variance column even though the data is grouped and in different datasets?
Any help would really be appreciated :)
Will

If we assume:
There could be voids in either data set, we could use a full outer join and coalesce.
You want the absolute difference for variance (no negatives)
You want to display the month and workshops which ran in all cases.
Neither dataset would span more than 1 year's period. (if they did we would need the aggregate datasets to contain year along with month and include it on the join)
The Q1 total value (or others) exists in both data sets and is spelled the same.
.
SELECT DS1.Month as [DS1 Month]
, DS1.[Workshops which Ran] as [DS1 Workshops which Ran]
, DS2.Month as [DS2 Month]
, DS2.[Workshops which Ran] as [DS2 Workshops which Ran]
, abs(coalesce(DS1.[Workshops which Ran],0) - coalesce(DS2.[Workshops which Ran],0)) as [Variance]
FROM Dataset1 DS1
FULL OUTER JOIN Dataset2 DS2
on DS1.Month = DS2.Month

The best way is to create a dataset with all your data in one place. If you can't do this for whatever reason, and the data in the datasets is more details than the aggregated data you are showing in your example, then check this post.
http://salvoz.com/blog/2013/05/27/sum-result-of-ssrs-lookupset-function/

Related

Adding column based on dynamic criteria that changes for every row in snowflake

Trying to add a column that counts distinct customers in snowflake based on criteria that changes for every row i.e. needs to count customers between 52 weeks before current week_ending date to current week_ending date.
The query that goes like
select week_ending, sales, last_year_cust_count
from table where year = 2022
now i want the last_year_cust_count to have distinct customers between 52 weeks before week_ending till current week_ending and this needs to show following results as example
Week_ending
Sales
last_year_cust_count
02/01/22
$300
3479
09/01/22
$350
3400
16/01/22
$450
3500
... and so on
The optimal way to solve this over complex structure, is to use a bitmap, and then roll that up to the projections you over.
You should read Using Bitmaps to Compute Distinct Values for Hierarchical Aggregations
The simple, non-performant way is to self join and throw processing power at it.
select a.week_ending, a.sales, count(distinct b.customer) as last_year_cust_count
from table_a as a
join table_a as b
on <filter that I cannot bothered writing to select last 52 weeks base on years and weeks>
where year = 2022

Select same account numbers in a new table

Using Teradata SQL Assistant, I want to be able to pull a table a year ahead but only the ones that would match the results in the query from the year before. Here's what I am trying to do. I pulled a table that contains information where the results in a specific column equals 0 for no. I want to pull information from 1 year ahead where the results in that column equals 1 but only include the account numbers that came when I pulled the results for the year before. Like only pull the customer account numbers for the year ahead that are the same from the year before.
Explanation: I pull the one table that has 0 in the column. From that, I want to see which of those accounts became a 1 in the table from a year ahead. The table has millions of accounts and I just have my settings for 10,000 of them so I want to see of those 10,000 in the first year that did not have the product, how many of them became 1 in the second year.
Can I do this? If so, how? I have been googling and I do not think I am explaining what I am trying to do correctly in my google query so I am coming up short with results.
Thanks for clarifying. That makes it a little simpler. I would put the second year data in a subquery and filter the main table on the first year and quantity = 0. This will give you two columns one with the first year and one with the second year. If you're only looking for this information for a single product_id you will need to add this to both WHERE clauses.
SELECT TABLE_NAME.ACCOUNT_ID, TABLE_NAME.QUANTITY AS "2019" , YEAR_TWO.QUANTITY AS "2020"
FROM TABLE_NAME
LEFT JOIN
(
SELECT *
FROM TABLE
WHERE YEAR = 2020
) YEAR_TWO ON TABLE_NAME.ACCOUNT_ID = YEAR_TWO.ACCOUNT_ID
WHERE TABLE_NAME.YEAR = 2019
AND TABLE_NAME.QUANTITY = 0
If you want just the % of accounts that are no longer 0 in the second year you could try something like this (adding up all the 1s and dividing by total count)
SELECT TABLE_NAME.YEAR, SUM(YEAR_TWO.QUANTITY) / COUNT(YEAR_TWO.QUANTITY) AS PERCENTAGE_NOT_ZERO
FROM TABLE_NAME
LEFT JOIN
(
SELECT *
FROM TABLE
WHERE YEAR = 2020
) YEAR_TWO ON TABLE_NAME.ACCOUNT_ID = YEAR_TWO.ACCOUNT_ID
WHERE TABLE_NAME.YEAR = 2019
AND TABLE_NAME.QUANTITY = 0
GROUP BY TABLE_NAME.YEAR

How to calculated on created fields? Why the calculation is wrong?

I am working on the workforce analysis project. And I did some case when conditional calculations in Google Data Studio. However, when I successfully conducted the creation of the new field, I couldn't do the calculation again based on the fields I created.
Based on my raw data, I generated the start_headcount, new_hires, terminated, end_headcount by applying the Case When conditional calculations. However, I failed in the next step to calculate the Turnover rate and Retention rate.
The formula for Turnover rate is
terms/((start_headcount+end_headcount)/2)
for retention is
end_headcount/start_headcount
However, the result is wrong. Part of my table is as below:
Supervisor sheadcount newhire terms eheadcount turnover Retention
A 1 3 1 3 200% 0%
B 6 2 2 6 200% 500%
C 6 1 3 4 600% 300%
So the result is wrong. The turnover rate for A should be 1/((1+3)/2)=50%; For B should be 2/((6+6)/2)=33.33%.
I don't know why it is going wrong. Can anyone help?
For example, I wrote below for start_headcount for each employee
CASE
WHEN Last Hire Date<'2018-01-01' AND Termination Date>= '2018-01-01'
OR Last Hire Date<'2018-01-01' AND Termination Date IS NULL
THEN 1
ELSE 0
END
which means if an employee meets the above standard, will get 1. And then they all grouped under a supervisor. I think it might be the problem why the turnover rate in sum is wrong since it is not calculated on the grouped date but on each record and then summed up.
Most likely you are trying to do both steps within the same query and thus newly created fields like start_headcount, etc. not visible yet within the same select statement - instead you need to put first calculation as a subquery as in example below
#standardSQL
SELECT *, terms/((start_headcount+end_headcount)/2) AS turnover
FROM (
<query for your first step>
)

How to do bitwise operations in SSAS cube for aggregations using MDX

I want to model a fact table for our users to help us calculate DAU (Daily active Users), WAU (Weekly active users) and MAU (Monthly active users).
The definitions of these measures are as follows:
1. DAU are users who is active every day during last 28 days.
2. WAU are users who are active at least on one day in each 7 days period during last 28 days
3. MAU are users who are active at least 20 days during last 28 days
I have built a SSAS cube with my fact table and user dimension table as follows
Fact : { date, user_id, activity_name}
Dimension: { date, user_id, gender, age, country }
Now I want to build a cube over this data so that we can see all the measures in any given day for last 28 days.
I thought of initially storing 28 days of data for all users in the SQL server and then do count distinct on date to see which measures they fall into.. but this proved very expensive since the data per day is huge..almost 10 millions rows.
So my next thought was to model the fact table (before moving it to SQL) such that it has a new column called "active_status" which is a 32 bit binary type column.
Basically, I'll store a binary number (or decimal equivalent) like 11000001101111011111111111111 which has a bit set on the days the user is active and off on the days user is not active.
This way I can compress 28 days worth of data in a single day before loading into data mart
Now the problem is , I think MDX doesn't support bitwise operations on columns in the expressions for calculated members like regular SQL does. I was hoping to create calculated measures daily_active_users, weekly_active_users and monthly_active_users using MDX that looks at this active_status bit for the user and does bitwise operation to determine the status.
Any suggestions on how to solve this problem? if MDX doesn't allow bitwise, what else can I do SSAS to achieve this.
thanks for the help
Additonal notes:
#Frank
Interesting thought about using a view to do the conversion from bitset to a dimension category..but I'm afraid it won't work. Because I have few dimensions connected to this fact table that have many-many relationships..for ex: I have a dimension called DimLanguage and another dimension called DimCountry and they have many-many relationship. And what ultimately I would like to do in the cube is to calculate the DAU/WAU/MAU which are COUNT(DISTINCT UserId) based on the combination of dimensions. So for ex; If a user is not MAU for dimension country US because he is only active 15 days out of 28 ....but he will be considered
You do not want to show the bitmap data to the users of the cube, but just the categories DAU, WAU, MAU, you should do the conversion from bitmap to category on data loading time. Just create a dimension table containing e. g. the following data:
id category
-- --------
1 DAU
2 WAU
3 MAU
Then define a view on your fact table that evaluates the bitmap data, and for each user and each date just calculates the id value of the category the user is in. This is then conceptually a foreign key to the dimension table. Use this view instead of the fact table in your cube.
All the bitmap evaluations are thus done on the relational side, where you have the bit operators available.
EDIT
As your requirement is that you need to aggregate the bitmap data in Analysis Services using bitwise OR as the aggregation method, I see no simple way to do that.
What you could do, however, would be to have 28 single columns, say Day1 to Day28, which would be either 0 or 1. These could be of type byte to save some space. You would use Maximum as aggregation method, which is equivalent to binary OR on a single bit.
Then, it would not be really complex to calculate the final measure, as we know the values are either zero or one, and thus we can just sum across the days:
CASE
WHEN Measures.[Day1] + ... + Measures.[Day28] = 28 THEN 'DAU'
WHEN Measures.[Day1] + ... + Measures.[Day7] >= 1 AND
Measures.[Day8] + ... + Measures.[Day14] >= 1 AND
Measures.[Day15] + ... + Measures.[Day21] >= 1 AND
Measures.[Day22] + ... + Measures.[Day28] >= 1 THEN 'WAU'
WHEN Measures.[Day1] + ... + Measures.[Day28] >= 20 THEN 'MAU'
ELSE 'Other'
END
The order of the clauses in the CASE is relevant, as the first condition matching is taken, and your definitions of WAU and MAU have some intersection.
If you have finally tested everything, you would make the measures Day1 to Day28 invisible in order not to confuse the users of the cube.

SQL YTD for previous years and this year

Wondering if anyone can help with the code for this.
I want to query the data and get 2 entries, one for YTD previous year and one for this year YTD.
Only way I know how to do this is as 2 separate queries with where clauses.. I would prefer to not have to run the query twice.
One column called DatePeriod and populated with 2011 YTD and 2012YTD, would be even better if I could get it to do 2011YTD, 2012YTD, 2011Total, 2012Total... though guessing this is 4 queries.
Thanks
EDIT:
In response to help clear a few things up:
This is being coded in MS SQL.
The data looks like so: (very basic example)
Date | Call_Volume
1/1/2012 | 4
What I would like is to have the Call_Volume summed up, I have queries that group it by week, and others that do it by month. I could pull all the dailies in and do this in Excel but the table has millions of rows so always best to reduce the size of my output.
I currently group by Week/Month and Year and union all so its 1 output. But that means I have 3 queries accessing the same table, large pain, very slow not efficient and that is fine but now I also need a YTD so its either 1 more query or if I could find a way to add it to the yearly query that would ideal:
So
DatePeriod | Sum_Calls
2011 Total | 40
2011 YTD | 12
2012 Total | 45
2012 YTD | 15
Hope this makes any sense.
SQL is built to do operations on rows, not columns (you select columns, of course, but aggregate operations are all on rows).
The most standard approach to this is something like:
SELECT SUM(your_table.sales), YEAR(your_table.sale_date)
FROM your_table
GROUP BY YEAR(your_table.sale_date)
Now you'll get one row for each year on record, with no limit to how many years you can process. If you're already grouping by another field, that's fine; you'll then get one row for each year in each of those groups.
Your program can then iterate over the rows and organize/render them however you like.
If you absolutely, positively must have columns instead, you'll be stuck with something like this:
SELECT SUM(IF(YEAR(date) = 2011, sales, 0)) AS total_2011,
SUM(IF(YEAR(date) = 2012, total_2012, 0)) AS total_2012
FROM your_table
If you're building the query programmatically you can add as many of those column criteria as you need, but I wouldn't count on this running very efficiently.
(These examples are written with some MySQL-specific functions. Corresponding functions exist for other engines but the syntax would be a little different.)