For each activity, show the volunteer highest number of points - sql

CREATE DATABASE E_volunteerSy;
USE E_volunteerSy;
CREATE TABLE Participate_In
( V_ID INT(4) PRIMARY KEY,
Ename CHAR(20),
POINTS INT(255),
AName CHAR(20)
);
INSERT INTO Participate_In
values
(1001,'Name1',10,'A'),
(1002,'Name2',3,'A'),
(1003,'Name3',11,'B'),
(1004,'Name4',3,'B'),
(1005,'Name5',4,'B');
how can i wright a query that return the highest point for AName A and AName B.
AName meant activity name .

You can use the following using MAX and GROUP BY:
SELECT AName, MAX(POINTS) AS Points FROM Participate_In GROUP BY AName
demo: http://www.sqlfiddle.com/#!9/7b8ea6/1/0

This query will display the highest points for all the activities
SELECT Aname, MAX(points)
FROM Participate_In
GROUP BY Aname

This will select the top record by pointsw for each AName value
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY AName ORDER BY POINTS DESC) AS RowNum
FROM Participate_In
) Sub
WHERE RowNum = 1

Related

How to return ties from aggregation functions in SQLite

I have a homework question which requires me to return the name of the oldest child of a person, and in case of ties return all the ties.
The schema for the database is:
create table persons (
fname char(12),
lname char(12),
bdate date,
bplace char(20),
address char(30),
phone char(12),
primary key (fname, lname)
);
create table births (
regno int,
fname char(12),
lname char(12),
regdate date,
regplace char(20),
gender char(1),
f_fname char(12),
f_lname char(12),
m_fname char(12),
m_lname char(12),
primary key (regno),
foreign key (fname,lname) references persons,
foreign key (f_fname,f_lname) references persons,
foreign key (m_fname,m_lname) references persons
);
My current query is
SELECT fname, lname, min(bdate)
from (SELECT *
from persons
JOIN births using (fname, lname)
WHERE f_fname='Michael' and f_lname='Fox');
Where Michael Fox is the person in question. The expected output is
Q4|MFOld
Q4|MFOld2
however I am only able to get the first oldest child. I tried using a With statement, but we are not allowed to use views or temporary tables to answer this question. I also looked into using Rank (), but to my knowledge, that was introduced insqlite v3.25, but this question will be tested using v3.11. Any insight as to how the ties can be returned?
You can use RANK():
SELECT fname, lname, bdate
FROM (
SELECT
b.fname,
b.lname,
p.bdate,
RANK() OVER(ORDER BY bdate) rnk
from persons p
JOIN births b using (fname, lname)
WHERE b.f_fname='Michael' and b.f_lname='Fox'
) x
WHERE rnk = 1;
If you ever need to remove the where clause in order to get the oldest child(ren) for each person, then you would need to add a use a PARTITION:
SELECT fname, lname, bdate
FROM (
SELECT
b.fname,
b.lname,
p.bdate,
RANK() OVER(PARTITION BY b.f_fname, b.f_lname ORDER BY bdate) rnk
from persons p
JOIN births b using (fname, lname)
) x
WHERE rnk = 1;
In SQLite < 3.25, where window functions such as RANK() are not available, you can use a common table expression (available since version 3.8) to pull out all children of Michael Fox and use NOT EXISTS to filter on the oldest one(s):
WITH cte AS (
SELECT b.fname, b.lname, p.bdate
FROM persons p
JOIN births b using (fname, lname)
WHERE b.f_fname = 'Michael' AND b.f_lname = 'Fox'
)
SELECT *
FROM cte c
WHERE NOT EXISTS (
SELECT 1 FROM cte c1 WHERE c1.bdate < c.bdate
)
Why do you need min, itll be same for all rows as theres no group by just replace it with normal date
SELECT fname, lname, b_date,
row_number() over (partition by b_date
order by fname, lname)
from (SELECT *
from persons
JOIN births using (fname, lname)
WHERE f_fname='Michael' and
f_lname='Fox');

sql max sub of Columns

First I did:
CREATE TABLE Persons (
id INTEGER not null,
capital_loss INTEGER,
capital_gain INTEGER,
salary INTEGER,
PRIMARY KEY ( id )
);
I want to get the id and the salary of one row such that:
max(capital_gain-capital_loss) and salary =50
How about this
select id, salary, max(capital_gain - capital_loss)
from Persons
where salary = 50
group by id, salary
Having on mind your conditions (no matter which row is returned from all of maximum ones), and if you are using mysql:
SELECT id, salary FROM Persons
WHERE salary=50
ORDER BY (capital_gain - capital_loss) DESC LIMIT 1;

Postgres most common value query

