BI Answers COUNT the number in cloumn? - obiee

Here is the data look like.
Name P_ID NUM
A P1 3
A P2 1
B P3 1
B P4 1
C P5 2
D P7 1
In BI Answers I want the result show like this:
Name NUM_OF_1 NUM_OF_2 NUM_OF_3 SUM
A 1 0 1 2
B 2 0 0 2
C 0 1 0 1
D 1 0 0 1
The column NUM_OF_N is occurrences of a number in a 'name' group.

If you are looking for a SQL query then you can try the following pivot:
SELECT Name,
SUM(CASE WHEN NUM = 1 THEN 1 ELSE 0 END) AS NUM_OF_1,
SUM(CASE WHEN NUM = 2 THEN 1 ELSE 0 END) AS NUM_OF_2,
SUM(CASE WHEN NUM = 3 THEN 1 ELSE 0 END) AS NUM_OF_3,
COUNT(*) AS "SUM"
FROM yourTable
GROUP BY Name

Tim has got it nailed in terms of SQL. In terms of pure OBI dev you should put that logic into logical (measure) columns in your RPD though so the BI server treats them as such and you can use them automatically with all the usual functionalities like drill, aggregate etc

Related

Oracle: Join 2 tables without an explicit key

I have 2 table as follows:
Case_No.
Month
Month_Prev
Code
Stage
Code_Prev
Stage_Prev
Status
1
2022.09
2022.08
b
2
a
1
1
2
2022.09
2022.08
a
2
b
1
1
and
Month
Code
Stage
Rate
Status
2022.09
a
1
0.2
1
2022.09
a
2
0.1
1
2022.09
b
1
0.3
1
2022.09
b
2
0.1
1
2022.08
a
1
0.3
1
2022.08
a
2
0.2
1
2022.08
b
1
0.15
1
2022.08
b
2
0.25
1
My desired output:
Case_No.
Month
Month_Prev
Code
Stage
Code_Prev
Stage_Prev
Status
Rate
Rate_Prev
1
2022.09
2022.08
b
2
a
1
1
0.1
0.3
2
2022.09
2022.08
a
2
b
1
1
0.1
0.15
Basically, I want to obtain the rate corresponding to each individual set of {Month, Code, Stage, Status} and {Month_Prev, Code_Prev, Stage_Prev, Status} and I'm using Oracle. Anyone can help?
Well, you have already shown the keys for the join, so simply apply them. You'll have to join the second table twice, once for Month, once for Month_Prev.
select
t1.*
this.rate,
prev.rate as prev_rate
from t1
join t2 this on this.month = t1.month and this.code = t1.code and this.stage = t1.stage and this.status = t1.status
join t2 prev on prev.month = t1.month_prev and prev.code = t1.code and prev.stage = t1.stage and prev.status = t1.status
order by t1.month, t1.code, t1.stage, t1.status;
(In case there can be t1 rows without a match in t2 and you still want to show the row without a rate then, then change the inner joins to left outer joins.)

How to count or sum distinct values when there is a risk of intersection?

