List the Id who appeared once only in Relational Algebra - sql

Let's say there's a table called Winner, with 3 attributes: Name, Gender and Id.
Name Gender Id
Kevin Male 8
Kevin Male 8
Benny Male 31
Jenny Female 7
Louie Male 4
Peter Male 11
Kevin Male 2
Jenny Female 7
Jenny Female 7
Chris Male 23
Louie Female 14
Apart from those people who is actually 2 different person but with the same name and those people who have the same name but with different gender, their Id's will be the unique value to identify themselves. If I want to list all the Id's who appeared once only in the list, I am thinking to do something like this:
Am I expressing it correctly ?

I don't know what your formula is trying to say, but in SQL you can achieve the result you want with a GROUP BY query:
SELECT Id, COUNT(Id) AS idCount
FROM Winner
GROUP BY Id
HAVING COUNT(Id) = 1

Related

sql command to find out how many players score how much

I have a table like these
country
gender
player
score
year
ID
Germany
male
Michael
14
1990
1
Austria
male
Simon
13
1990
2
Germany
female
Mila
16
1990
3
Austria
female
Simona
15
1990
4
This is a table in the database. It shows 70 countries around the world with player names and gender. It shows which player score how many goals in which year. The years goes from 1990 to 2015. So the table is large. Now I would like to know how many goals all female player and how many male player from Germany have scored from 2010 to 2015. So I would like to know the total score of german male player and the total score of german female player every year from 2010 to 2015 with a Sqlite
I expecting these output
country
gender
score
year
Germany
male
114
2010
Germany
female
113
2010
Germany
male
110
2011
Germany
female
111
2011
Germany
male
119
2012
Germany
female
114
2012
Germany
male
119
2013
Germany
female
114
2013
Germany
male
129
2014
Germany
female
103
2014
Germany
male
109
2015
Germany
female
104
2015
SELECT
country,
gender,
year,
SUM(score) AS score
FROM
<table_name>
WHERE
country ='Germany'
AND year between 2010 and 2015
GROUP BY
1, 2, 3
filtering on country and the years you are interested in
then summing up total score using group by

Sql distinct group of rows

In sql i want get distict sets of rows : identical group for Characteristic and Value only one time :
The column Characteristic can range from one to 10
Table :
Name
Characteristic
Value
Mary
eyes
Blu
Mary
hair
blonde
Mary
Sex
Female
Jhon
eyes
Black
Jhon
Hair
Black
Jhon
Sex
Male
Jhon
Nation
Franch
Bill
eyes
Blu
Bill
Hair
Blond
Bill
Sex
Male
Will
eyes
Green
Will
Hair
Blond
Will
Sex
Male
Will
Nation
Spain
Lilly
eyes
Blu
Lilly
Hair
Blonde
Lilly
Sex
Female
mark
eyes
Black
mark
Hair
Black
mark
Sex
Male
mark
Nation
Franch
Anna
eyes
Blu
Anna
Hair
Blonde
Anna
Sex
Female
Antonio
eyes
Black
Antonio
Hair
Black
Antonio
Sex
Male
Antonio
Nation
Franch
The result that i want to achieve :
Group
Characteristic
Value
1
eyes
Blu
1
Hair
Blonde
1
Sex
Female
2
eyes
Black
2
Hair
Black
2
Sex
Male
2
Nation
Franch
3
eyes
Blu
3
Hair
Blond
3
Sex
Male
4
eyes
Green
4
Hair
Blode
4
Sex
Male
4
Nation
Spain
and finally if it's possible :
Name
Characteristic
Value
Group
Mary
eyes
Blu
1
Mary
Hair
Blonde
1
Mary
Sex
Female
1
Jhon
eyes
Black
2
Jhon
Hair
Black
2
Jhon
Sex
Male
2
Jhon
Nation
Franch
2
Bill
eyes
Blu
3
Bill
Hair
Blond
3
Bill
Sex
Male
3
Will
eyes
Green
4
Will
Hair
Blond
4
Will
Sex
Male
4
Will
Nation
Spain
4
Lilly
eyes
Blu
1
Lilly
Hair
Blonde
1
Lilly
Sex
Female
1
mark
eyes
Black
2
mark
Hair
Black
2
mark
Sex
Male
2
mark
Nation
Franch
2
Anna
eyes
Blu
1
Anna
Hair
Blonde
1
Anna
Sex
Female
1
Antonio
eyes
Black
2
Antonio
Hair
Black
2
Antonio
Sex
Male
2
Antonio
Nation
Franch
2
You can use STRING_AGG to join all the characteristics together, then use ROW_NUMBER and DENSE_RANK to count them. Then you re-join that back to the base table.
For your first query, you can do it like this.
SELECT
Groups.GroupId,
t.Characteristic,
t.Value
FROM YourTable t
JOIN (
SELECT
t.Name,
t.GroupDefinition,
GroupId = DENSE_RANK() OVER (ORDER BY t.GroupDefinition),
RowId = ROW_NUMBER() OVER (PARTITION BY t.GroupDefinition ORDER BY t.Name)
FROM (
SELECT
t.Name,
GroupDefinition = STRING_AGG(Characteristic + ':' + Value, '|')
WITHIN GROUP (ORDER BY t.Characteristic)
FROM YourTable t
GROUP BY
t.Name
) t
) Groups ON Groups.Name = t.Name
WHERE Groups.RowId = 1;
The second query is as follows.
SELECT
Groups.GroupId,
t.*
FROM YourTable t
JOIN (
SELECT
t.Name,
t.GroupDefinition,
GroupId = DENSE_RANK() OVER (ORDER BY t.GroupDefinition),
RowId = ROW_NUMBER() OVER (PARTITION BY t.GroupDefinition ORDER BY t.Name)
FROM (
SELECT
t.Name,
GroupDefinition = STRING_AGG(Characteristic + ':' + Value, '|')
WITHIN GROUP (ORDER BY t.Characteristic)
FROM YourTable t
GROUP BY
t.Name
) t
) Groups ON Groups.Name = t.Name;
db<>fiddle
Another option would be to aggregate it into a JSON or XML format, then shred it back out without re-joining the base table.

