Error code 1111: says invalid use of group function - mysql

Im trying to use
select Suppliers.sid
from Suppliers
left join Catalog on Suppliers.sid=Catalog.sid
where Catalog.cost>avg(Catalog.cost);
but im getting error code 1111:
Unsure what's going on with my database. Im very nice to sql and just having issues getting this to work.
CREATE DATABASE CSC123Lab2;
USE CSC123Lab2;
CREATE TABLE Suppliers (
sid CHAR(20),
sname CHAR(20),
address CHAR(20),
pid CHAR(20)
);
CREATE TABLE Parts (
pid CHAR(20),
pname CHAR(20),
color CHAR(20),
sid CHAR(20)
);
CREATE TABLE Catalog (
sid CHAR(20),
pid CHAR(20),
cost REAL
);
ALTER TABLE Suppliers ADD PRIMARY KEY (sid);
ALTER TABLE Parts ADD PRIMARY KEY (pid);
INSERT INTO Suppliers (sid, sname, address) VALUES (1, "carvel", "1234 Main Street");
INSERT INTO Suppliers (sid, sname, address) VALUES (2, "coldstone", "5678 Pine Street");
INSERT INTO Suppliers (sid, sname, address) VALUES (3, "ralphs", "9876 Oak Street");
INSERT INTO Suppliers (sid, sname, address) VALUES (4, "Acme Widget", "4321 Maple Street");
INSERT INTO Parts (pid, pname, color) VALUES (1, "hammer", "red");
INSERT INTO Parts (pid, pname, color) VALUES (2, "screwdriver", "pink");
INSERT INTO Parts (pid, pname, color) VALUES (3, "nails", "green");
INSERT INTO Parts (pid, pname, color) VALUES (4, "screws", "teal");
INSERT INTO Catalog (sid, pid, cost) VALUES (1, 3, 32);
INSERT INTO Catalog (sid, pid, cost) VALUES (4, 1, 10);
INSERT INTO Catalog (sid, pid, cost) VALUES (4, 3, 48);
INSERT INTO Catalog (sid, pid, cost) VALUES (2, 4, 24);
select Suppliers.sid
from Suppliers
left join Catalog on Suppliers.sid=Catalog.sid
where Catalog.cost>avg(Catalog.cost);
DROP TABLE Catalog;
DROP TABLE Parts;
DROP TABLE Suppliers;
DROP DATABASE CSC123Lab2;

use group by and do filter in next level
with cte as
(select Suppliers.sid,avg(Catalog.cost) as avg_val
from Suppliers
left join Catalog on Suppliers.sid=Catalog.sid
group by Suppliers.sid
) select a.sid
from Catalog a join cte on a.sid=cte.sid
where a.cost>avg_val

I think you just want a window function:
select s.sid
from Suppliers s join
(select c.*, avg(c.cost) over () as avg_cost
from Catalog c
) c
on s.sid = c.sid
where c.cost > c.avg_cost;
Note, though, that you don't really need the left join. The where clause turns the left join into an inner join.
Then, you don't need the join at all, because sid is in both tables:
select c.sid
from (select c.*, avg(c.cost) over () as avg_cost
from Catalog c
) c
where c.cost > c.avg_cost;
If you prefer, you could express this using a subquery:
select c.sid
from Catalog c
where c.cost > (select avg(c2.cost) from catalog c2);

Related

Query to get the ID of authors who published papers in two consecutive years