Imagine I have a table with people and their features:
group Name red_hair tall blue_eyes programmer
1 Mark 1 1 0 1
1 Sean 1 0 1 0
1 Lucas 1 1 1 1
2 Linda 0 1 1 1
I would like to count how many people of specific sets of features are in every group. In other words, I would like to make some bins without counting a person multiple times.
There are 2^4 (16) possible combinations of those sets, but I don't need so much.
For example, if a person has red_hair I don't care whether he or she has blue eyes or he or she a programmer. This person goes to the red hair bin of this group.
If a person is a programmer I don't care whether he or she is tall, but I don't want to count people who are already in a red hair bin. Because I have already counted them.
So I have a priority:
Red hair people counts first
Programmers second
People with blue eyes third
Expected result of this dataset:
group red_hair_persons programmers blue_eyes_persons
1 3 0 0
2 0 1 0
when I do this:
select group, count(case when red_hair = 1 then name end) as red_hair,
count(case when programmer = 1 and red_hair = 0 then name end) as programmers
from table
group by group
I fear that there would be some intersections. Or the logic with CASES would be so complex I could drown in it.
Am I right?
If so how could I avoid them? Maybe I am doing everything wrong and there is a better way to do what I want to. I have an enormous table with many features in it and I don't want to screw up.
Here's how I understood it:
SQL> with test (cgroup, name, red_hair, tall, blue_eyes, programmer) as
2 (select 1, 'mark' , 1, 1, 0, 1 from dual union all
3 select 1, 'sean' , 1, 0, 1, 0 from dual union all
4 select 1, 'lucas', 1, 1, 1, 1 from dual union all
5 select 2, 'linda', 0, 1, 1, 1 from dual
6 ),
7 priority as
8 (select t.*,
9 case when red_hair = 1 then 'A'
10 when programmer = 1 then 'B'
11 when blue_eyes = 1 then 'C'
12 else 'D'
13 end priority
14 from test t
15 )
16 select cgroup,
17 sum(case when priority = 'A' then 1 else 0 end) red_hair,
18 sum(case when priority = 'B' then 1 else 0 end) programmer,
19 sum(case when priority = 'C' then 1 else 0 end) blue_eyes,
20 sum(case when priority = 'D' then 1 else 0 end) other
21 from priority
22 group by cgroup;
CGROUP RED_HAIR PROGRAMMER BLUE_EYES OTHER
---------- ---------- ---------- ---------- ----------
1 3 0 0 0
2 0 1 0 0
SQL>
priority CTE puts every person into its priority group, based on their properties
the final select counts (using SUM + CASE) them per group
With a little bit of simple math involved in the conditional aggregation:
select "group",
sum("red_hair") red_hair_persons,
sum((1 - "red_hair") * "programmer") programmers,
sum((1 - "red_hair") * (1 - "programmer") * "blue_eyes") blue_eyes_persons
from tablename
group by "group"
See the demo.
Results:
> group | RED_HAIR_PERSONS | PROGRAMMERS | BLUE_EYES_PERSONS
> ----: | ---------------: | ----------: | ----------------:
> 1 | 3 | 0 | 0
> 2 | 0 | 1 | 0

count of flags in a column after pivoting the table

I have created a function that pivots my current table so that I can see which of my students enjoy what sports. I am using oracle db. So now, each sport is in its own respective column after the pivoting. It is flagged as a 1 if a student enjoys that specific sport.
Year Student Basketball Baseball Golf Soccer
2019 Michael 1 NA 1 NA
2018 Jason NA NA 1 NA
2017 Sarah 1 1 1 NA
2016 Michelle NA NA NA NA
I want to grab the count for the sports columns to see how many students flagged that respective sport.
select
SUM(CASE WHEN Basketball=1 THEN 1 ELSE 0 END) as NBA,
SUM(CASE WHEN Baseball=1 THEN 1 ELSE 0 END) as MLB,
SUM(CASE WHEN Golf=1 THEN 1 ELSE 0 END) as PGA,
SUM(CASE WHEN Soccer=1 THEN 1 ELSE 0 END) as MLS
from students_sports
group by year
order by 1;
I have tried the syntax above but no luck. I have also tried the syntax below.
select
sum(nvl("Basketball", 0)) as NBA,
sum(nvl("Baseball", 0)) as MLB,
etc....
When I run this query, I get the total count of rows and not the actual sum count of the rows flagged as 1. Any thoughts?
the first syntax is wrong. Your column Basketball, Baseball, Golf, Soccer is varchar as you are saving NA in the field not numeric. And while you are doing a comparison in a query CASE WHEN Basketball=1 you are doing a numeric comparison. So change your query as following and let us know if it works.
**Query**
`SELECT SUM (CASE WHEN Basketball = '1' THEN 1 ELSE 0 END) AS NBA
,SUM (CASE WHEN Baseball = '1' THEN 1 ELSE 0 END) AS MLB
,SUM (CASE WHEN Golf = '1' THEN 1 ELSE 0 END) AS PGA
,SUM (CASE WHEN Soccer = '1' THEN 1 ELSE 0 END) AS MLS
FROM students_sports
GROUP BY year
ORDER BY 1;`
Example:
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=9c6cc6b067cc128b699316cb299769e3
This should give you result as 1 or 0. Let us know how it goes. I am not sure about your SUM what are you doing with it but it does not make sense to me as that sum will worth nothing.

