This problem consists of a database system relating components to their suppliers with corresponding costs, which are used to build widget assemblies.
Here is the database and tables:
CREATE DATABASE IF NOT EXISTS DB;
USE DB;
CREATE TABLE components (
c_id INT AUTO_INCREMENT NOT NULL,
name_c VARCHAR(255),
PRIMARY KEY (c_id)
);
CREATE TABLE suppliers (
s_id INT AUTO_INCREMENT NOT NULL,
name_s VARCHAR(255),
PRIMARY KEY (s_id)
);
CREATE TABLE widgets (
w_id INT AUTO_INCREMENT NOT NULL,
name_w VARCHAR(255),
PRIMARY KEY (w_id)
);
CREATE TABLE assemblies (
w_id INT,
c_id INT,
FOREIGN KEY (w_id)
REFERENCES widgets (w_id),
FOREIGN KEY (c_id)
REFERENCES components (c_id)
);
CREATE TABLE prices (
p_id INT AUTO_INCREMENT NOT NULL,
s_id INT,
c_id INT,
cost INT,
PRIMARY KEY (p_id),
FOREIGN KEY (s_id)
REFERENCES suppliers (s_id),
FOREIGN KEY (c_id)
REFERENCES components (c_id)
);
insert into components(name_c)
values('C1');
insert into components(name_c)
values('C2');
insert into components(name_c)
values('C3');
insert into components(name_c)
values('C4');
insert into components(name_c)
values('C5');
insert into components(name_c)
values('C6');
insert into suppliers(name_s)
values('S1');
insert into suppliers(name_s)
values('S2');
insert into suppliers(name_s)
values('S3');
insert into suppliers(name_s)
values('S4');
insert into suppliers(name_s)
values('S5');
insert into widgets(name_w)
values('A1');
insert into widgets(name_w)
values('A2');
insert into widgets(name_w)
values('A3');
insert into widgets(name_w)
values('A4');
insert into assemblies(w_id, c_id)
values(1,1);
insert into assemblies(w_id, c_id)
values(2,2);
insert into assemblies(w_id, c_id)
values(2,3);
insert into assemblies(w_id, c_id)
values(3,4);
insert into assemblies(w_id, c_id)
values(3,5);
insert into assemblies(w_id, c_id)
values(4,6);
insert into assemblies(w_id, c_id)
values(4,3);
insert into prices(s_id, c_id, cost)
values(1,1,121);
insert into prices(s_id, c_id, cost)
values(1,2,135);
insert into prices(s_id, c_id, cost)
values(2,2,94);
insert into prices(s_id, c_id, cost)
values(2,3,155);
insert into prices(s_id, c_id, cost)
values(3,3,178);
insert into prices(s_id, c_id, cost)
values(3,4,199);
insert into prices(s_id, c_id, cost)
values(4,4,122);
insert into prices(s_id, c_id, cost)
values(4,5,155);
insert into prices(s_id, c_id, cost)
values(5,5,133);
insert into prices(s_id, c_id, cost)
values(5,6,184);
The resulting tables are as follows:
components
c_id | name_c
1 C1
2 C2
3 C3
4 C4
5 C5
6 C6
(Note: tables components, suppliers, and widgets all defined analogously such that widgets with 1-A1, 2-A2, etc. and suppliers with 1-S1, 2-S2, etc.)
prices - list of supplier-component cost combinations
p_id s_id c_id cost
1 1 1 121
2 1 2 135
3 2 2 94
4 2 3 155
5 3 3 178
6 3 4 199
7 4 4 122
8 4 5 155
9 5 5 133
10 5 6 184
assemblies - list of components used to build the widget assemblies
w_id | c_id
1 1
2 2
2 3
3 4
3 5
4 6
4 3
For the first part, with help I was able to determine the correct query to find the minimum-cost outputs with respect to assemblies as follows (objective was to determine the minimum-cost components to build each widget assembly):
select w.name_w, sum(price_min.min_cost) as min_cost
from widgets as w
left join assemblies as a on a.w_id = w.w_id
left join (select c_id, min(cost) as min_cost from prices group by c_id) as price_min on price_min.c_id = a.c_id
group by w.name_w
order by w.w_id
Output:
name_w min_cost
A1 121
A2 249
A3 255
A4 339
However, I'm stuck trying to figure out how to determine which suppliers (name_s) are not used in this cost optimization (i.e., did not provide a competitive component price to be used in the corresponding widget-assembly build incorporating those suppliers' components). Working out on paper, I expect the following result:
name_s
S3
But I can't seem to get this result using SQL (specifically MySQL)...
Thanks in advance!
Modified from the query for finding the minimum cost:
select distinct s.name_s
from suppliers s
left join
prices p
on s.s_id = p.s_id
where p.s_id not in (
select distinct s_id from prices p1 -- suppliers of low cost components
inner join
(select a.c_id, price_min.min_cost
from widgets as w
left join assemblies as a on a.w_id = w.w_id
left join (select c_id, min(cost) as min_cost from prices group by c_id) as price_min
on price_min.c_id = a.c_id ) t -- component price details before sum()
on p1.cost = t.min_cost and
p1.c_id = t.c_id )
Related
-- create
CREATE TABLE employee
(
emp_id INTEGER,
job_code TEXT,
cnt_check int
);
-- insert
INSERT INTO employee(emp_id,job_code) VALUES (0001, 'JC001');
INSERT INTO employee(emp_id,job_code) VALUES (0001, 'JC001');
INSERT INTO employee(emp_id,job_code) VALUES (0002, 'JC002');
INSERT INTO employee(emp_id,job_code) VALUES (0002, 'JC002');
INSERT INTO employee(emp_id,job_code) VALUES (0003, 'JC003');
INSERT INTO employee(emp_id,job_code) VALUES (0004, 'JC004');
INSERT INTO employee(emp_id,job_code) VALUES (0004, 'JC004');
INSERT INTO employee(emp_id,job_code) VALUES (0004, 'JC004');
Expected Output:
emp_id job_code cnt_check
--------------------------------
0001 JC001 1
0001 JC001 2
0002 JC002 1
0002 JC002 2
0003 JC003 1
0004 JC004 1
0004 JC004 2
0004 JC004 3
My try:
update employee t1
join
(
select emp_id ,job_code ,row_number() over(partition by emp_id ,job_code ) rnk
from employee
) t2
on t1.emp_id = t2.emp_id and t1.job_code = t2.job_code
set t1.cnt_check = t2.rnk;
But all records getting updated with value 1.
Demo link
Using the exact columns in your sample data, we can try:
SELECT emp_id, job_code,
ROW_NUMBER() OVER (PARTITION BY emp_id ORDER BY emp_id) AS cnt_check
FROM employee
ORDER BY 1, 3;
Note that I suggest not doing this update, as every time your data changes you might have to run the update again.
You may use generation which uses BEFORE INSERT trigger and additional table:
CREATE TABLE autoinc_helper (
emp_id INT,
cnt_check INT AUTO_INCREMENT,
PRIMARY KEY (emp_id, cnt_check)
) ENGINE = MyISAM;
CREATE TRIGGER generate_autoinc
BEFORE INSERT ON employee
FOR EACH ROW
BEGIN
DECLARE autoinc INT;
INSERT INTO autoinc_helper (emp_id) VALUES (NEW.emp_id);
SET autoinc = LAST_INSERT_ID();
SET NEW.cnt_check = autoinc;
DELETE FROM autoinc_helper WHERE emp_id = NEW.emp_id AND cnt_check < autoinc;
END
DEMO fiddle
Course Table
course_id
course_name
1
s001
2
s002
3
s003
4
s004
Prerequisite Table
course_id
prerequisite_course_id
3
2
4
1
My question is to print both the Names of the course and the Prerequisite Course Name.
Example:
course_name
prerequisite_course_name
s003
s002
s004
s001
You can simply use inner join for that:
Schema and insert statements:
create table course(course_id int, course_name varchar(10));
insert into course values(1, 's001');
insert into course values(2, 's002');
insert into course values(3, 's003');
insert into course values(4, 's004');
create table Prerequisite(course_id int, prerequisite_course_id int);
insert into Prerequisite values(3, 2);
insert into Prerequisite values(4, 1);
Query:
select c.course_name, pc.course_name
from Course c inner join Prerequisite p
on c.course_id=p.course_id
inner join Course pc
on p.prerequisite_course_id=pc.course_id
Output:
course_name
course_name
s004
s001
s003
s002
db<>fiddle here
your data
drop
table if exists tmp_CourseTable;
create table tmp_CourseTable (
course_id int NOT NULL,
course_name VARCHAR(40) NOT NULL
);
INSERT INTO tmp_CourseTable(course_id, course_name)
VALUES
(1, 's001'),
(2, 's002'),
(3, 's003'),
(4, 's004');
drop
table if exists tmp_PrerequisiteTable;
create table tmp_PrerequisiteTable (
course_id INTEGER NOT NULL ,
prerequisite_course_id INTEGER NOT NULL
);
INSERT INTO tmp_PrerequisiteTable(
course_id, prerequisite_course_id
)
VALUES
(3, 2),
(4, 1);
you should join Prerequisite Table with Course Table twice
select
a.course_name,
b.course_name
from
tmp_PrerequisiteTable p
join tmp_CourseTable a on p.course_id = a.course_id
join tmp_CourseTable b on p.course_id = b.course_id
I need to run a script in order to fix some rows from my table company_menu.
However, I can't build this query to get these registers.
I build the schema in this link: http://sqlfiddle.com/#!9/5ab86b
Below I show the expected result.
companies
id
name
1
company 1
2
company 2
3
company 3
menu_items
id
name
1
home
2
charts
3
users
4
projects
company_menu
id
company_id
menu_item_id
1
1
1
2
1
2
3
1
3
4
1
4
5
2
1
6
2
3
This is a result that I expected:
id
company_id
menu_item_id
1
2
2
2
2
4
3
3
1
4
3
2
5
3
3
6
3
4
CREATE TABLE companies(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
CREATE TABLE menu_items(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
CREATE TABLE company_menu(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
company_id INT,
menu_item_id INT,
FOREIGN KEY(company_id) REFERENCES companies(id),
FOREIGN KEY(menu_item_id) REFERENCES menu_items(id)
);
INSERT INTO companies (name) VALUES ("Company 1"),("Company 2"),("Company 3");
INSERT INTO menu_items (name) VALUES ("home"),("charts"),("users"),("projects");
INSERT INTO company_menu (company_id, menu_item_id) VALUES (1, 1),(1, 2),(1,3),(1,4);
INSERT INTO company_menu (company_id, menu_item_id) VALUES (2, 1),(2,3);
Two ways I can think of. Don't know which is more efficient. Both start with a full compannies-menu_items join to get all possible combinations, and then cut out the existing:
WHERE NOT EXISTS
select c.id company_id, m.id menu_item_id
from companies c
join menu_items m
where not exists (
select * from company_menu where company_id = c.id and menu_item_id = m.id
);
LEFT JOIN + IS NULL:
select c.id company_id, m.id menu_item_id
from companies c
join menu_items m
left join company_menu cm on cm.company_id = c.id and cm.menu_item_id = m.id
where cm.id is null;
Both are sortable on any company or menu_item column.
http://sqlfiddle.com/#!9/5ab86b/11
I am somehow new to SQL, and I have a Election Application. I have done 80% of it and now stuck at counting votes from 2 or more Columns.
Example Table:
|**Senator_1** | **Senator_2** | **Senator_3**|
----------------------------------------------
George | Carl | Anthony
Carl | Tony | Stark
Anthony | George | Tony
Anthony | George | Stark
I would like to have this kind of result.
|**Candidate_Name** | **Vote_Count**|
-------------------------------------
George | 3
Anthony | 3
Carl | 2
Stark | 2
Tony | 2
I really don't have any idea of what query I am going to use. Any ideas of solving this?
By the way, for the confusion and all the arguments that started here, I am going to explain:
I wanted to be straight to my problem that's why I just posted a sample table. I have a table for the Voters, Candidates and the Votes. All tables have its ID and such, so I'm pretty sure it's normalized.
The main issue that you have is your table is not normalized. I would strongly advise that you fix your current table structure. A possible new table structure would be:
/* Table for unique voters */
CREATE TABLE voters (
id INT UNSIGNED NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL
) ENGINE=InnoDB;
/* Table for unique candidates */
CREATE TABLE candidates (
id INT UNSIGNED NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL
) ENGINE=InnoDB;
/* Many-to-many table storing votes by voters for candidates */
CREATE TABLE votes (
voter_id INT UNSIGNED NOT NULL,
candidate_id INT UNSIGNED NOT NULL,
PRIMARY KEY (voter_id, candidate_id),
CONSTRAINT FOREIGN KEY (voter_id) REFERENCES voters (id),
CONSTRAINT FOREIGN KEY (candidate_id) REFERENCES candidates (id)
) ENGINE=InnoDB;
/* Populate data */
INSERT INTO voters (name)
VALUES ('Voter 1'), ('Voter 2'), ('Voter 3'), ('Voter 4');
INSERT INTO candidates (name)
VALUES ('George'), ('Carl'), ('Anthony'), ('Tony'), ('Stark');
INSERT INTO votes (voter_id, candidate_id)
VALUES (1,1), (1,2), (1,3),
(2,2), (2,4), (2,5),
(3,3), (3,1), (3,4),
(4,3), (4,1), (4,5);
Then you could easily get a result by joining the two tables:
/* query showing all voters and the candidates they voted for */
SELECT voters.name, candidates.name
FROM votes
INNER JOIN voters on votes.voter_id = voters.id
INNER JOIN candidates ON votes.candidate_id = candidates.id;
/* Finally, a query showing votes per candidate */
SELECT candidates.name, COUNT(*) AS votes
FROM votes
INNER JOIN candidates ON votes.candidate_id = candidates.id
GROUP BY candidates.id;
See SQL Fiddle with Demo
However, if you cannot alter the design of the table, then you can get the result by unpivoting the data that you have in multiple columns. You can use a UNION ALL to unpivot the multiple columns into rows to get the count:
select name, count(*) TotalVotes
from
(
select senator_1 name
from yt
union all
select senator_2 name
from yt
union all
select senator_3 name
from yt
) d
group by name
order by totalVotes desc;
See SQL Fiddle with Demo
I think you are looking to count the total no. of occurrence of each name in different columns. Based on this, I think something like below might help -
select senator, sum(cnt) as 'count' from (
select senator_1 as 'senator', count(1) 'cnt' from election_table group by senator_1
union all
select senator_2 as 'senator', count(1) 'cnt' from election_table group by senator_2
union all
select senator_3 as 'senator', count(1) 'cnt' from election_table group by senator_3
) x group by x.senator
I have the following tables.
Industry(id, name)
Movie(id, name, industry_id) [Industry has many movies]
Trailer(id, name, movie_id) [Movie has many trailers]
I need to find 6 latest trailers for each Industry. Every movie does not need to have a trailer or can have multiple[0-n].
CREATE TABLE industry(id int, name char(10), PRIMARY KEY (id));
CREATE TABLE movie(id int, name char(10), industry_id int, PRIMARY KEY (id),
FOREIGN KEY (industry_id) REFERENCES industry(id));
CREATE TABLE trailer(id int, name char(10), movie_id int, PRIMARY KEY (id),
FOREIGN KEY (movie_id) REFERENCES movie(id));
INSERT INTO industry VALUES (1, "sandalwood");
INSERT INTO industry VALUES (2, "kollywood");
INSERT INTO movie VALUES (1, "lakshmi", 1);
INSERT INTO movie VALUES (2, "saarathi", 2);
INSERT INTO trailer VALUES (1, "lakshmi1", 1);
INSERT INTO trailer VALUES (2, "lakshmi2", 1);
INSERT INTO trailer VALUES (3, "lakshmi3", 1);
INSERT INTO trailer VALUES (4, "lakshmi4", 1);
INSERT INTO trailer VALUES (5, "lakshmi5", 1);
INSERT INTO trailer VALUES (6, "lakshmi6", 1);
INSERT INTO trailer VALUES (7, "saarathi4", 2);
INSERT INTO trailer VALUES (8, "saarathi5", 2);
INSERT INTO trailer VALUES (9, "saarathi6", 2);
SELECT c.*
FROM industry a
LEFT JOIN movie b
ON a.id = b.industry_id
LEFT JOIN trailer c
ON b.id = c.movie_id
LIMIT 0, 6
| ID | NAME | MOVIE_ID |
----------------------------
| 1 | lakshmi1 | 1 |
| 2 | lakshmi2 | 1 |
| 3 | lakshmi3 | 1 |
| 4 | lakshmi4 | 1 |
| 5 | lakshmi5 | 1 |
| 6 | lakshmi6 | 1 |
I need to fetch only one recent trailer from each movie. But I am getting all trailers for each movie. Please suggest me to get the SQL statement.
I'm not sure if this works in MySql or not because I can't remember if you can have subqueries inside of an in clause, but you might try:
select * from trailer
where id in (select max(id) from trailer group by movie_id)
Whether it works or not, it looks like you're not using the industry table in your query so there's not much point in joining to it (unless you are actually trying to exclude movies that don't have any industry assigned to them... but based on your sample I it doesn't look like that was your intention).
If the above query doesn't work in MySql, then try this one
select t.*
from trailer t join
(select max(id) id from trailer group by movie_id) t2 on t1.id = t2.id
To get recent trailor you should include date field column from which we can fetch it
If you must do this all in SQL (and not in whatever backend or code you are using, which I would actually recommend) then you are probably going to have to rely on some variable magic.
Essentially, you need to "rank" each trailer by the date and then "partition" it by the movie that the trailer belongs to. These words have actual meaning in some other flavors of SQL (such as PL/SQL) but unfortunately don't have native functionality in MySQL.
You're going to want do to something similar to what is mentioned in this SO post. Once you get the "ranks" in there partitioned by movie_id, you just select WHERE rank < 6. The query could get pretty messy and there is some risk in using variables in that way but from what I can tell this is the best way to do it strictly with a MySQL query
Try this query
SELECT * FROM industry
LEFT JOIN movie on movie.industry_id = industry.id
LEFT JOIN (
SELECT
id as T_ID,
name as T_Name,
movie_id
FROM trailer
INNER JOIN ( SELECT
MAX(id) as TID
FROM trailer
GROUP BY movie_id
) as t on t.TID = trailer.id
) as c on c.movie_id = movie.id;
Here is the Demo
SELECT i.name, m.name, MAX(t.id) AS 'Latest Trailer ID', MAX(t.name) AS 'Latest Trailer'
FROM industry i
INNER JOIN movie m ON(i.id = m.industry_id)
INNER JOIN trailer t ON(m.id = movie_id)
GROUP BY m.id
If you want latest trailer by id of trailer table then use below query:
SELECT * FROM trailer t
INNER JOIN (SELECT movie_id, MAX(id) id
FROM trailer GROUP BY movie_id) AS A ON t.id = A.id
OR If you want data latest by date then use this query:
SELECT * FROM trailer t
INNER JOIN (SELECT movie_id, MAX(latestbydate) latestbydate
FROM trailer GROUP BY movie_id
) AS A ON t.movie_id = A.movie_id AND t.latestbydate = A.latestbydate