Create calculated field with condition from another column - tableau-desktop

I have data that shows student name and the years they attended the school along with the grades they achieved each year.
I need to visualize this in a horizontal bar graph with names on the y-axis and grades on the x-axis
My dataset looks somewhat like this:
name
Year
Grade
John
2016
79
2017
65
Smith
2018
87
2019
56
Mary
2017
92
Jack
2016
95
2017
75
I want a dropdown/parameter based on the year that changes my data in a way that shows, The names and grades of the selected year only.
So if I were to select 2017, I want the data to look like this:
Name
Grade
John
65
Mary
92
Jack
75
I've tried something like this with no luck in the 'create calculated field' dialog box:
If [Parameters].[By Year] == "2017"
THEN
[Name] = WHEN [year] = "2017"
END

your calculated field (for filter) should be like this:
IF [Year] = [Parameters].[By Year]
THEN [Grade]
ELSE NULL
END

Related

How to multiply and merge two tables in SAS using a bridge table?

I am trying to merge two SAS tables based on a third “bridge table” and perform some calculations during the process. The code should be like “For each good lookup the price and calculate the annual revenue.”
My raw data: one table with annual quantity of goods, one table with prices and one bridge table with the information which price is used for which good.
data work.goods;
input date date. GoodA GoodB GoodC;
format date year. ;
datalines;
01Jan20 10 12 2
01Jan21 12 11 5
run;`
data work.price;
input date date. PriceA PriceB;
format date year.;
datalines;
01Jan20 220 110
01Jan21 250 120
run;
data work.bridgetable;
input goods $5. price $7.;
datalines;
GoodA PriceA
GoodB PriceB
GoodC PriceB
run;
So far, I used a proc sql statement without the information in the bridge table.
proc sql;
create table work.result as
select goods.date,
goods.GoodA * price.PriceA as RevenueA,
goods.GoodB * price.PriceB as RevenueB,
goods.GoodC * price.PriceB as RevenueC
from work.goods as goods, work.price as price
where goods.date = price.date;
quit;
Now, I would like to use the information from the bridge table, so that I can change the assignment of a price to a good (e.g. instead of PriceB PriceA is used for GoodC). In addition, I’d like to have the code more dynamic without the hardcoding so that I can add new goods and prices in my tables without re-coding the ‘select’ part of my sql statement.
How do I implement the bridge table in proc sql?
Thanks a lot for your help!
Your first two tables need to be vertical and not horizontal. Then the structure will not change when new goods or new price categories are added.
You can use PROC TRANSPOSE to convert your current tables.
data goods;
input year GoodA GoodB GoodC;
datalines;
2020 10 12 2
2021 12 11 5
;`
data price;
input year PriceA PriceB;
datalines;
2020 220 110
2021 250 120
;
data bridgetable;
input goods $5. price $7.;
datalines;
GoodA PriceA
GoodB PriceB
GoodC PriceB
;
proc transpose data=goods
name=goods
out=goods_tall(rename=(col1=amount))
;
by year;
var good: ;
run;
proc transpose data=price
name=price
out=price_tall(rename=(col1=unit_price))
;
by year;
var price: ;
run;
Now the tables are easy to join.
proc sql ;
create table want as
select *,unit_price*amount as revenue
from goods_tall
natural join price_tall
natural join bridgetable
;
quit;
Results
unit_
Obs goods price year amount price revenue
1 GoodA PriceA 2020 10 220 2200
2 GoodB PriceB 2020 12 110 1320
3 GoodC PriceB 2020 2 110 220
4 GoodA PriceA 2021 12 250 3000
5 GoodB PriceB 2021 11 120 1320
6 GoodC PriceB 2021 5 120 600

List unique dates and add line at the beginning of a new month

I have long (multiple thousand lines and growing) list of data in Sheets which have a date and additional columns with data. Here's a simplified example of this list (=TAB1):
Date Number Product-ID
02.09.2021 123 1
02.09.2021 2 1
01.09.2021 15 1
01.09.2021 675 2
01.09.2021 45 2
01.09.2021 52 1
31.08.2021 2 1
31.08.2021 78 1
31.08.2021 44 1
31.08.2021 964 2
30.08.2021 1 2
29.08.2021 ...
...
Three remarks:
The date is formatted to European standard DD.MM.YYYY
There definitely is more than one line per day per product (could be a big number depending on the day)
(for the formulas below) In the European standard Sheets uses ; instead of , as in =IF(A;B;C)
In a different tab (=TAB2), I want to add up all the numbers for a unique date for Product-ID 1. So far I've done it like this:
Date Sum (if Product-ID=1)
=UNIQUE('TAB1'!A2:A) =ARRAYFORMULA(SUMIF('TAB1'!A:A&'TAB1'!C:C;A2:A&"1";'TAB1'!B:B))
02.09.2021 125
01.09.2021 67
31.08.2021 124
30.08.2021 1
29.08.2021 ...
...
This works fine so far. Here's what I want to do now:
For every month (here: August and September 2021) I need an additional line above the current date (in this case: above 02.09.2021) AND above a completed month to sum over the whole month for column B. Here's how it should look like:
Date Sum (if Product-ID=1)
September 2021 192
02.09.2021 125
01.09.2021 67
August 2021 125
31.08.2021 124
30.08.2021 1
29.08.2021 ...
Of course, the line for the next day (03.09.2021) should be added above 02.09.2021 and below the sum for the month when it's automatically added to TAB1 on the next day.
I tried to play around with s.th. like =IF(DAY(UNIQUE('TAB1'!A2:A))=1;...;...) but didn't get far.
Is there anyone with an idea how to realize s.th. like this?
You want to learn about QUERY().
in cell A1 of an empty tab.
=QUERY('TAB1'!A2:C,"select A,SUM(B) where C = 1 group by A")
it makes a very big difference whether your product ids are text or numbers. the above was written as if they are numbers, but you might have just been simplifying. If they are text you would write it like this:
=QUERY('TAB1'!A2:C,"select A,SUM(B) where C = '1XYZ' group by A")
note the single quotes.
if the IDs are a MIX of text and letters then you need to force them all to text values in the original data by highlighting the IDs column and choosing Format>Number>Plain Text from the menu bar.
UPDATE:
I understand the requirements better now for intermixing a cumulative month total into the output. This may work.
=ARRAYFORMULA({QUERY({EOMONTH('TAB1'!A2:A,0),'TAB1'!B2:C},"select 'Total',Col1,SUM(Col2) where Col3 = 1 group by 'Total',Col1 label 'Total''',SUM(Col2)''",0);QUERY('TAB1'!A2:C,"select '',A,SUM(B) where C = 1 group by '',A label '''',SUM(B)''",0)},"order by Col2,Col1",0))