I want to write a query that displays the ID of the Author who published papers in two consecutive years.
Here is the database schema:
CREATE TABLE Author (aid integer NOT NULL,
name varchar(50) NOT NULL,
affiliation varchar(50), primary key(aid));
CREATE TABLE Paper (pid integer NOT NULL,
title varchar(50) NOT NULL,
year integer NOT NULL, primary key(pid));
CREATE TABLE Authored (aid integer references Author,
pid integer references Paper,
primary key(aid, pid), foreign key(aid) references Author(aid), foreign key(pid) references Paper(pid));
insert into Author(aid, name, affiliation) values (1, "A", "DS");
insert into Author(aid, name, affiliation) values (2, "B", "PS");
insert into Author(aid, name, affiliation) values (3, "C", "CS");
insert into Paper(pid, title, year) values (100, "DS1", 2019);
insert into Paper(pid, title, year) values (101, "PS1", 2019);
insert into Paper(pid, title, year) values (102, "CS1", 2019);
insert into Paper(pid, title, year) values (103, "DS2", 2020);
insert into Paper(pid, title, year) values (104, "PS2", 2020);
insert into Paper(pid, title, year) values (105, "CS2", 2019);
Authored.aid is a foreign key to Author and Authored.pid is a foreign key to Paper. And this is what I have so far but this is not giving me the desired result and I don't know what's wrong:
select au1.aid, a1.name
from authored au1 inner join authored au2 on au1.aid=au2.aid
inner join author a1 on au1.aid=a1.aid
inner join paper p1 on au1.pid=p1.pid
inner join paper p2 on au2.pid=p2.pid
where p1.year = p2.year+1
order by au1.aid;
You need to GROUP BY au1.aid to get distinct authors:
SELECT au1.aid, a1.name
FROM authored au1 INNER JOIN authored au2 ON au1.aid=au2.aid
INNER JOIN author a1 ON au1.aid=a1.aid
INNER JOIN paper p1 ON au1.pid=p1.pid
INNER JOIN paper p2 ON au2.pid=p2.pid AND p1.year+1 = p2.year
GROUP BY au1.aid
ORDER BY au1.aid
Not sure about your query but an IN clause looks to be useful:
where paper.year IN ('2019', '2020')

How to display column names from multiple table using sub query

I have created the following tables and have inserted these values:
create table customer (cid int, cname varchar(25), email varchar(25), phone int, status varchar(25), primary key (cid));
create table accounts( cid int, account int, atype varchar(25), balance int, foreign key(cid) references customer(cid));
create table address( cid int, street varchar(25), city varchar(25), country varchar(25), foreign key(cid) references customer(cid));
insert into customer values (101,'A', 'a#gmail.com', 99,'active');
insert into accounts values (101, 123, 'SA', 1000);
insert into address values (101, 'HMT','Blore','India');
insert into customer values (102,'B', 'b#gmail.com', 199,'active');
insert into accounts values (102, 123, 'CA', 2000);
insert into address values (102, 'Jayanagar','Blore','India');
My objective is to display cname, account and balance of the customers whose status is active.
I have tried writing the query using this: (I am unable to print the column cname using this) But it displays the rest.
select account, balance
from accounts
where cid in (select cid from customer where status = 'active');
this does not work:
select cname, account, balance
from customer, accounts
where cid in (select cid from customer where status = 'active');
One possible way is to join the two tables on the common customer ID.
SELECT c.cname,
a.account,
a.balance
FROM customer c
LEFT JOIN accounts a
ON a.cid = c.cid
WHERE c.status = 'active';
One possible way that worked for me:
SELECT cust.cname,
acc.account,
acc.balance
FROM customer cust,
accounts acc
WHERE cust.cid=acc.cid
AND acc.cid IN
(select cid FROM customer WHERE status='active');
SELECT customer.cname,accounts.account,accounts.balance FROM customer INNER JOIN accounts ON accounts.cid = customer.cid WHERE customer.status = 'active';

SQL: Sort on number of row entries and join

