Struggling to structure an SQL query - mysql

Currently I'm trying to run a query that returns the 'Trainer' username and 'Type' title for every trainer who has caught all unique 'Species' of a specific type. For example, if there are two distinct species who are type fighting, and Jenny has caught both of them, then she should be output as such:
---------------------
| Username | Type |
---------------------
| Jenny | Fighting |
---------------------
If she has also caught all distinct species of another type, another row would be output, but with a different type. This must account for the fact a species have two types and that a trainer may catch more than one of each species, so to determine if someone has caught all species of a type, both types are taken into account. Here is what the tables look like:
(Type) (Species) (Trainer) (Pokemon)
------------ ---------------------------- --------------- ------------------------
| id | title | | id | title | type1 | type2 | | id | username | | id | species | trainer |
------------ ---------------------------- --------------- ------------------------
I've also provided the schema and sample data for the query. With an expected result set underneath it. So far I've taken an approach to determining how many unique species of each type there are with the following query:
SELECT Type.id AS TypeID, Type.title, COUNT(Species.id) AS 'Number of Species of Type'
FROM Type, Species WHERE Type.id = Species.type1 OR Type.id = Species.type2 GROUP BY Type.id;
My next thought was to determine how many species of each type a trainer has caught, so that I can compare the two. But I'm stuck on how I could structure the query to do so. Views or common table expressions also cannot be used. Any suggestions or ideas would be appreciated.
create database pokemon;
use pokemon;
CREATE TABLE IF NOT EXISTS `Type` (
`id` TINYINT NOT NULL,
`title` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE IF NOT EXISTS `Species` (
`id` TINYINT UNSIGNED NOT NULL,
`title` VARCHAR(50) NOT NULL,
`type1` TINYINT NOT NULL,
`type2` TINYINT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`type1`) REFERENCES `Type` (`id`),
FOREIGN KEY (`type2`) REFERENCES `Type` (`id`));
CREATE TABLE IF NOT EXISTS `Trainer` (
`id` INT NOT NULL,
`username` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE IF NOT EXISTS `Pokemon` (
`id` BIGINT NOT NULL,
`species` TINYINT UNSIGNED NOT NULL,
`trainer` INT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`trainer`) REFERENCES `Trainer` (`id`),
FOREIGN KEY (`species`) REFERENCES `Species` (`id`));
insert into Type values (1,'Normal');
insert into Type values (2,'Fighting');
insert into Type values (3,'Flying');
insert into Type values (4,'Poison');
insert into Type values (5,'Ground');
insert into Type values (6,'Rock');
insert into Type values (7,'Bug');
insert into Type values (8,'Ghost');
insert into Type values (9,'Steel');
insert into Type values (10,'Fire');
insert into Type values (11,'Water');
insert into Type values (12,'Grass');
insert into Type values (13,'Electric');
insert into Type values (14,'Psychic');
insert into Type values (15,'Ice');
insert into Type values (16,'Dragon');
insert into Type values (17,'Dark');
insert into Type values (18,'Fairy');
insert into Species values (100,'Voltorb',13,null);
insert into Species values (101,'Electrode',13,null);
insert into Species values (102,'Exeggcute',12,14);
insert into Species values (103,'Exeggutor',12,14);
insert into Species values (104,'Cubone',5,null);
insert into Species values (105,'Marowak',5,null);
insert into Species values (106,'Hitmonlee',2,null);
insert into Species values (107,'Hitmonchan',2,null);
insert into Species values (108,'Lickitung',1,null);
insert into Species values (109,'Koffing',4,null);
insert into Species values (110,'Weezing',4,null);
insert into Species values (111,'Rhyhorn',5,6);
insert into Species values (112,'Rhydon',5,6);
insert into Species values (113,'Chansey',1,null);
insert into Species values (114,'Tangela',12,null);
insert into Species values (115,'Kangaskhan',1,null);
insert into Species values (116,'Horsea',11,null);
insert into Species values (117,'Seadra',11,null);
insert into Species values (118,'Goldeen',11,null);
insert into Species values (119,'Seaking',11,null);
insert into Species values (120,'Staryu',11,null);
insert into Species values (121,'Starmie',11,14);
insert into Trainer values (1,'Ash');
insert into Trainer values (2,'Brock');
insert into Trainer values (3,'Misty');
insert into Trainer values (4,'Jenny');
insert into Trainer values (5,'Luna');
insert into Pokemon values (1,109,1);
insert into Pokemon values (2,110,1);
insert into Pokemon values (3,115,1);
insert into Pokemon values (4,113,1);
insert into Pokemon values (5,108,1);
insert into Pokemon values (6,117,1);
insert into Pokemon values (7,102,2);
insert into Pokemon values (8,103,2);
insert into Pokemon values (9,121,2);
insert into Pokemon values (10,104,2);
insert into Pokemon values (11,111,3);
insert into Pokemon values (12,112,3);
insert into Pokemon values (13,121,3);
insert into Pokemon values (14,106,4);
insert into Pokemon values (15,107,4);
insert into Pokemon values (16,110,4);
Expected result set for the sample data is:
---------------------
| Username | Type |
| --------------------|
| Ash | Poison |
| --------------------|
| Ash | Normal |
| --------------------|
| Brock | Psychic |
| --------------------|
| Misty | Rock |
| --------------------|
| Jenny | Fighting |
--------------------