Select the sum of occurances of first alphabetical character

Hi what i need to do is create a select statement which outputs the sum of the first character in a field within the table so the output would look something like
A,12
B,0
C,20
D,14
E,0
ect...
The table is called contacts, in the above there was 12 occurrences of people whose names begin with the letter A
I hope i have explained this correctly
Let's understand this with EMP table example.
SQL> with
2 letters
3 as
4 (select chr( ascii('A')+level-1 ) letter
5 from dual
6 connect by level <= 26
7 )
8 SELECT substr(ename, 1, 1) AS init_name,
9 count(*) cnt
10 FROM emp
11 WHERE substr(ename, 1, 1) IN (SELECT letter from letters)
12 GROUP BY substr(ename, 1, 1)
13 UNION
14 SELECT l.letter AS init_name,
15 0 cnt
16 FROM letters l
17 WHERE l.letter NOT IN (SELECT substr(ename, 1, 1) FROM emp)
18 ORDER BY init_name
19 /
I CNT
- ----------
A 2
B 1
C 1
D 0
E 0
F 1
G 0
H 0
I 0
J 2
K 1
L 0
M 2
N 0
O 0
P 0
Q 0
R 0
S 2
T 1
U 0
V 0
W 1
X 0
Y 0
Z 0
26 rows selected.
SQL>
So, it gives the count of each letter of first name, and for the other letters which does not exist in the first name, the count is 0.
Generate the 26 letters using connect then left join to the first letter of the name and count them:
select letter, count(name) count
from (select chr(ascii('A')+level-1) letter from dual connect by level < 27) l
left join emp on substr(name, 1, 1) = letter
group by letter order by 1
See SQLFiddle
Attribution: My technique of generating letters uses elements of Lalit's answer.

Create a Matrix with conditions

I am struggling to create two matrix in SAS based on certain conditions.
trying to create a 12x12 matrix in the format below:
col1 col2 col3 col4 ............col12
1 0 0 0 ............ 0
1 1 0 0 ............ 0
1 1 1
0 1 1
0 0 1
1 0 0
1 1 0
1 1 1
0 1 1
0 0 1
0 0 0
0 0 0
and so on.
and this-
col1 col2 col3 col4 ............col12
1 0 0 0 ............ 0
1 2 0 0 ............ 0
1 2 3
0 2 3
0 0 3
1 0 0
1 2 0
1 2 3
0 2 3
0 0 3
0 0 0
0 0 0
and so on. Basically displays the col# instead of 1's.
I read a couple of articles online and tried Proc IML but i got an error that the procedure doesn't exist.
I tried the code below to start with but nothing. I am confused as to how should I enter the conditions.
data test_matrices ;
array col(12) col1-col12;
do i=1 to 12;
j=i-1;
col(i)=ifn(i le 5 , 1, 0,0);
output;
end;
run;
Please help.
Thanks.
Jay
What you need to start with:
Arrays have to have a name, and unless they're temporary arrays they also need variable names (they'll take the name concatenated with the array index if you don't provide it). So:
array (*) 1-12;
needs to be
array myVars(12) col1-col12;
You need two loops, one to define your 'rows' and one to work on your columns, nested. IE, for row 1, do something 12 times, for row 2, do something 12 times.
So this:
do i=1 to 12;
do j=1 to 12;
... do stuff ...
end;
output; *you had this right! It goes in the outer loop since it defines rows.;
end;
Now, you have something that lets you work on just one cell. So you're on cell (i,j); what rule defines what should go there? Figure out that logic, and then set myvars[j] to that value. You can't operate on the 'i' parameter, but instead that's going to just define how often you output.
Ie, this:
myvars[j] = i;
That's not correct, but figure out what is correct and assign that to myvars[j].

Resources