select distinct and where in so slow - mysql

table1
row_id row_one row_two
1 1 5
2 1 5
3 2 5
4 2 5
5 2 6
table2
row2_id row2_one row2_two
1 1 somevalue
2 2 somevalue2
"select distinct row_one from table1 where row_two=5"
result
row_one
1
2
after that i want select
select * from table2 where row2_one=1
select * from table2 where row2_one=2
i want select with one query.
i am trying this query
select * from table2 where row2_one in (select distinct row_one from table1 where
row_two where row_two=5)
but it took 8s
Showing rows 0 - 14 ( 15 total, Query took 8.3255 sec)
why is it so slow. i want select faster.
please help me!

You don't need the DISTINCT in there. You can just do:
SELECT *
FROM table2
WHERE row2_one IN (SELECT row_one FROM table1 WHERE row_two=5)
And using EXISTS might be faster:
SELECT *
FROM table2 A
WHERE EXISTS (SELECT * FROM table1 WHERE row_two=5 AND row_one = A.row2_one)

Let me add to the that was said bellow - use GROUP BY or EXISTS instead of DISTINCT it can really improve your performance.

Assuming that this is your query:
select *
from table2 where row2_one in (select distinct row_one from table1 where row_two=5)
Then this is well-formed. One thing, you don't need the distinct in the subquery.
If you add an index to the table1 on the column row_two, you should get better performance. An index on row2_one in table2 would also speed it up.

Select distinct table2.*
from table1 t1, table2 t2
where t1.row_two =5 and t1.row2_one = t2.row2_one

Related

MySql: How to select rows where all values are the same?

I have a table like this:
name |id | state
name1 12 4
name1 12 4
name2 33 3
name2 33 4
...
I want to select every name and id from table where state is only 4, that means name1 is correct, because it only has two records with state 4 and nothing more. Meanwhile name2 is wrong, because it has record with state 4 and record with state 3.
You can use aggregation as shown below:
SELECT name, id
FROM your_table
GROUP BY name, id
HAVING SUM(state<>4)=0;
See a Demo on SQL Fiddle.
select name, id from mytable where id not in
(select distinct id from mytable where state <> 4)
you might need 2 sub queries .
select with group by name were state 4
select with group by name
compare the count if the count is same then select it
example : select name , count (name) from table where state = 4 as T1
select name , count (name) from table as T2
select T1.name from T1 and T2 where T2.count = T1.count
You can use not exists like this:
select distinct name, id
from table1 a
where not exists (select *
from table1 b
where a.id=b.id and state<>4)
In a more general case you can use count distinct (with not exists or with a join):
select distinct name, id
from table1 a
where not exists (
select *
from table1 b
where a.id=b.id
group by id
HAVING count(distinct state)>1)

Mysql union select error

I am trying to display all records from table1 even if the catid not existing in table2 (all employee in table2 should have all catid from table1 with 0 days if not exising in table2) with the following sql query but getting an error
Error Code: 1054. Unknown column 'catid' in 'group statement'
select empid,days from table2 union select catid from
table1 group by empid, catid;
table1:
catid
1
2
3
table2:
empid catid days (computed column count(*))
1000 1 8
1000 3 10
expected result:
empid catid days
1000 1 8
1000 2 0 <---catid 2 and days 0 if catid not existing in table2 for empid 1000
1000 3 10
That is not the function of the union statement. Union statement does a set like capability which merging two sets. What you are looking for a is a join with the table 1 where you do a count and group by catid. Your data model to achieve this output itself is grievously wrong ;)
select employeeid, catid, sum(days) from table1, table2 group by employeeid, catid;
You just need a LEFT JOIN:
Select tab2.empid, tab2.catid, ifnull(tab2.days, 0)
from tab2
left join tab1 on tab2.catid = tab1.catid
Please note : While doing a UNION the number and type of the columns present in the first select should be the same as the next Selects.
So you need to first make the select columns in sync first.
can you check this and add empid similarly.
SELECT TABLE1.CATID, IFNULL(TABLE2.DAYS,0) FROM table1 LEFT OUTER JOIN
table2 ON table1.catid = table2.catid
Please use LEFT JOIN with IFNULL.
Select table2.empid, table1.catid, IFNULL(table2.days, 0) from table2
LEFT JOIN table1 ON table2.catid = table1.catid;

MySQL select from custom set and compare with table data