WITH
cte1 AS ( SELECT Species.id sid, t1.id, t1.title ttitle
FROM Species
JOIN Type t1 ON Species.type1 = t1.id
UNION ALL
SELECT Species.id sid, t2.id, t2.title ttitle
FROM Species
JOIN Type t2 ON Species.type2 = t2.id ),
cte2 AS ( SELECT ttitle, COUNT(id) ids
FROM cte1
GROUP BY ttitle ),
cte3 AS ( SELECT Trainer.username, cte1.ttitle, COUNT(*) ids
FROM Pokemon
JOIN Trainer ON Pokemon.trainer = Trainer.id
JOIN cte1 ON Pokemon.species = cte1.sid
GROUP BY Trainer.username, cte1.ttitle )
SELECT cte3.username, cte2.ttitle type
FROM cte2
JOIN cte3 USING (ttitle, ids);
The same without CTE, for MySQL 5.x
SELECT cte3.username, cte2.ttitle type
FROM ( SELECT ttitle, COUNT(id) ids
FROM ( SELECT Species.id sid, t1.id, t1.title ttitle
FROM Species
JOIN Type t1 ON Species.type1 = t1.id
UNION ALL
SELECT Species.id sid, t2.id, t2.title ttitle
FROM Species
JOIN Type t2 ON Species.type2 = t2.id) AS cte1
GROUP BY ttitle ) AS cte2
JOIN ( SELECT Trainer.username, cte1.ttitle, COUNT(*) ids
FROM Pokemon
JOIN Trainer ON Pokemon.trainer = Trainer.id
JOIN ( SELECT Species.id sid, t1.id, t1.title ttitle
FROM Species
JOIN Type t1 ON Species.type1 = t1.id
UNION ALL
SELECT Species.id sid, t2.id, t2.title ttitle
FROM Species
JOIN Type t2 ON Species.type2 = t2.id) AS cte1 ON Pokemon.species = cte1.sid
GROUP BY Trainer.username, cte1.ttitle) AS cte3 USING (ttitle, ids);
https://dbfiddle.uk/?rdbms=mysql_8.0&rdbms2=mysql_5.7&fiddle=0a33601724fa53d9ee4a583c983ff01a

If it is the case a trainer can take the same Specie more than once, and of course, that shouldn't count as two species taken you would just have to substitute table Pokémon by a version of the table with no duplicates, meaning:
(select distinct species, trainer from pokemon)
So the query would be:
select t.username, tp.title
from
(select p.trainer, t.id TypeID, count(species) Cuenta
from (select distinct species, trainer from pokemon) p, species s, type t
where p.species = s.id
and (s.type1 = t.id or s.type2 = t.id)
group by p.trainer, t.id) Tra
, (SELECT Type.id AS TypeID, Type.title, COUNT(Species.id) Cuenta
FROM Type, Species WHERE Type.id = Species.type1 OR Type.id = Species.type2
GROUP BY Type.id) ty
, trainer t, type tp
where ty.TypeID = Tra.TypeId
and ty.Cuenta = Tra.Cuenta
and t.id = Tra.Trainer
and tp.id = Tra.TypeId;
In order to test the result I added these three records of Ground type; Specie Cubone to Brock:
insert into Pokemon values (17,104,2);
insert into Pokemon values (18,104,2);
insert into Pokemon values (19,104,2);
And I observed that, with the previous query, Brock would appear as a certificate in Ground and with this new one it does not.
PS.: You can make same substitution in Akina's query and I am sure it will work just as well.