Get name(s) from JSON format column, that not in 2 other columns with names

I need to create column with name(s) (Supervisors - can be multiple supervisors at the same time, but also there might not be supervisor at all) from JSON format column, that not in 2 other column with names (Employee and Client).
Id
Employee
Client
AllParticipants
1
Justin Bieber
Ariana Grande
[{"ParticipantName":"Justin Bieber"},{"ParticipantName":"Ariana Grande"}]
2
Lionel Messi
Christiano Ronaldo
[{"ParticipantName":"Christiano Ronaldo"},{"ParticipantName":"Lionel Messi"}]
3
Nicolas Cage
Robert De Niro
[{"ParticipantName":"Robert De Niro"},{"ParticipantName":"Nicolas Cage"},{"ParticipantName":"Brad Pitt"}]
4
Harry Potter
Ron Weasley
[{"ParticipantName":"Ron Weasley"},{"ParticipantName":"Albus Dumbldor"},{"ParticipantName":"Harry Potter"},{"ParticipantName":"Lord Voldemort"}]
5
Tom Holland
Henry Cavill
[{"ParticipantName":"Henry Cavill"},{"ParticipantName":"Tom Holland"}]
6
Spider Man
Venom
[{"ParticipantName":"Venom"},{"ParticipantName":"Iron Man"},{"ParticipantName":"Superman"},{"ParticipantName":"Spider Man"}]
7
Andrew Garfield
Leonardo DiCaprio
[{"ParticipantName":"Tom Cruise"},{"ParticipantName":"Andrew Garfield"},{"ParticipantName":"Leonardo DiCaprio"}]
8
Dwayne Johnson
Jennifer Lawrence
[{"ParticipantName":"Jennifer Lawrence"},{"ParticipantName":"Dwayne Johnson"}]
The output column I need:
Supervisors
NULL
NULL
Brad Pitt
Albus Dumbldor, Lord Voldemort
NULL
Iron Man, Superman
Tom Cruise
NULL
I've tried to create extra columns to use Case expression after that, but it seems too complex.
SELECT *,
JSON_VALUE(w.AllParticipants,'$[0].ParticipantName') AS ParticipantName1,
JSON_VALUE(w.AllParticipants,'$[1].ParticipantName') AS ParticipantName2,
JSON_VALUE(w.AllParticipants,'$[2].ParticipantName') AS ParticipantName3,
JSON_VALUE(w.AllParticipants,'$[3].ParticipantName') AS ParticipantName4
FROM Work AS w
I'm wondering if there is an easy way to compare values and extract only unique ones.