Hi I'm trying to solve which elements doesn't exists in my database. In order to do so I want to compare list of integers (output from external script) with data in table. How to do such thing like:
SELECT * FROM (1,1,2,3,5,8,13...) l WHERE l NOT IN (select id from table1);
This is probably best done with a left outer join. But, your problem is creating the table of constants:
SELECT *
FROM (select 1 as id union all select 2 union all select 3 union all select 5 union all
select 8 union all select 13 union all select 21 . . .
) ids
where ids.id NOT IN (select id from table1);
This can have odd behavior, if table1.id is ever NULL. The following works more generally:
SELECT *
FROM (select 1 as id union all select 2 union all select 3 union all select 5 union all
select 8 union all select 13 union all select 21 . . .
) ids left outer join
table1 t1
on ids.id = t1.id
where t1.id is null;
EDIT:
The size of a MySQL query is dictated by the parameter max_packet_size (see here). The most recent version has a limit of 1 Gbyte. You should be able to fit 18,000 rows of:
select <n> union all
into that limit, quite easily. Gosh, I don't even think it would be 1 megabyte. I would say, though, that passing a list of 18,000 ids through the application seems inefficient. It would be nice if one database could just pull the data from the other database, without going through the application.
If your set to compare is huge I'd recommend you to create a temporary table myids with the only column id, put there all your 18K values and run query like that:
select id from myids where myids.id not in (select id from table1);

mysql query help in two table

I have two table table1 and table2
table1:
id amount
1 394
2 897
2 345
3 123
table2:
id amount
2 876
3 890
3 876
4 908
I need to generate table3. join two table and SUM id wise and show top 30 amount holder.
table3:
id amount
2 2118
3 1889
4 908
1 394
You can get data in followng way:
select table3.id, SUM (table3.amount) AS amount
FROM
(SELECT * FROM table1 UNION ALL SELECT * FROM table2) table3
GROUP BY table3.id
If you want to create table with above data, you can do like this:
CREATE TABLE new_table select table3.id, SUM (table3.amount) AS amount
FROM
(SELECT * FROM table1 UNION ALL SELECT * FROM table2) table3
GROUP BY table3.id ;
Try using this query
SELECT a.id, SUM(a.amount)
FROM (
SELECT * FROM table1
UNION
SELECT * FROM table2) AS a
GROUP BY a.id
ORDER BY SUM(a.amount)
LIMIT 30 DESC;
Above query will generate results, now to create new table use following
CREATE TABLE table3(
SELECT a.id, SUM(a.amount)
FROM (
SELECT * FROM table1
UNION
SELECT * FROM table2) AS a
GROUP BY a.id
ORDER BY SUM(a.amount)
LIMIT 30 DESC);
Hope this helps...

Join two tables in MySQL with random rows from the second

I have two tables
The first with only 5 rows
The second with 800 rows
I'm using this query:
SELECT *
FROM table1 t1
JOIN (SELECT * FROM table2 ORDER BY RAND() LIMIT 5) t2
But I'm getting 5 rows from the first table for each result of the second table.
I don't need a condition when joining, I just want 5 random results from the second table to join the 5 results from the first.
Example:
--------------------------------------------------------
|table1 (always with same order)| table2(random order) |
--------------------------------------------------------
item1 | item4
item2 | item2
item3 | item5
item4 | item1
item5 | item3
Do you mean UNION ?
SELECT * FROM table1
UNION SELECT * FROM table2 ORDER BY RAND() LIMIT 5;
Update: revised answer after modification of your question:
SELECT field1 FROM table1
UNION SELECT field2 FROM table2 ORDER BY RAND() LIMIT 5;
To my understanding, you just need one field from each table. If you need several ones, you can list them: field2, field2, ... as long as the number of fields is the same in both SELECTs.
Update 2: ok, I think I see what you mean now. Here is a (dirty) way to do it, I'm quite confident someone can come with a more elegant solution though:
SET #num1=0, #num2=0;
SELECT t1.field1, t2.field2
FROM (
SELECT field1, #num1:=#num1+1 AS num
FROM table1
) AS t1
INNER JOIN (
SELECT field2, #num2:=#num2+1 AS num
FROM (
SELECT field2
FROM table2
ORDER BY RAND()
LIMIT 5
) AS t
) AS t2
ON t1.num = t2.num;
Try use subquery in select. The subquery part pick an id for each row of table1.
SELECT
id AS table1_id,
(
SELECT id FROM table2 ORDER BY RAND() LIMIT 1
) AS table2_id
FROM table1
The query result would be like this:
table1_id
table2_id
1
24
2
13
3
36
4
68
5
5
You may join with table2 to select other table2 column:
SELECT table1.*, table2.*
FROM (
SELECT
id AS table1_id,
(
SELECT id FROM table2 ORDER BY RAND() LIMIT 1
) AS table2_id
FROM table1
) t
JOIN table1 on t.table1_id = table1.id
JOIN table2 on t.table2_id = table2.id