Line graphs in Tableau

I have a line graph in Tableau over the past 6 months and it is filtered by person. Some people have no data for certain months. When they do not have data, the graph appears blank for that month. I would like for the graph to show 0 instead of a blank. For example, if person A had no sales in February, I would like for the graph to show 0 for February rather than a blank for February. I cannot use the Zn function because there are no null values.
Any ideas?
Thanks!
Edit: Here is an example using false data
The second graph is the same as the first graph except it is filtered by person. Even though Sally has no data in Feb, March, or June, this actually means that the value should be 0. I would like for the line graph to drop to 0 for these months. Further, then the average should be around 58 rather than 116.
Assuming you have a data like the following:
Date Person Sales
15/01/2021 Peter 10
15/02/2021 Peter 20
15/03/2021 Peter 10
15/04/2021 Peter 30
15/05/2021 Peter 40
15/06/2021 Peter 20
15/01/2021 Sally 20
15/03/2021 Sally 10
15/05/2021 Sally 50
Drag date into your colum shelf and make it Month-discrete
Drag Sales into the worksheet
Switch to line chart
Right click Sales --> Format --> Pane --> Marks --> Show at default value
Right click Month (Date) --> Show missing values
Add Person as a Filter --> show Filter
Then you should be able to get something like this having Sally (just 3 out of 5 total months) showing her non existing 2 values as zero.

Split revenue by year with Google Sheets' QUERY function

I get monthly revenue data from the finance department that I have clean to input into a reporting format. Its monthly data that lists all revenue in a single column. I need to split out the revenue by years (2018, 2019, etc.).
I believe that I need to use a query function for this but if you have some other solution, then I'm open to that too.
The data looks like this:
Client Source Month Year Revenue
abc Google 1 2019 100
abc Google 1 2018 100
abc Facebook 1 2018 50
abc Facebook 2 2018 50
And I need it to look like this:
Client Source Month 2018 Revenue 2019 Revenue
abc Google 1 100 100
abc Facebook 1 50 0
abc Facebook 2 50 0
I'm familiar with query functions but I can't wrap my head around how to do this.
The pseudo code for this would be something like:
select Client,
Source,
Month,
Case when Year in 2019 then sum(Revenue) as 2019 Revenue else 0 end,
Case when Year in 2018 then sum(Revenue) as 2018 Revenue else 0 end
from Data
Group by Client, Source, Month
Please let me know if I need to provide any additional information. And I appreciate your help with this problem.
=QUERY(A1:E, "select A,B,C,sum(E) where A is not null group by A,B,C pivot D", 1)

Ruby on rails active record multiple group record to calculate numbers

I want to calculate number of employee who has commanded to shoot on every day.
Shoot.where("command_type = ?", "shoot").group("DATE(created_at)").group("employee_number").order("DATE(created_at)").count
It will give me a output like
{[Wed, 03 Aug 2011, "7838744451"]=>2, [Wed, 03 Aug 2011, "8055898284"]=>11,[Fri, 05 Aug 2011, "9702553828"]=>1, [Fri, 05 Aug 2011, "9717466677"]=>1,[Fri, 05 Aug 2011, "8055898284"]=>1,[Wed, 06 Aug 2011, "8055898284"]=>5
I want to have an array something like:-
[2,0,3,1] // zero is for the dates when no record is there for that date. and number in the array is that number of the employees that has been ordered to shoot.
For example from array: 2 employee were ordered to shoot on Wed, 3rd.
0 employee were ordered to shoot on 4th and so on...
Also: How can i calculate that a how many times all employees were commanded to shoot in a week/month. Basically 100 employee were ordered to shoot 1st week. 120 employees were order to shoot 2nd week and so on 1st month and 2nd month..
The command you are using returns the daily count by employee. If you want to get the daily count across employees, remove the 2nd group call.
# return [2,3,1]
Shoot.where(:command_type => shoot").group("DATE(created_at)").values
If you want to fill the missing date values, you can use this function:
class Shoot
def self.daily_count_by_type(type = "shoot", range=7.days)
counts = Shoot.where(:command_type => type).group("DATE(created_at)").
count("DISTINCT employee_id")
(range.ago.to_date..Date.today).map {|d| counts[d.to_s] || 0}
end
end
Now
Shoot.daily_count_by_type # for type `shoot`, last 7 days
Shoot.daily_count_by_type("shoot") # for type `shoot`, last 7 days
Shoot.daily_count_by_type("eat", 14.days) # for type `eat`, last 14 days
Shoot.daily_count_by_type("leave") # for type `leave`, last 14 days
Make sure you add an index on DATE(CREATED_AT) to improve the performance.
Edit 1
Based on the comment you need to COUNT the distinct values. I have updated the answer accordingly.

Resources