How do I find duplicate entries in a column (like multiple rows in student_id column) and join those to another table with common id (like student_id from another table to get student_name)?
grades:
student_id,grade
6,A
1,B
1,F
7,C
6,A
students:
student_id,student_name
1,roy
6,bob
7,art
so that I can get a joined table of only duplicate student rows on student_id that resembles:
student_id,student_name,grade
6,bob,A
1,roy,B
1,roy,F
6,bob,A
It would be nice to then just return the names of the most recent data frame:
bob
roy
Try this:
select students.student_name
from grades
inner join students on grades.student_id = students.student_id
group by student_name
having count(*) > 1
Example:
create table grades (student_id int, grade char(1));
insert into grades values (6, 'A'), (1, 'B'), (1, 'F'), (7, 'C'), (6, 'A');
create table students (student_id int, student_name varchar(20));
insert into students values (1, 'roy'), (6,'bob'), (7,'art');
select students.student_name
from grades
inner join students on grades.student_id = students.student_id
group by student_name
having count(*) > 1
Result:
student_name
bob
roy
This should result in bob and roy.
Command line on Linux, assuming you have sqlite:
~$ sqlite
SQLite version 2.8.17
Enter ".help" for instructions
sqlite> create table grades (student_id int, grade char(1));
sqlite> insert into grades values (6, 'A');
sqlite> insert into grades values (1, 'B');
sqlite> insert into grades values (1, 'F');
sqlite> insert into grades values (7, 'C');
sqlite> insert into grades values (6, 'A');
sqlite>
sqlite> create table students (student_id int, student_name varchar(20));
sqlite> insert into students values (1, 'roy');
sqlite> insert into students values (6,'bob');
sqlite> insert into students values (7,'art');
sqlite>
sqlite> select students.student_name
...> from grades
...> inner join students on grades.student_id = students.student_id
...> group by student_name
...> having count(*) > 1;
roy
bob
sqlite>
Find duplicates and then join it back for more information:
SELECT s.student_id, s.student_name
FROM student s
INNER JOIN
(SELECT g.student_id
FROM grades g
GROUP BY g.student_id
HAVING COUNT(*) > 1) dups
ON s.student_id = dups.student_id

Stuck with sql subquery

I have these 3 tables :
1) Sailors (sid:INT, sname:VARCHAR(30), rating:INT, age:INT)
2) Boats (bid:INT, bname:VARCHAR(30), color:VARCHAR(10))
3) Reserves (bid:INT, sid:INT, day:DATE)
I want to write a query which displays the number(bid) of every boat that has been reserved by all the sailors at least once/
So far I wrote this :
SELECT b.bid, b.bname
FROM boats as b , sailors as s , reserves as r
WHERE r.bid = b.bid and r.sid = s.sid
GROUP BY r.bid
HAVING count(r.sid) = count(s.sid)
It seems the right answer to me but after trying it on MYSQL id didn't work.
Have you tried comparing the count of boat reserves to count of sailors like this?
HAVING count(r.sid) = (Select count(sid) from sailors)
you also need to make sure that count(r.sid) is a unique count of bid and sid incase the same sailor reserved the same boat more than once.
SELECT g.bid,
g.name
FROM
(SELECT b.bid, b.name, s.sid
FROM boats AS b, reserves AS r, sailors AS s
WHERE b.bid = r.bid AND r.sid = s.sid
GROUP BY b.bid, b.name, s.sid
) AS g
GROUP BY g.bid, g.name
HAVING COUNT(g.bid) = (SELECT COUNT(s.SID) FROM sailors AS s)
There are several query patterns that will return the specified result.
Assuming that the sid column in the Reserves table is a FOREIGN KEY referencing Sailors(sid), we can use a distinct count of sid from the Reserves table for a given boat, and compare that to a distinct count of sid from Sailors.
For example:
SELECT b.bid
, b.bname
FROM Boats b
JOIN ( SELECT rr.bid
, COUNT(DISTINCT rr.sid) AS cnt
FROM Reserves rr
GROUP BY rr.bid
) r
ON r.bid = b.bid
JOIN ( SELECT COUNT(DISTINCT ss.sid) AS cnt
FROM Sailors ss
) s
ON s.cnt = r.cnt
The inline view aliased as r gets us a count of distinct sid values for each boat, from the Reserves table.
The inline view aliased as s gets us a count of distinct sid values from Sailors. If sid is the PRIMARY KEY or UNIQUE KEY of Sailors (which is what we expect, it's the normative pattern) we can omit the DISTINCT keyword. The question did not indicate if this was the case, so rather than making a wrong assumption, we write a query that will work in the more general case.)
This query did assume that there was a foreign key constraint... that rows in Reserves would not have a non-NULL value that didn't reference a row in Sailors. If that's not the case, we can modify the inline view query r, so we get a distinct count of sid values that appear in the Sailors table.
This can replace the inline view query r above:
( SELECT rr.bid
, COUNT(DISTINCT rr.sid) AS cnt
FROM Reserves rr
JOIN Sailors rs
ON rs.sid = rr.sid
GROUP BY rr.bid
) r
This query pattern can easily be adapted to check conditions other than ALL sailors.
And there are other query patterns that can achieve an equivalent result.
You Can Check This out :)
===============================================
CREATE TABLE Sailors (sid INT, sname VARCHAR(30), rating INT, age INT)
INSERT INTO Sailors values (1,'S1',100,20);
INSERT INTO Sailors values (2,'S2',100,20);
INSERT INTO Sailors values (3,'S3',100,20);
INSERT INTO Sailors values (4,'S4',100,20);
INSERT INTO Sailors values (5,'S5',100,20);
CREATE TABLE Boats (bid INT, bname VARCHAR(30), color VARCHAR(10))
INSERT INTO Boats values (1,'B1','Blue');
INSERT INTO Boats values (2,'B2','Red');
INSERT INTO Boats values (3,'B3','Green');
INSERT INTO Boats values (4,'B4','Blue');
INSERT INTO Boats values (5,'B5','Green');
CREATE TABLE Reserves (bid INT, sid INT, day DATE)
INSERT INTO Reserves values (1,1,'2015-01-01');
INSERT INTO Reserves values (1,2,'2015-01-01');
INSERT INTO Reserves values (1,3,'2015-01-01');
INSERT INTO Reserves values (1,4,'2015-01-01');
INSERT INTO Reserves values (1,5,'2015-01-01');
INSERT INTO Reserves values (2,1,'2015-01-01');
INSERT INTO Reserves values (2,2,'2015-01-01');
INSERT INTO Reserves values (2,3,'2015-01-01');
INSERT INTO Reserves values (2,4,'2015-01-01');
INSERT INTO Reserves values (2,5,'2015-01-01');
INSERT INTO Reserves values (2,3,'2015-01-02');
INSERT INTO Reserves values (2,4,'2015-01-03');
INSERT INTO Reserves values (2,5,'2015-01-04');
INSERT INTO Reserves values (3,1,'2015-01-02');
INSERT INTO Reserves values (4,1,'2015-01-03');
INSERT INTO Reserves values (5,1,'2015-01-04');
===============================================
SELECT Reserves.bid , Boats.bname FROM Reserves , Boats
WHERE Reserves.bid = Boats.bid
GROUP BY Reserves.bid , Boats.bname
HAVING COUNT (DISTINCT Reserves.sid) = (SELECT COUNT(sid) FROM Sailors)
Result ===>
BID BNAME
---------------
1 B1
2 B2
Hope it will help :)