Obtain percentage of values in a column

I have a table called Director, which looks like
DirectorID FirstName FamilyName FullName DoB Gender
1 Steven Spielberg Steven Spielberg 1946-12-18 Male
2 Joel Coen Joel Coen 1954-11-29 Male
3 Ethan Coen Ethan Coen 1957-09-21 Male
4 George Lucas George Lucas 1944-05-14 Male
5 Ang Lee Ang Lee 1954-10-23 Male
6 Martin Scorsese Martin Scorsese 1942-11-17 Male
7 Mimi Leder Mimi Leder 1952-01-26 Female
I am trying to work out the percentage of Female to Male directors
I can work out the number of Male and Female Directors using:
SELECT count(*) as myMale from Director
where Gender = 'Male'
SELECT count(*) as myFemale from Director
where Gender = 'Female')
But I am having trouble combining them to obtain a percentage of Female Directors.
I am looking for the result of 14.3%, which is calculated using:
Total Female Directors / (Total Male Directors + Total Female Directors)
or
1/(6+1)
How would I do this with SQL?
A simple method uses aggregation. Assuming directors are either male or female (binary), then a simple conditional aggregation suffices:
select avg(case when gender = 'Female' then 1.0 else 0 end) as ratio_female
from directors;
If you want to limit this only to male and female (assuming other options), then include where gender in ('female', 'male').

sqlite3: COUNT & EXCEPT not working as expected

I'm fairly new to SQL but having searched the internet for an answer to this I still cannot get my COUNT and EXCEPT statements to select what I want.
My Database:
sqlite> CREATE TABLE Football(Team TEXT, Player TEXT, Age INTEGER, primary key(Team, Player));
sqlite> .separator ,
sqlite> .import databaseTest Football
sqlite> .headers on
sqlite> .mode col
sqlite> SELECT Team, Player, Age FROM Football ORDER BY Team;
Team Player Age
---------- ---------- ----------
Arsenal Cech 38
Arsenal Giroud 29
Arsenal Sanchez 28
Arsenal Walcott 27
Chelsea Costa 29
Chelsea Courtois 25
Chelsea Hazard 26
Chelsea Willian 26
Liverpool Can 23
Liverpool Coutinho 24
Liverpool Wjinaldum 25
Liverpool Woodburn 17
Manchester Aguero 29
Manchester Jesus 19
Manchester Silva 28
Manchester Toure 34
Manchester De Gea 26
Manchester Felliani 29
Manchester Rooney 32
Manchester Schweinste 35
Tottenham Delle Ali 22
Tottenham Kane 24
Tottenham Rose 24
Tottenham Vertonghen 27
What I want to do is SELECT the COUNT of teams that do not have a player over the age of 30. So the select statement should be 3 (Chelsea, Liverpool, Tottenham).
This is the statement I've tried and assumed would work:
sqlite> SELECT COUNT(DISTINCT Team) FROM Football
...> EXCEPT
...> SELECT COUNT(DISTINCT Team) FROM Football WHERE Age > 30;
COUNT(DISTINCT Team)
--------------------
6
But as you can see it returns '6'. What am I doing wrong and how can I get the correct result?
Here is another way. Look at the maximum age for each team:
SELECT COUNT(*)
FROM (SELECT Team
FROM Football
GROUP BY Team
HAVING MAX(Age) <= 30
) t;
You can also use EXCEPT, but this also requires a subquery. You need to do the set operation before doing the count:
SELECT COUNT(DISTINCT TEAM)
FROM (SELECT Team FROM Football
EXCEPT
SELECT Team FROM Football WHERE Age > 30
) t;
Strictly speaking, this query could use COUNT(*) rather than COUNT(DISTINCT). However, it can be troublesome to remember that EXCEPT (like UNION) removes duplicate values.