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;
Related
Think this is probably fairly simple but cannot find the correct search terms, so if this is duplicated then great cause im sure there will be an answer somewhere.
I have the following tables setup
CREATE TABLE IF NOT EXISTS `customer` (
`id` int(6) unsigned auto_increment NOT NULL,
`name` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `billing_run` (
`id` int(6) unsigned auto_increment NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `invoice` (
`id` int(6) unsigned auto_increment NOT NULL,
`billing_run_id` int(6) unsigned NOT NULL,
`customer_id` int(6) unsigned NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (billing_run_id) REFERENCES billing_run(id),
FOREIGN KEY (customer_id) REFERENCES customer(id)
) DEFAULT CHARSET=utf8;
with the following data
insert into customer (name) values ('test customer');
insert into billing_run (date) values ('2019-01-01 12:00:00');
insert into billing_run (date) values ('2019-02-01 12:00:00');
insert into billing_run (date) values ('2019-03-01 12:00:00');
insert into invoice (customer_id,billing_run_id) values (1,1);
SQLFiddle here -> http://sqlfiddle.com/#!9/a54162/5
And i want to get the customer records that do not have an invoice related to billing_run with id of 2
My query
select c.id from customer c
left join invoice i on i.customer_id = c.id
left join billing_run br on br.id = i.billing_run_id and br.id = 2
where i.id is null
returns 0 records. Why ?
First you join the table customer (1 row) with the table invoice (1 row).
This join will return 1 row because there is a match between the columns in the ON clause:
on i.customer_id = c.id
(both i.customer_id and c.id have the value 1 in your sample data).
So there is not any row with i.id is null.
The next join to the table billing_run does not affect the first 2 joined tables.
So the condition:
where i.id is null
returns no rows.
The correct condition (which you had in the original fiddle) is:
where br.id is null
because the join to the table billing_run will return a non matching row for the condition:
on br.id = i.billing_run_id and br.id = 2
because there is no i.billing_run_id = 2 in invoice.
You will want to do an exclusive where clause this will return the 1 row that you want.
select * from customer c
where c.id not in (Select customer_id from invoice i LEFT JOIN billing_run br on
i.billing_run_id=br.id WHERE br.id=2 and br.id is not null)
http://sqlfiddle.com/#!9/a54162/14
You don't need the billing_run table. So I think you intend:
select c.id
from customer c left join
invoice i
on i.customer_id = c.id and i.billing_run_id = 2
where i.id is null
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.
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
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).
I have the following table structure:
CREATE TABLE a (
a_id int(10) unsigned NOT NULL AUTO_INCREMENT,
);
CREATE TABLE b {
b_id int(10) unsigned NOT NULL AUTO_INCREMENT,
};
CREATE TABLE cross (
a_id int(10) unsigned NOT NULL,
b_id int(10) unsigned NOT NULL,
PRIMARY KEY (a_id),
KEY (b_id),
CONSTRAINT FOREIGN KEY (a_id) REFERENCES a (a_id),
CONSTRAINT FOREIGN KEY (b_id) REFERENCES b (b_id)
);
CREATE TABLE prices (
a_id int(10) unsigned NOT NULL,
price int(10) NOT NULL,
PRIMARY KEY (a_id),
CONSTRAINT FOREIGN KEY (a_id) REFERENCES a (a_id)
);
I would like to retrieve every b_id value for which there are inconsistent prices. A b.id value 'B' has an inconsistent price if the following conditions both hold:
There exist two a_id values (say, 'A1' and 'A2') such that table cross contains both ('A1', 'B') and ('A2', 'B'). (For any b_id value, there may be zero or more rows in cross.)
Either 'A1' and 'A2' correspond to rows of prices that have different values of price, or else exactly one of 'A1' and 'A2' corresponds to an entry in prices.
Because of restrictions by the hosting provider, I cannot use stored procedures with this data base. I haven't figured out a sensible way to do this with SQL queries. So far, I've resorted to retrieving all relevant data and scanning for inconsistencies in Perl. That's a lot of data retrieval. Is there a better way? (I'm using InnoDB, if it makes a difference.)
/* Condition 1 and Condition 2a */
SELECT
c.b_id
FROM
`cross` AS c
JOIN prices AS p ON (p.a_id = c.a_id)
GROUP BY
c.b_id
HAVING
COUNT(c.a_id) > 1 AND
MAX(p.price) != MIN(p.price)
UNION
/* Condition 1 and Condition 2b */
SELECT
c.b_id
FROM
`cross` AS c
LEFT JOIN prices AS p ON (p.a_id = c.a_id)
GROUP BY
c.b_id
HAVING
COUNT(c.a_id) > 1 AND
SUM(IF(p.price IS NULL, 0 ,1)) = 1;