I have three worksheets: players, teams, and weights (how highly a particular attribute is weighted when determining player-team match).
Players
Name
Age
Height
Free_Throw_Perc
...
Bod
23
74
62
...
Teams
| Team_Name | Age | Height | Free_Throw_Perc | ... |
|-----------|-----|--------|-----------------|-----|
|Team1|23|78|62|...|
Weights
| Team_Name | Age | Height | Free_Throw_Perc | ... |
|:---------:|:---:|:------:|:---------------:|:---:|
| Team1 | 5 | 10 | 10 | ... |
CREATE TABLE players (name, age, height, free_throw_perc) AS
SELECT 'Alice', 20, 160, 90 FROM DUAL UNION ALL
SELECT 'Betty', 21, 165, 80 FROM DUAL UNION ALL
SELECT 'Carol', 22, 170, 70 FROM DUAL UNION ALL
SELECT 'Debra', 23, 175, 60 FROM DUAL UNION ALL
SELECT 'Emily', 24, 180, 50 FROM DUAL UNION ALL
SELECT 'Fiona', 25, 185, 40 FROM DUAL UNION ALL
SELECT 'Gerri', 26, 190, 30 FROM DUAL UNION ALL
SELECT 'Heidi', 27, 195, 20 FROM DUAL UNION ALL
SELECT 'Irene', 28, 200, 10 FROM DUAL;
CREATE TABLE teams (team_name, age, height, free_throw_perc) AS
SELECT 'ALPHA', 20,175,90 FROM DUAL;
CREATE TABLE weights team_name, age, height, free_throw_perc) AS
SELECT 'ALPHA', 5,10,10 FROM DUAL;
The teams table corresponds to the players table but contains a record for each team detailing their ideal player based on the current composition of the team. The weights table contains a record for each team with an integer value weight stating how much they care about each player attribute. I am trying to compute a total match score for each player-team combination. I was able to do this quite easily with python but am struggling to accomplish the same in SQL.
In Python this would be a simple for loop with logical operators comparing each cell of one dataframe to each cell of another, but the lack of positional referencing in SQL makes this a lot trickier to do and generalize (be able to use the same queries for other pairs of tables with different attributes).
So far I have
BEGIN
FOR c in (SELECT column_name FROM all_tab_columns WHERE table_name = 'teams')
LOOP
INSERT INTO match_table (players.Name, candidates.c)
SELECT players.Name, players.c WHERE players.c = teams.c
END LOOP;
BEGIN
FOR c IN (SELECT column_name FROM all_tab_columns WHERE table_name = 'weights')
LOOP
UPDATE match_table
SET match_table.c = (SELECT weights.c FROM weights WHERE match_table.c = weights.c)
END LOOP;
From what I can tell that will generate a table of player names with a single column corresponding to a match to a team attribute populated by the corresponding weight and all other columns full of null values. If that is the case, I can group by name to create a singular record with all matches and corresponding weights.
The script should loop through each player and team and compare the attributes of the player with those desired by the team. Where there is a match a new row should be added to the match_table with the player name and nulls values except for the column that matched. That should be done for each player-team attribute match. Then those matches should be replaced by the corresponding weight from the weight table. I would then like to sum those to get a total match score. I can't use the '+' operator because the column nammes will vary. They will always match between the three tables, but there will be varied attributes of interest.
The expected output would look something like:
players.name
Age
Height
Free_Throw_Perc
...
'Alice'
5
NULL
NULL
...
'Alice'
NULL
10
NULL
...
How would I then sum across each record to find the total match score of each candidate for a team?
If you have the sample data:
CREATE TABLE teams ( id, name ) AS
SELECT 1, 'Alpha' FROM DUAL UNION ALL
SELECT 2, 'Beta' FROM DUAL UNION ALL
SELECT 3, 'Gamma' FROM DUAL;
CREATE TABLE players (name, team, age, height, free_throw_perc) AS
SELECT 'Alice', 1, 20, 160, 90 FROM DUAL UNION ALL
SELECT 'Betty', 1, 21, 165, 80 FROM DUAL UNION ALL
SELECT 'Carol', 1, 22, 170, 70 FROM DUAL UNION ALL
SELECT 'Debra', 2, 23, 175, 60 FROM DUAL UNION ALL
SELECT 'Emily', 2, 24, 180, 50 FROM DUAL UNION ALL
SELECT 'Fiona', 2, 25, 185, 40 FROM DUAL UNION ALL
SELECT 'Gerri', 3, 26, 190, 30 FROM DUAL UNION ALL
SELECT 'Heidi', 3, 27, 195, 20 FROM DUAL UNION ALL
SELECT 'Irene', 3, 28, 200, 10 FROM DUAL;
CREATE TABLE weights(team, key, weight) AS
SELECT 1, 'AGE', 1.0 FROM DUAL UNION ALL
SELECT 1, 'HEIGHT', 0.5 FROM DUAL UNION ALL
SELECT 1, 'FREE_THROW_PERC', 0.2 FROM DUAL UNION ALL
SELECT 2, 'AGE', 0.0 FROM DUAL UNION ALL
SELECT 2, 'HEIGHT', 1.0 FROM DUAL UNION ALL
SELECT 2, 'FREE_THROW_PERC', 0.8 FROM DUAL UNION ALL
SELECT 3, 'AGE', 0.5 FROM DUAL UNION ALL
SELECT 3, 'HEIGHT', 0.5 FROM DUAL UNION ALL
SELECT 3, 'FREE_THROW_PERC', 1.0 FROM DUAL;
And you want to insert the sum of the weight column from the weights table multiplied by the respective value in the players table into the following table:
CREATE TABLE match_table(
team INT,
value NUMBER
);
Then you can use the following INSERT query:
INSERT INTO match_table (team, value)
SELECT p.team,
SUM(p.value * w.weight)
FROM ( SELECT name, team, key, value
FROM players
UNPIVOT ( value FOR key IN (age, height, free_throw_perc) )
) p
INNER JOIN weights w
ON ( p.team = w.team AND p.key = w.key )
GROUP BY p.team
Then the table will contain the weighted totals:
TEAM
VALUE
2
660
3
393
1
358.5
fiddle
And if your match_table is:
CREATE TABLE match_table(
player VARCHAR2(20),
team INT,
age NUMBER,
height NUMBER,
free_throw_perc NUMBER,
total NUMBER
);
Then you can use the query (and calculate the total with the + operator):
INSERT INTO match_table (player, team, age, height, free_throw_perc, total)
SELECT p.name,
p.team,
p.age * w.age_weight,
p.height * w.height_weight,
p.free_throw_perc * w.free_throw_perc_weight,
p.age * w.age_weight
+ p.height * w.height_weight
+ p.free_throw_perc * w.free_throw_perc_weight
FROM players p
INNER JOIN (
SELECT *
FROM weights
PIVOT (
MAX(weight)
FOR key IN (
'AGE' AS age_weight,
'HEIGHT' AS height_weight,
'FREE_THROW_PERC' AS free_throw_perc_weight
)
)
) w
ON (p.team = w.team)
Which gives the values:
PLAYER
TEAM
AGE
HEIGHT
FREE_THROW_PERC
TOTAL
Alice
1
20
80
18
118
Betty
1
21
82.5
16
119.5
Carol
1
22
85
14
121
Debra
2
0
175
48
223
Emily
2
0
180
40
220
Fiona
2
0
185
32
217
Gerri
3
13
95
30
138
Heidi
3
13.5
97.5
20
131
Irene
3
14
100
10
124
fiddle
Or, if the players are uncorrelated to a team then:
INSERT INTO match_table (player, team, age, height, free_throw_perc, total)
SELECT p.name,
w.team,
p.age * w.age_weight,
p.height * w.height_weight,
p.free_throw_perc * w.free_throw_perc_weight,
p.age * w.age_weight
+ p.height * w.height_weight
+ p.free_throw_perc * w.free_throw_perc_weight
FROM players p
CROSS JOIN (
SELECT *
FROM weights
PIVOT (
MAX(weight)
FOR key IN (
'AGE' AS age_weight,
'HEIGHT' AS height_weight,
'FREE_THROW_PERC' AS free_throw_perc_weight
)
)
) w
Which, for the sample data, outputs:
PLAYER
TEAM
AGE
HEIGHT
FREE_THROW_PERC
TOTAL
Alice
1
20
80
18
118
Alice
2
0
160
72
232
Alice
3
10
80
90
180
Betty
1
21
82.5
16
119.5
Betty
2
0
165
64
229
Betty
3
10.5
82.5
80
173
Carol
1
22
85
14
121
Carol
2
0
170
56
226
Carol
3
11
85
70
166
Debra
1
23
87.5
12
122.5
Debra
2
0
175
48
223
Debra
3
11.5
87.5
60
159
Emily
1
24
90
10
124
Emily
2
0
180
40
220
Emily
3
12
90
50
152
Fiona
1
25
92.5
8
125.5
Fiona
2
0
185
32
217
Fiona
3
12.5
92.5
40
145
Gerri
1
26
95
6
127
Gerri
2
0
190
24
214
Gerri
3
13
95
30
138
Heidi
1
27
97.5
4
128.5
Heidi
2
0
195
16
211
Heidi
3
13.5
97.5
20
131
Irene
1
28
100
2
130
Irene
2
0
200
8
208
Irene
3
14
100
10
124
fiddle
We have tables Table1 and Table2
Table 1
ID name subject
1 xxx physics
maths
chemistry
2 yyy physics
maths
chemistry
Table 2
Id Marks
1 70
67
88
2 90
99
89
We need to join the above two tables like this format with condition Table1.Id=Table2.Id,
Id name subject Marks
1 xxx physics 70
maths 67
chemistry 88
2 yyy physics 90
maths 99
chemistry 89
#standardSQL
WITH `project.dataset.table1` AS (
SELECT 1 id, 'xxx' name, ['physics', 'maths', 'chemistry'] subject UNION ALL
SELECT 2, 'yyy', ['physics', 'maths', 'chemistry']
), `project.dataset.table2` AS (
SELECT 1 id, [70, 67, 88] marks UNION ALL
SELECT 2, [90, 99, 89]
)
SELECT *
FROM `project.dataset.table1` t1
JOIN `project.dataset.table2` t2
USING(id)
with result
Row id name subject marks
1 1 xxx physics 70
maths 67
chemistry 88
2 2 yyy physics 90
maths 99
chemistry 89
I'm having an issue writing a query that grabs/calculates the average of three test scores for specific tests for a student. Consider the following TEST_SCORES table:
ID Name TestCode Score
-----------------------------
119 Joe MCA 108
119 Joe BRT 98
119 Joe LPO 76
119 Joe BRT 111
119 Joe ALK 83
119 Joe MCA 100
119 Joe RTK 75
For my scenario, I only want to consider scores from the "MCA" test,
the "BRT" test, and the "RTK" test. I need the average of those tests.
Also, I want to take the highest grade received for those
tests (This is where I get stuck at). The following is what I have
so far:
SELECT A.ID, avg(A.Score)
FROM TEST_SCORES A
WHERE A.TestCode in ('MCA','BRT','RTK')
AND A.ID = 119
GROUP BY A.ID
There are more than one score entry for this student for the "BRT" test and the "MCA" test. I am trying to grab the MAX test score for each test. I try to use a condition to grab the max score, but I keep ending up with the highest test score period as opposed to the average of the three tests.
Any help on this would be greatly appreciated. Thanks in advance.
Get the max score per ID,testCode first and then avg those scores per ID.
SELECT ID,AVG(maxScore) as avgScore
FROM (SELECT ID,TestCode,MAX(Score) as maxScore
FROM TEST_SCORES
WHERE TestCode in ('MCA','BRT','RTK')
GROUP BY ID,TestCode
) t
GROUP BY ID
The setup is not optimal (the NAME shouldn't appear in this table, it should be in a smaller lookup table associating a name to each ID as shown in the illustration below).
Other than that, depending on your Oracle version, which you should always include in your question, you may or may not be able to use the lateral clause (available since Oracle 12.1) for a more efficient solution, in a single pass over the data - even if you need the average score for all students, not just for a single one.
Another observation though - if a student didn't take one of the exams (exam codes) at all, that exam will not be considered in the computation AT ALL, instead of getting averaged in with a score of 0 (as is usually the case in real life). The Accepted Answer doesn't handle that possibility, and neither does the solution below. If that must be handled then you need to clarify your question/requirement.
with
test_data ( id, testcode, score ) as (
select 119, 'MCA', 108 from dual union all
select 119, 'BRT', 98 from dual union all
select 119, 'LPO', 76 from dual union all
select 119, 'BRT', 111 from dual union all
select 119, 'ALK', 83 from dual union all
select 119, 'MCA', 100 from dual union all
select 119, 'RTK', 75 from dual union all
select 200, 'ABC', 110 from dual union all
select 200, 'LPO', 90 from dual union all
select 200, 'BRT', 90 from dual union all
select 200, 'ALK', 102 from dual union all
select 200, 'LPO', 90 from dual
),
students ( id, name ) as (
select 119, 'Joe' from dual union all
select 200, 'Ann' from dual
)
select s.id, s.name, avgscore
from students s,
lateral ( select avg(max(score)) as avgscore
from test_data t
where t.id = s.id
and testcode in ('MCA','BRT','RTK')
group by testcode
)
;
ID NAME AVGSCORE
--- ---- --------
119 Joe 98
200 Ann 90
I store option values and categories in a table.
I want to get one column with all possible combinations of option values.
For example:
Option category ID are (1,2,5)
Option values are {(31,39,55),(61,62),(98,99)}
I want a listing like this, in one column:
31
61
98
31
61
99
31
62
98
31
62
99
39
61
98
39
61
99
39
62
98
39
62
99
55
61
98
55
61
99
55
62
98
55
62
99
Please see below screen shot
Not an answer, just leave it here for you to work with it
Schema, data sample and query you show.
select * into #a from(
select 1 prod,1 id union all
select 1,2 union all
select 1,5 )a
select * into #b from(
select 1 id,31 cat union all
select 1,39 union all
select 1,55 union all
select 2,61 union all
select 2,62 union all
select 5,98 union all
select 5,99 ) b
select * from #a a inner join #b b on a.id=b.id
And this retrieves one row of tree items you look for, in order you need
select b1.cat 'a', b2.cat 'b', b3.cat 'c' from #b b1, #b b2, #b b3, #a a1
where a1.id=b1.id and b2.id>a1.id and b3.id>a1.id and b3.id>b2.id
and b1.cat<b2.cat and b2.cat<b3.cat
order by b1.cat, b2.cat, b3.cat
I'll come back latter
I have a table with the following columns
id, teamA_id, teamB_id
Will it be possible to do a MYSQL SELECT statement that gives both teamA_id and teamB_id in the same column?
EDIT
Consider this example
From
id, teamA_id, teamB_id
1, 21, 45
2, 34, 67
I need
Teams
21
45
34
67
SELECT teamA_id as 'Teams'
FROM Teams
UNION
SELECT teamB_id as 'Teams'
FROM Teams