Retrieve rows with more than 2 relations in another table - mysql

I have two tables, table_a and table_b. table_a has the following schema :
CREATE TABLE table_a (
a_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
a VARCHAR(255) NOT NULL UNIQUE,
b_id INT(11)
);
and table_b :
CREATE TABLE table_b (
b_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
b VARCHAR(255) NOT NULL UNIQUE
);
Each element in table_a refers (in table_a.b_id) to one element of table_b.
I want a query that would output every element of table_b for which there are 2 elements or more referencing to it in table_a (and for each row, I'd like it to display how many elements in table_a refer to it)
Thanks

Try this query:
SELECT b.b_id, b.b, t.b_count
FROM table_b b INNER JOIN
(
SELECT a.b_id, COUNT(*) AS b_count
FROM table_a a
GROUP BY a.b_id
HAVING COUNT(*) > 1
) t
ON b.b_id = t.b_id
This avoids a single GROUP BY query which would contain ambiguous columns (and therefore would not run on SQL Server and some other flavors).

Related

Query Slowness Between Two Tables

If there is a result matching the value of "parent_id" in my "table1" and "table2" tables, I want to get the number of rows in the "table1" table.
But the SQL query takes too long.
There are 100 thousand rows in table1.
There are 40 thousand rows in table2.
A table data file for you to try
See: https://pastebin.pl/view/raw/ddf8c467
Table Structure
CREATE TABLE table1 (id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT ,
parent_id INT(11) UNSIGNED NOT NULL ,
tes1 INT(1) NOT NULL , PRIMARY KEY (id)) ENGINE = MyISAM;
CREATE TABLE table2 (id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT ,
parent_id INT(11) UNSIGNED NOT NULL ,
tes2 INT(1) NOT NULL , PRIMARY KEY (id)) ENGINE = MyISAM;
SQL Query I use
SELECT COUNT(A.id) AS total
FROM table1 A
LEFT JOIN table2 B ON A.parent_id = B.parent_id
WHERE B.id IS NOT NULL
create a index on parent_id on table B and use INNODB if possible.
you can also use inner join
SELECT COUNT(A.id) AS total
FROM table1 A
INNER JOIN table2 B ON A.parent_id = B.parent_id;

SQL Chaining joins

EDIT: The isssue was mismatching data the B-ids in tables A_B and B_C had no overlap
I have the following tables:
A(id, …)
A_B(a_id, b_id)
B_C(b_id, c_id)
C_D(c_id, d_id)
D(id, value, …)
Where I want some rows from A based on the value of the row in D.
The tables A_B, B_C and C_D are just id mappings from one table to another.
I was trying to get to something that would look something like this:
select * from A where D.value = "true"
I got this far:
select * from A
inner join A_B on A_B.a_id = A.id
inner join B_C on B_C.b_id = A_B.b_id
which is just an empty table.
I am starting to think that I am approaching this issue in the wrong way or perhaps have misunderstood how one should go about joining tables.
What you've got works OK if your data is coherent. Here's a version of your database and query which demonstrates that. For simplicity, I inferred the existence of tables b and c, and made the various columns in the X_Y style tables into foreign keys to the single-letter tables.
CREATE TABLE a
(
id INTEGER NOT NULL PRIMARY KEY,
info VARCHAR(20) NOT NULL
);
CREATE TABLE b
(
id INTEGER NOT NULL PRIMARY KEY,
data VARCHAR(20) NOT NULL
);
CREATE TABLE C
(
id INTEGER NOT NULL PRIMARY KEY,
extra VARCHAR(20) NOT NULL
);
CREATE TABLE d
(
id INTEGER NOT NULL PRIMARY KEY,
value VARCHAR(20) NOT NULL
);
CREATE TABLE a_b
(
a_id INTEGER NOT NULL REFERENCES a,
b_id INTEGER NOT NULL REFERENCES b,
PRIMARY KEY (a_id, b_id)
);
CREATE TABLE b_c
(
b_id INTEGER NOT NULL REFERENCES b,
c_id INTEGER NOT NULL REFERENCES C,
PRIMARY KEY(b_id, c_id)
);
CREATE TABLE c_d
(
c_id INTEGER NOT NULL REFERENCES C,
d_id INTEGER NOT NULL REFERENCES d,
PRIMARY KEY(c_id, d_id)
);
INSERT INTO a VALUES(1, "Quasimodo");
INSERT INTO b VALUES(20, "Quiet");
INSERT INTO C VALUES(333, "Contemporaneous");
INSERT INTO d VALUES(4444, "true");
INSERT INTO a_b VALUES(1, 20);
INSERT INTO b_c VALUES(20, 333);
INSERT INTO c_d VALUES(333, 4444);
SELECT *
FROM a
JOIN a_b ON a_b.a_id = a.id
JOIN b_c ON b_c.b_id = a_b.b_id
JOIN c_d ON c_d.c_id = b_c.c_id
JOIN d ON d.id = c_d.d_id
WHERE d.value = "true";
For the given data, that produces:
1 Quasimodo 1 20 20 333 333 4444 4444 true
So, if the data is correct, the query you were building can produce an answer. However, if you were getting an empty table on your incomplete query, then there is a data problem in your tables — or (outside chance) your outline schema misled us.
Testing performed on a Mac running macOS High Sierra 10.13.4, using Informix 12.10.FC6, but using what is believed to be a subset of SQL common to Informix and MySQL.

SQL find where two tables does not match (combined key)

I have the following two tables:
Table: user_has_academy_team
Columns:
user_id int(11) PK
academy_team_id int(11) PK
timestamp datetime
Table: user_has_academy_module
Columns:
id int(11) AI PK
user_id int(11)
module_id int(11)
academy_team_id int(11)
academy_id int(11)
sort_number int(11)
is_complete int(11)
score_to_pass int(11)
is_open int(11)
deadline datetime
module_version_id int(11)
waiting_approval int(11)
I wish to find all the records in the table user_has_academy_module where academy_team_id and user_id does not match in user_has_academy_team
You are looking for a NOT IN (or NOT EXISTS) clause: records from one table that have no match in another:
select *
from user_has_academy_module
where (user_id, academy_team_id) not in
(select user_id, academy_team_id from user_has_academy_team);
In a comment to another answer you say you want to delete those records from user_has_academy_module, which is about the same query, only with delete instead of select:
delete
from user_has_academy_module
where (user_id, academy_team_id) not in
(select user_id, academy_team_id from user_has_academy_team);
SELECT a.* FROM user_has_academy_team a
LEFT JOIN user_has_academy_module b
ON a.user_id = b.user_id AND a.academy_team_id = academy_team_id
WHERE b.user_id IS NULL or b.academy_team_id IS NULL
Should give you the result (I believe, since you haven't posted sample and expected). However I feel that your table structure leaves much to be desired. If you had a auto_increment primary key on your user user_has_academy_team table instead of the composite primary key, and referred that in your other table, life would be a lot easier.
Try this:
SELECT m.* FROM user_has_academy_module AS m
LEFT JOIN user_has_academy_team as t
ON m.user_id = t.user_id
AND m.academy_team_id = t.academy_team_id
WHERE t.user_id IS NULL
That's how it works: you try to join 2 tables on one ore more fields, when the fields of the second table are NULL you know that the tables don't match on those fields.

Insert into with multi select or multi conditions

I have a table that contains many informations:
CREATE TABLE sequences (
`id` INT(11) NOT NULL DEFAULT '0',
`name` TEXT NULL,enter code here
`nbrlsu` BIGINT(20) NULL DEFAULT NULL,
`nbrits` BIGINT(20) NULL DEFAULT NULL,
`nbrco1` BIGINT(20) NULL DEFAULT NULL,
`nbrrcbl` BIGINT(20) NULL DEFAULT NULL,
`nbrmatk` BIGINT(20) NULL DEFAULT NULL,
`nbrsequences` BIGINT(20) NULL DEFAULT NULL,
`parent_id` BIGINT(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
);
I want to create a table based on sum of columns in the first table
for exemple I want to know te number of elements that have the same parent_id and has numbersequences>0
and I want to know for each type of sequences the number of rows that contains information:
SELECT parent_id ,
Classification,count(id) as nbrspecies,
SUM(nbrsequences) ,
SUM(nbrco1),
SUM(nbrits),
SUM(nbrlsu),
SUM(nbrrcbl),
SUM(nbrmatk)
FROM dashboard_specimen
GROUP BY parent_id
and I have an other kind of queries:
SELECT parent_id ,
count(id) as co1
FROM dashboard_specimen
WHERE nbrco1>0
GROUP BY parent_id ;
and
SELECT parent_id ,
count(id) as nbrspecies
FROM dashboard_specimen
WHERE nbrsequences>0
GROUP BY parent_id
and other types like this
and my goal in the end is to insert this information into an other table with insert select
like this:
INSERT INTO bold_namestats (id,
name,
numberofstrains,
numberofsequences,
numberofco1,
numberofits,
numberoflsu,
numberofrbcl,
numberofmatk)
SELECT parent_id ,
Classification,
count(id) as nbrspecies,
SUM(nbrsequences) ,
SUM(nbrco1),
SUM(nbrits),
SUM(nbrlsu),
SUM(nbrrcbl),
SUM(nbrmatk)
FROM dashboard_specimen
GROUP BY parent_id
I don't know if there is a simple way to do this with temp tables or something like this
If I understand well, you could do a subquery for each column you want to populate, filtering each subquery for an id.
INSERT INTO bold_namestats (id,
name,
numberofstrains,
numberofsequences,
numberofco1,
numberofits,
numberoflsu,
numberofrbcl,
numberofmatk)
select parent_id, (*select1* where parent_id=...), (*select2* where parent_id=...), ... , (*selectn* where parent_id=...)
from dashboard_specimen
group by parent_id
where select1, select2, ... , selectn are the different queries you have.
Finally I have resolved my problem using join and temp tables
INSERT INTO bold_namestats (_id,numberofstrains, numberofsequences,numberofco1,numberofits,numberoflsu,numberofrbcl,numberofmatk,numberstrainswithco1,numberstrainswithseq)
SELECT a._id ,a.numberofstrains,a.numberofsequences ,a.numberofco1,a.numberofits,a.numberoflsu,a.numberofrbcl,a.numberofmatk,b.numberofstrainswithco1,c.numberofstrainswithseq FROM bold_temp_namestats a left join bold_strainswithco1 b on a._id=b.parent_id left join bold_strainswithseq c on a._id=c.parent_id union
SELECT a._id ,a.numberofstrains,a.numberofsequences ,a.numberofco1,a.numberofits,a.numberoflsu,a.numberofrbcl,a.numberofmatk,b.numberofstrainswithco1,c.numberofstrainswithseq FROM bold_temp_namestats a right join bold_strainswithco1 b on a._id=b.parent_id left join bold_strainswithseq c on a._id=c.parent_id ;
this query is used to replace full outer join so I fill 3 tables with data and after that I insert with joinin result with left and right join and union the result to get full lines in the end

double insert-select statement in mysql

I need to move data from one table into two tables.
for example
I have TableA with A,B,C,D,E fields (this is the old table), and TableX and TableY. TableX contains A,B and C fields and TableY contains D and E.
Currently I have a query that inserts the data into the first table but not in the second, something like
INSERT INTO TableX
(A,B,C)
SELECT A,B,C
FROM TableA
This works
The 3 tables contains their id's and in the new structure TableY must contain a reference with TableX, the complete fields of table would
complete fields of table would
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_toX` int(10) not NULL,
`D` varchar(45) DEFAULT NULL,
`E` varchar(45) DEFAULT NULL,
How insert the the reference of TableX in TableY of the same record of the TableA???
Alter TableA to contain a unique ID which you can insert into both of the new tables. Use this column to create whatever references you wish, then remove this column if it is no longer needed with another ALTER TABLE.
try:
INSERT INTO TableY (id_toX, D, E)
SELECT DISTINCT t2.id, t1.D, t1.E
FROM TableA as t1
inner join
TableX as t2
on (t1.A=t2.A and t1.B=t2.B and t1.C=t2.C)