I am trying to figure out how to structure some queries, and I am a bit lost.
Tables:
CREATE TABLE dv_customer(
customer_id INTEGER PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(50),
address_id INTEGER,
active BOOLEAN
);
CREATE TABLE dv_address(
address_id INTEGER PRIMARY KEY,
address VARCHAR(50),
address2 VARCHAR(50),
district VARCHAR(50),
city_id INTEGER,
postal_code VARCHAR(50),
phone VARCHAR(50)
);
CREATE TYPE MPAA_RATING AS ENUM(
'G',
'PG',
'PG-13',
'R',
'NC-17'
);
CREATE TABLE dv_film(
film_id INTEGER PRIMARY KEY,
title VARCHAR(50),
description TEXT,
length SMALLINT,
rating MPAA_RATING,
release_year SMALLINT
);
CREATE TABLE cb_customers(
last_name VARCHAR(50),
first_name VARCHAR(50),
PRIMARY KEY (last_name, first_name)
);
CREATE TABLE cb_books(
title VARCHAR(50),
author_id INTEGER,
edition SMALLINT,
publisher VARCHAR(50),
PRIMARY KEY (title, author_id, edition)
);
CREATE TABLE cb_authors(
author_id INTEGER PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50)
);
CREATE TABLE mg_customers(
customer_id INTEGER PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(50),
address_id INTEGER,
active BOOLEAN
);
I need to figure out the following Queries:
What are the first and last names of all customers who live in the district having the most customers?
So far:
SELECT x.first_name, x.last_name
FROM dv_customer x, dv_address y
WHERE x.address_id = y.address_id
AND (SELECT count(district)
FROM dv_address >= SELECT count(district) FROM dv_address
);
What are the first and last names of the top 10 authors when ranked by the number of books each has written? I want author name and book count, in descending order of book count.
So far:
SELECT x.first_name, x.last_name, count(y.title)
FROM cb_authors x, cb_books y
GROUP BY first_name, last_name
ORDER BY count(*) DESC
LIMIT 10;
I know these are a bit of a mess, but they are the only queries I can't seem to figure out. Any help would be appreciated. I am a Postgres noob and just trying to figure out how it works.
What are the first and last names of the top 10 authors when ranked by the number of books each has written
This kind of query is typically done using a window function:
select first_name, last_name, num_books
from (
SELECT x.first_name, x.last_name,
dense_rank() over (order by count(y.title) desc) as rnk,
count(*) as num_books
FROM cb_authors x
join cb_books y on x.author_id = y.author_id
GROUP BY x.author_id
) t
where rnk <= 10
Your from clause FROM cb_authors x, cb_books y is missing a join condition and thus creates a cartesian join between the two tables. It is a good example on why the implicit joins in the where clause are a bad thing. If you get in the habit of using an explicit JOIN operator you will never accidentally miss a join condition.
The above also uses x.author_id which is sufficient for grouping as it is the primary key of the column and all other (non-grouped) columns in the select list are functionally dependent on it.
The query below will give you the district with the most customers
select district
from dv_address
group by district
order by count(*) desc
limit 1
Then you can select all customers living in that district with a sub query
select c.* from dv_customer c
join dv_address a on c.address_id = a.address_id
where a.district = (
select district
from dv_address
group by district
order by count(*) desc
limit 1
)
Similarly you can get the top 10 author_id's with this query
select author_id
from cb_books
group by author_id
order by count(*) desc
limit 10
Similarly, with a dervied table
select a.*, t.cnt from cb_authors a
join (
select author_id, count(*) cnt
from cb_books
group by author_id
order by count(*) desc
limit 10
) t on t.author_id = a.author_id
order by t.cnt desc

find names of classes with the highest enrollement

I have the following relation in database
ENROLLMENT (snum: int, cname:varchar(100))
where snum is the student id and cname is the course name
and I want to find the name(s) of the class(s) with the most students enrolled.
There are multiple solutions. One solution is usage of SELECT TOP 1 :
SELECT TOP 1
cname, count(*) as NumberOfStudents
FROM ENROLLMENT
GROUP BY cname
ORDER BY count(*) desc
Use a common table expression (cte):
with cte as
(
select cname, count(*) as cnt
from ENROLLMENT
group by cname
)
select cname
from cte
where cnt = (select max(cnt) from cte)

using "with" statement on multiple queries?

I am attempting to delete duplicate rows from my table for example if my customer table contained the following:
first_name last_name email
fred wilford wilford#xchange.co.uk
fred wilford wilford#xchange.co.uk
Damian Jones jones#xchange.co.uk
the ideal result should be the following:
first_name last_name email
fred wilford wilford#xchange.co.uk
Damian Jones jones#xchange.co.uk
this should be fairly straightforward to do with an intermediary table created containing the duplicate rows before deleting the duplicates in the master table and lastly insert all rows in the intermediary table back into the master table. However I would prefer to remove the intermediary table and just use something like a with statement.
consider the following example:
with dups as
(
select name,last_name,email from customer group by 1,2,3 having
count(*) > 1
)
delete from customer
using
(
select name,last_name,email from customer group by 1,2,3 having
count(*) > 1
)b
where b.name = customer.name;
insert into customer
(
select name,last_name,email from dups
)
the trouble is the final insert statement fails as "dups" is not recognised. Is there a way to fix this? Thanks in advance
You can chain the CTE if you want to:
WITH dups AS
(
select name,last_name,email from customer group by 1,2,3 having
count(*) > 1
),
del AS(
DELETE FROM customer USING dups WHERE dups.name = customer.name RETURNING dups.*
),
ins AS(
INSERT INTO customer(name,last_name,email) SELECT name,last_name,email FROM del RETURNING del.*
)
SELECT * FROM ins;
You could also do it in this way:
Schema:
create table tbl (first_name varchar(50),
last_name varchar(50),
email varchar(50));
insert into tbl values
('fred','wilford','wilford#xchange.co.uk'),
('fred','wilford','wilford#xchange.co.uk'),
('Damian','Jones','jones#xchange.co.uk');
DO this:
CREATE TABLE temp (first_name varchar(50),
last_name varchar(50),
email varchar(50));
INSERT INTO temp SELECT DISTINCT * FROM tbl;
DROP TABLE tbl;
ALTER TABLE temp RENAME TO tbl;
check:
select * from tbl;
result:
first_name last_name email
fred wilford wilford#xchange.co.uk
Damian Jones jones#xchange.co.uk
Instead of a WITH clause, you could create dups as a temporary table:
CREATE TEMP TABLE dups (name, last_name, email ) AS
(
select name,last_name,email from customer group by 1,2,3 having
count(*) > 1
);