I really like Akina's solution. It is well organised and beautiful. Mine does not look so nice, but, just in case you want another approach:
select t.username, tp.title
from
(select p.trainer, t.id TypeID, count(species) Cuenta
from pokemon p, species s, type t
where p.species = s.id
and (s.type1 = t.id or s.type2 = t.id)
group by p.trainer, t.id) Tra
, (SELECT Type.id AS TypeID, Type.title, COUNT(Species.id) Cuenta
FROM Type, Species WHERE Type.id = Species.type1 OR Type.id = Species.type2
GROUP BY Type.id) ty
, trainer t, type tp
where ty.TypeID = Tra.TypeId
and ty.Cuenta = Tra.Cuenta
and t.id = Tra.Trainer
and tp.id = Tra.TypeId
Tra is about the courses that each trainer has.
ty is the query that you put in the question about how many species per type.

Related

MySQL select row from one table with multiple rows in a second table and get array of multi row in selected row

i have one table containing "Client" information, and another including "Tickets" information for each client.
int-------| varchar -------| varchar
client_id | client_name | client_tickets
----------+----------------+--------------
1 | Title one | 1,2
2 | Title two | 2,3
Simplified tickets table
int--------| varchar -------| varchar
ticket_id | ticket_name | ticket_price
-----------+-------------+--------------
1 | ticketone | 30
2 | tickettwo | 40
3 | ticketthree | 50
4 | ticketfour | 60
5 | ticketfive | 70
With the above two tables, I want to produce a single table with a single query with all the pertinent information to generate a search grid
So as to give the following output :
client_id | client_name | client_tickets | ticket_names | ticket_prices
----------+----------------+----------------+-----------------------+--
1 | Title one | 1,2 | ticketone,tickettwo | 30,40
2 | Title two | 2,3 | tickettwo,ticketthree | 40,50
ticket_names,ticket_ids,client_name are varchar
I want to receive the final 5 columns with one request
for example :
SELECT s.*,
(SELECT GROUP_CONCAT(ticket_name SEPARATOR ',') FROM tickets_table WHERE ticket_id IN(s.client_tickets)) AS ticket_names,
(SELECT GROUP_CONCAT(ticket_price SEPARATOR ',') FROM tickets_table WHERE ticket_id IN(s.client_tickets)) AS ticket_prices
FROM client_table s where s.client_id=1
Which seems to have a problem
Do you have a better suggestion?
Please make your suggestions
Update :
To clean the result I want
The following code has two querys,
I want this code to be done with a query
$client_result = $conn->query("SELECT * FROM client_table where client_id=1");
while($client_row = $client_result->fetch_assoc()) {
$ticket_result = $conn->query("SELECT * FROM tickets_table where ticket_id IN ($client_row['client_tickets'])");
while($ticket_row = ticket_result->fetch_assoc()) {
echo $ticket_row['ticket_name']."<br>";
}
}
update 2
i use suggest #raxi , but my mariadb is 10.4.17-MariaDB and don't support JSON_ARRAYAGG , for resolve it according to the reference Creating an aggregate function
, Using SQL
DELIMITER //
DROP FUNCTION IF EXISTS JSON_ARRAYAGG//
CREATE AGGREGATE FUNCTION IF NOT EXISTS JSON_ARRAYAGG(next_value TEXT) RETURNS TEXT
BEGIN
DECLARE json TEXT DEFAULT '[""]';
DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN json_remove(json, '$[0]');
LOOP
FETCH GROUP NEXT ROW;
SET json = json_array_append(json, '$', next_value);
END LOOP;
END //
DELIMITER ;
What you want a fairly straightforward SELECT query with some LEFT/INNER JOIN(s).
This website has some good examples/explanations which seem very close to your need: https://www.mysqltutorial.org/mysql-inner-join.aspx
I would give you a quick working example, but it is not really clear to me what datatype the relevant columns are. Both tables' _id-columns are likely some variant of INTEGER, are they also both primary keys (or otherwise atleast indexed ?), the client_name/ticket_name are likely VARCHAR/TEXT/STRING types, but how exactly is the remaining column stored? as json or array or ? (+details)
Also you tagged your post with PHP, are you just after the SQL query ? or looking for PHP code with the SQL inside it.
updated
Improved version of the schema
CREATE TABLE clients (
client_id SERIAL,
client_name VARCHAR(255) NOT NULL,
PRIMARY KEY (client_id)
);
CREATE TABLE tickets (
ticket_id SERIAL,
ticket_name VARCHAR(255) NOT NULL,
ticket_price DECIMAL(10,2) NOT NULL,
PRIMARY KEY (ticket_id)
);
-- A junction table to glue those 2 tables together (N to N relationship)
CREATE TABLE client_tickets (
client_id BIGINT UNSIGNED NOT NULL,
ticket_id BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (client_id, ticket_id)
);
I have changed the datatypes.
client_name and ticket_name are still VARCHARS. I've flagged them as NOT NULL (eg: required fields), but you can remove that part if you don't like that.
client_id/ticket_id/ticket_price are also NOT NULL but changing that has negative side-effects.
ticket_price is now a DECIMAL field, which can store numbers such as 1299.50 or 50.00 The (10,2) bit means it covers every possible number up to 8 whole digits (dollars/euros/whatever), and 2 decimals (cents). so you can store anything from $ -99.999.999,99 to $ 99.999.999,99 .
in SQL always write numbers (like lets say 70k) in this notation: 70000.00 (eg: a dot, not a comma; and no thousandseperators).
client_id and ticket_id are both SERIALs now, which is shorthand for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE and theyre both PRIMARY KEYs on top of that. That probably sounds complicated but they're still just ordinary INTEGERs with values like 4 or 12 etc.
The UNIQUE bit prevents you from having 2 clients with the same ID number, and the AUTO_INCREMENT means that when you add a new client, you dont have to specify an ID (though you are allowed to); you can just do:
INSERT INTO clients (client_name) values ('Fantastic Mr Fox');
and the client_id will automatically be set (incrementing over time). And the same goes for ticket_id in the other table.
.
I've replaced your original client_tickets column, into a separate junction table.
Records in there store the client_id of a client and the ticket_id that belongs to them.
A client can have multiple records in the junction table (one record for each ticket they own).
Likewise, a ticket can be mentioned on any number of rows.
It's possible for a certain client_id to not have any records in the junction table.
Likewise, it's possible for a certain ticket_id to not have any records in the junction table.
Identical records cannot exist in this table (enforced by PRIMARY KEY).
Testdata
Next, we can put some data in there to be able to test it:
-- Create some tickets
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (1, 'ticketone', '30' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (2, 'tickettwo', '40' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (3, 'ticketthree', '50' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (4, 'ticketfour', '60' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (5, 'ticketfive', '70' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (6, 'ticketsix', '4' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (7, 'ticketseven', '9' );
INSERT INTO tickets (ticket_id, ticket_name, ticket_price) values (8, 'ticketeight', '500' );
-- Create some users, and link them to some of these tickets
INSERT INTO clients (client_id, client_name) values (1, 'John');
INSERT INTO client_tickets (client_id, ticket_id) values (1, 3);
INSERT INTO client_tickets (client_id, ticket_id) values (1, 7);
INSERT INTO client_tickets (client_id, ticket_id) values (1, 1);
INSERT INTO clients (client_id, client_name) values (2, 'Peter');
INSERT INTO client_tickets (client_id, ticket_id) values (2, 5);
INSERT INTO client_tickets (client_id, ticket_id) values (2, 2);
INSERT INTO client_tickets (client_id, ticket_id) values (2, 3);
INSERT INTO clients (client_id, client_name) values (3, 'Eddie');
INSERT INTO client_tickets (client_id, ticket_id) values (3, 8);
INSERT INTO clients (client_id, client_name) values (9, 'Fred');
-- Note: ticket #3 is owned by both client #1/#2;
-- Note: ticket #4 and #6 are unused;
-- Note: client #9 (Fred) has no tickets;
Queries
Get all the existing relationships (ticket-less clients are left out & owner-less tickets are left out)
SELECT clients.*
, tickets.*
FROM client_tickets AS ct
INNER JOIN clients ON ct.client_id = clients.client_id
INNER JOIN tickets ON ct.ticket_id = tickets.ticket_id
ORDER BY clients.client_id ASC
, tickets.ticket_id ASC ;
Get all the tickets that are still free (owner-less)
SELECT tickets.*
FROM tickets
WHERE tickets.ticket_id NOT IN (
SELECT ct.ticket_id
FROM client_tickets AS ct
)
ORDER BY tickets.ticket_id ASC ;
Get a list of ALL clients (even ticketless ones), and include how many tickets each has and the total price of their tickets.
SELECT clients.*
, COALESCE(COUNT(tickets.ticket_id), 0) AS amount_of_tickets
, COALESCE(SUM(tickets.ticket_price), 0.00) AS total_price
FROM clients
LEFT JOIN client_tickets AS ct ON ct.client_id = clients.client_id
LEFT JOIN tickets ON ct.ticket_id = tickets.ticket_id
GROUP BY clients.client_id
ORDER BY clients.client_id ASC ;
Put all the juicy info together (owner-less tickets are left out)
SELECT clients.*
, COALESCE(COUNT(sub.ticket_id), 0) AS amount_of_tickets
, COALESCE(SUM(sub.ticket_price), 0.00) AS total_price
, JSON_ARRAYAGG(sub.js_tickets_row) AS js_tickets_rows
FROM clients
LEFT JOIN client_tickets AS ct ON ct.client_id = clients.client_id
LEFT JOIN (
SELECT tickets.*
, JSON_OBJECT( 'ticket_id', tickets.ticket_id
, 'ticket_name', tickets.ticket_name
, 'ticket_price', tickets.ticket_price
) AS js_tickets_row
FROM tickets
) AS sub ON ct.ticket_id = sub.ticket_id
GROUP BY clients.client_id
ORDER BY clients.client_id ASC ;
-- sidenote: output column `js_tickets_rows` (a json array) may contain NULL values
An list of all tickets with some aggregate data
SELECT tickets.*
, IF(COALESCE(COUNT(clients.client_id), 0) > 0
, TRUE, FALSE) AS active
, COALESCE( COUNT(clients.client_id), 0) AS amount_of_clients
, IF(COALESCE( COUNT(clients.client_id), 0) > 0
, GROUP_CONCAT(clients.client_name SEPARATOR ', ')
, NULL) AS client_names
FROM tickets
LEFT JOIN client_tickets AS ct ON ct.ticket_id = tickets.ticket_id
LEFT JOIN clients ON ct.client_id = clients.client_id
GROUP BY tickets.ticket_id
ORDER BY tickets.ticket_id ASC
, clients.client_id ASC ;

Group by wether or not the cell exists in another table as well

My SQL syntax is MariaDB (MySQL)
I have a table with organisation spokepersons, and a table with VIP organizations, and a table with presentations. How do I group or sort by wether the spokeperson's organisation is VIP, so that VIP organisation spokepersons show up on top when retrieving all presentations?
Table presentations: int presentation_id, int person_id, varchar title, date date
Table persons: int person_id, varchar name, varchar function, varchar organisation
Table VIP_orgs: int org_id, varchar org_name
Query that doesn't work:
CREATE TABLE persons (
person_id INT AUTO_INCREMENT,
name VARCHAR(64),
organisation VARCHAR(64),
PRIMARY KEY (person_id)
);
INSERT INTO `persons` (name, organisation) VALUES
("Guy Fieri", "VIP-org"),
("Fiona", "VIP inc."),
("Mr. Robot", "Evil Corp"),
("Marcus Antonius", "Rome"),
("Cicero", "Rome"),
("Shrek", "VIP inc.");
CREATE TABLE presentations (
presentation_id INT AUTO_INCREMENT,
person_id INT,
PRIMARY KEY (presentation_id)
);
INSERT INTO `presentations` (person_id) VALUES
(1),(1),(1),(1), -- guy fieri has 4
(2),
(3),(3),(3),(3),(3),
(4),(4),(4),(4),
(5),(5),(5),
(6),(6),(6),(6);
CREATE TABLE VIP_orgs (
org_id INT AUTO_INCREMENT,
org_name VARCHAR(64),
PRIMARY KEY (org_id)
);
INSERT INTO `VIP_orgs` (org_name) VALUES
("VIP-org"),
("VIP inc.");
SELECT organisation, COUNT(*) AS count
FROM `presentations`
JOIN `persons` ON `presentations`.person_id = `persons`.person_id
GROUP BY (SELECT org_name FROM `VIP_orgs` WHERE `VIP_orgs`.org_name = organisation), organisation
ORDER BY count DESC;
What I expect it to do:
return a table org_name, (total combined number of presentations by each spokeperson of that org)
Sorted by count of presentations, grouped by organisation, VIP organisations grouped on top.
The VIP and non-VIP parts should be sorted by count independently. The returned table should thus look something like this:
name count
VIP inc. 5
VIP-org 4
Rome 7
Evil Corp 5
The query works 50%: it counts all presentations and sorts it, but it doesn't seem to group by VIP organizations. In actuality the returned table looks like this:
name count
Rome 7
VIP inc. 5
Evil Corp 5
VIP-org 4
The schema doesn't look right. I would suggest creating an organisations table with a vip BOOLEAN column and add foreign key in persons table. Make the following changes in the schema:
CREATE TABLE `organisations` (
organisation_id INT AUTO_INCREMENT,
name VARCHAR(64),
vip BOOLEAN,
PRIMARY KEY (organisation_id)
);
INSERT INTO `organisations` (name, vip) VALUES
("VIP-org", True),
("VIP inc.", True),
("Evil Corp", False),
("Rome", False);
CREATE TABLE persons (
person_id INT AUTO_INCREMENT,
name VARCHAR(64),
organisation_id INT,
PRIMARY KEY (person_id),
FOREIGN KEY (organisation_id) REFERENCES `organisations`(organisation_id)
);
INSERT INTO `persons` (name, organisation_id) VALUES
("Guy Fieri", 1),
("Fiona", 2),
("Mr. Robot", 3),
("Marcus Antonius", 4),
("Cicero", 4),
("Shrek", 2);
Now the query would look something like this:
SELECT `organisations`.name as organisation, COUNT(*) AS count
FROM `presentations`
JOIN `persons` ON `presentations`.person_id = `persons`.person_id
JOIN `organisations` ON `organisations`.organisation_id = `persons`.organisation_id
GROUP BY `organisations`.organisation_id
ORDER BY `organisations`.vip DESC, count DESC;
Output:
+--------------+------------+
| organisation | count |
+--------------+------------+
| VIP inc. | 5 |
| VIP-org | 4 |
| Rome | 7 |
| Evil Corp | 5 |
+--------------+------------+
You can see the result here: db <> fiddle
Instead of grouping by, I needed to sort. DOh!
Edit: this doesn't quite work. It does not sort by count. If I put the ORDER BY count clause first, it puts all vip orgs on the bottom.
Edit 2: using EXISTS, it seems to work
SELECT organisation, COUNT(*) AS count
FROM `presentations`
JOIN `persons` ON `presentations`.person_id = `persons`.person_id
GROUP BY organisation
ORDER BY EXISTS (SELECT org_name FROM `VIP_orgs` WHERE `VIP_orgs`.org_name = organisation) DESC, count DESC;

How do I insert a limited number records to TableA from TableB , where TableC contains the list of records to insert?

I am using MySQL 5.6
Note:
TableA is Active_Orders
TableB is Old_Orders
TableC is Move_Orders
The field "contract" is unique in all three tables.
Here is what I got so far
Database setup:
CREATE TABLE IF NOT EXISTS Active_Orders (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
contract VARCHAR(255) NOT NULL UNIQUE
) ENGINE=INNODB;
INSERT INTO Active_Orders(name, contract)
VALUES ('steve', '3454'),
('tom', '6756'),
('becky', '9809');
CREATE TABLE IF NOT EXISTS Old_Orders (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
contract VARCHAR(255) NOT NULL UNIQUE
) ENGINE=INNODB;
INSERT INTO Old_Orders(name,contract)
VALUES ('mark', '9896'),
('kelly', '0897'),
('paul', '1537'),
('will', '8254');
CREATE TABLE IF NOT EXISTS Move_Orders (
contract VARCHAR(255) NOT NULL UNIQUE
) ENGINE=INNODB;
INSERT INTO Move_Orders(contract)
VALUES ('0897'),
('1537);
The Code I am using is:
INSERT INTO Active_Orders (name, contract)
SELECT name, contract
FROM Old_Orders
WHERE Move_Orders.contract = Old_Orders.contract;
But I am getting
#1054 - Unknown column 'Move_Orders.contract' in 'where clause'
What I want the result to be is:
SELECT * FROM Active_Orders;
id name contract
1 steve 3454
2 tom 6756
3 becky 9809
4 kelly 0897
5 paul 1537
I understand that 'Move_Orders.contract' is not in the FROM clause so I am getting error, but I am not sure how to rewrite the statement to get the output I need.
INSERT INTO Active_Orders (name, contract)
SELECT Old_Orders.name, Old_Orders.contract
FROM Old_Orders
JOIN Move_Orders ON Move_Orders.contract = Old_Orders.contract;
or
INSERT INTO Active_Orders (name, contract)
SELECT Old_Orders.name, Old_Orders.contract
FROM Old_Orders, Move_Orders
WHERE Move_Orders.contract = Old_Orders.contract;
or
INSERT INTO Active_Orders (name, contract)
SELECT name, contract
FROM Old_Orders
WHERE EXISTS ( SELECT contract
FROM Move_Orders
WHERE Move_Orders.contract = Old_Orders.contract )
It's nearly a literal translation from English:
INSERT INTO Active_Orders (name, contract)
SELECT o.name, o.contract
FROM Old_Orders o
WHERE o.contract IN (SELECT contract FROM Move_Orders)
You could also do a INNER JOIN between old_orders and move_orders, which will cause moveorders to filter the list of oldorders down to just those also present in move_orders
INSERT INTO Active_Orders (name, contract)
SELECT o.name, o.contract
FROM
Old_Orders o
INNER JOIN Move_Orders m ON o.contract = m.contract

sql select query using inner join

I was wondering why my code isn't working. I'm trying to retrieve all offers of a listing only.
CREATE DATABASE IF NOT EXISTS `assignment_db`;
USE `assignment_db`;
CREATE TABLE USER_LIST(
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
userName VARCHAR(50) NOT NULL,
email varchar(100) NOT NULL,
registeredDate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table listing_list(
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
itemName VARCHAR(50) NOT NULL,
itemDescription VARCHAR(254) NOT NULL,
price DECIMAL(4,2) NOT NULL,
fk_poster_id int references USER_LIST(id),
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table offer_list(
id int(6) Unsigned auto_increment Primary key,
offer int,
fk_listing_id int references listing_list(id),
fk_offeror_id int references user_list(id),
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
insert into user_list (userName, email) values ('John','johnnyboi#123.com');
insert into user_list (userName, email) values ('Tom','Tommyboi#123.com');
insert into listing_list (itemName,itemDescription, price) values ( 'Pen', 'A long delicate pen.',' 1.50 ');
insert into listing_list (itemName,itemDescription, price) values ( 'Pencil', 'A long delicate pencil.',' 0.50 ');
insert into offer_list (offer,fk_listing_id,fk_offeror_id) values ('200','2','3');
insert into offer_list (offer,fk_listing_id,fk_offeror_id) values ('200','1','1');
select * from listing_list
inner join offer_list on listing_list.fk_listing_id = offer_list.id;
Any ideas on how to resolve this?
If I've understood you correctly, you want something like this (see fiddle here). Note that I changed some of the numbers to make it easier to follow the flow of the query:
insert into user_list (id, userName, email) values (10, 'John','johnnyboi#123.com');
insert into user_list (id, userName, email) values (20, 'Tom','Tommyboi#123.com');
and
insert into listing_list (itemName,itemDescription, price, fk_poster_id)
values ( 'Pen', 'A long delicate pen.',' 1.50 ', 10);
insert into listing_list (itemName,itemDescription, price, fk_poster_id)
values ( 'Pencil', 'A long delicate pencil.',' 0.50 ', 20);
and
insert into offer_list (offer,fk_listing_id,fk_offeror_id)
values ('200','1', 10);
insert into offer_list (offer,fk_listing_id,fk_offeror_id)
values ('200','2', 20);
Then I ran the query:
SELECT
u.id,
u.username,
u.email,
l.id,
l.itemName,
l.itemDescription,l.price,
l.fk_poster_id,
l.created_at,
o.offer,
o.fk_listing_id
FROM user_list u
JOIN listing_list l ON u.id = l.fk_poster_id
JOIN offer_list o ON u.id = o.fk_offeror_id;
Result:
id username email id itemName itemDescription price fk_poster_id created_at offer fk_listing_id
10 John johnnyboi#123.com 1 Pen A long delicate pen. 1.50 10 2019-12-23 11:21:10 200 1
20 Tom Tommyboi#123.com 2 Pencil A long delicate pencil. 0.50 20 2019-12-23 11:21:10 200 2
Some of the result fields are redundant - I left them in so that you could see the reasoning. Can I recommend that in future a) you don't bother with backticks for MySQL anymore - they are no longer required and are a pain to type. Also, when dealing with numberic values - even though MySQL (weirdly) supports this, that you do not put numbers in single quotes - it makes the SQL more difficult to read using many SQL formatting tools.
select * from listing_list inner join offer_list on listing_list.id = offer_list.fk_listing_id
You have taken the wrong table names.
For more details, check https://www.w3schools.com/sql/sql_join_inner.asp
The basic syntax for inner join:
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name;
If you want to select the data only form 1 listing, you can do it
like:
SELECT
*
FROM
listing_list
INNER JOIN offer_list ON listing_list.id = offer_list.fk_listing_id
WHERE
listing_list.id = 1

What is the SQL query for finding the name of manager who supervises maximum number of employees?

person_id | manager_id | name |
| | |
-------------------------------
Query to find name of manager who supervises maximum number of employees?
Added: This is the only table. Yes self-referencing. DB is mysql. Recursive queries will also do.
This query returns the manager_id and manager_name of the manager with the maximal number of employees.
The trick is in the HAVING clause, which allows aggregates and counts over multiple rows.
SELECT manager_id,name, count(*)
FROM table
GROUP BY manager_id, name
HAVING max(count(*));
You can read more in the short but informative w3schools.com HAVING clause tutorial.
If the manager_id references a person id in the same table, Svinto's answer might be more suitable.
SELECT name
FROM table
WHERE person_id = (
SELECT manager_id
FROM table
GROUP BY manager_id
HAVING max(count(*)))
It's not entirely clear to me what you want, so if this isn't what you want please clarify your question.
This query returns just one of the managers if there is a tie:
SELECT T2.name FROM (
SELECT manager_id
FROM table1
WHERE manager_id IS NOT NULL
GROUP BY manager_id
ORDER BY count(*) DESC
LIMIT 1
) AS T1
JOIN table1 AS T2
ON T1.manager_id = T2.person_id
Result of query:
Bar
Here's a query that fetches all managers with the tied maximum count in the case that there is a tie:
SELECT name FROM (
SELECT manager_id, COUNT(*) AS C
FROM person
WHERE manager_id IS NOT NULL
GROUP BY manager_id) AS Counts
JOIN (
SELECT COUNT(*) AS C
FROM person
WHERE manager_id IS NOT NULL
GROUP BY manager_id
ORDER BY COUNT(*) DESC
LIMIT 1
) AS MaxCount
ON Counts.C = MaxCount.C
JOIN person
ON Counts.manager_id = person.person_id
Result of the second query:
Foo
Bar
Here's my test data:
CREATE TABLE Table1 (person_id int NOT NULL, manager_id nvarchar(100) NULL, name nvarchar(100) NOT NULL);
INSERT INTO Table1 (person_id, manager_id, name) VALUES
(1, NULL, 'Foo'),
(2, '1', 'Bar'),
(3, '1', 'Baz'),
(4, '2', 'Qux'),
(5, '2', 'Quux'),
(6, '3', 'Corge');
Assuming manager_id have a reference to person_id and name of table: table_name
SELECT name FROM (
SELECT manager_id
FROM table_name
GROUP BY manager_id
ORDER BY COUNT(*) DESC
LIMIT 1
) t
INNER JOIN table_name ON t.manager_id = table_name.person_id
edit:
Removed HAVING MAX COUNT, added ORDER BY COUNT DESC LIMIT 1 in subquery