MySQL query returning detailed group_contact information (with join)?

I have query which return me color of the owner and his pet's numbers. How to return instead of
[Red][1,2]
someting more detailed like
[Red][Rufus, Bali]
It's name of pet with join on id of the pet. Is possibile to make another Columns on every pet name? (without using few selects of courst)
CREATE TABLE pet (id INT, name VARCHAR(20));
insert into pet values (1,"Rufus");
insert into pet values (2,"Bali");
insert into pet values (3,"Lolo");
CREATE TABLE own (id INT, own_name VARCHAR(20), own_color VARCHAR(20));
insert into own values (1,"Me", "Red");
insert into own values (2,"Other owners" ,"Green");
CREATE TABLE pet_owner (id INT, id_pet INT, id_own INT);
insert into pet_owner values (1, 1, 1);
insert into pet_owner values (2, 2, 1);
insert into pet_owner values (3, 3, 2);
DROP procedure if exists `pet`;
DELIMITER $$
CREATE procedure `pet`()
BEGIN
set #param = 1;
select o.own_color as color,
(select group_concat(id_pet) from pet_owner po where po.id_own = #param) as pets
from own o
where o.id = #param;
END$$
call pet;
select o.own_color as color,
(select group_concat(p.name) from pet_owner po join pet p ON p.id = po.id_pet where po.id_own = #param) as pets
Try the following--the keys are the aggregate GROUP_CONCAT function and the GROUP BY clause:
select o.own_color as color, group_concat(p.name) as pet_names
from own o
inner join pet_owner po on o.id = po.id_own
inner join pet p on po.id_pet = p.id
group by o.id;