Compare large MySQL tables - mysql

I need to make a comparison between two (or more) tables with around 60.000 rows and about 60 columns.
In these tables there are two values on which I want to run a query. The purpose of the query is to count the rows which exists in TABLE_A but don't exist in TABLE_B based on two values in the row.
I've ran the following query:
SELECT id
FROM table_a ta
WHERE NOT EXISTS (
SELECT id
FROM table_b tb
WHERE ta.value1=tb.value1 AND ta.value2=tb.value2
)
As said, I've tried the code above and some variations on it. But to run this query it takes ages before it's finished. I hope to find a solution which runs in under 10 seconds.
Next query I tried, and of which I thought was working:
SELECT value1, value2
FROM (
SELECT ta.value1, ta.value2
FROM table_a ta
UNION ALL
SELECT tb.value1, tb.value2
FROM table_b tb
) result
GROUP BY value1, value2
HAVING COUNT(*) = 1
ORDER BY value1
The code shows me all differences between the two tables. So if valueX exists in TABLE_A but not in TABLE_B it's shown and vice versa.
So in short, I want to get all rows from TABLE_A which are not present in TABLE_B based on two values in the row.
Hope someone can help, thanks!

Why not use a join?
/* Create a table called NAMES */
CREATE TABLE NAMES(Id integer PRIMARY KEY, Name text, LastName text);
CREATE TABLE OTHERNAMES(Id integer PRIMARY KEY, Name text, LastName text);
/* Create few records in this table */
INSERT INTO NAMES VALUES(1,'Tom','Riddle');
INSERT INTO NAMES VALUES(2,'Lucy','I love');
INSERT INTO NAMES VALUES(3,'Frank','Frankly');
INSERT INTO NAMES VALUES(4,'Jane','Austen');
INSERT INTO NAMES VALUES(5,'Robert','Downey');
INSERT INTO OTHERNAMES VALUES(2,'Lucy','I love');
INSERT INTO OTHERNAMES VALUES(3,'Frank','Frankly');
INSERT INTO OTHERNAMES VALUES(4,'Jane','Austen');
INSERT INTO OTHERNAMES VALUES(5,'Robert','Downey');
select * from NAMES
LEFT JOIN OTHERNAMES on
NAMES.Name = OTHERNAMES.Name
AND Names.LastName = OTHERNAMES.LastName
where OTHERNAMES.id is null
See it online http://sqlfiddle.com/#!9/640c53/1
If you use a LEFT JOIN Items that don't exist in the right table will be replaced with null entries, which can be filtered with a where.
I don't know how efficient that is with your 60.000 database but this usually does the trick for me.

After some trial and error I have improved the second block of code. I noticed an additional field in my table which I could use to further filter the results.
SELECT date, value1, value2
FROM (
SELECT date, value1, value2
FROM (
SELECT ta.date, ta.value1, ta.value2
FROM table_1 ta
UNION ALL
SELECT tb.date, tb.value1, tb.value2
FROM table_2 tb
) filter
GROUP BY value1, value2
HAVING COUNT(*) = 1
) result
WHERE date='YYYY-MM-DD'
This code filters the results in under 4 seconds.
Anyway, thanks everyone for the trouble.

Related

Insert records for each selected record

I have two tables, Table1 contains a list of records with columns super_id, user_name and job_type
Table2 contains a 3 columns as well super_id, view and time
Using a select query with criteria on table I would like to create one record per super_id in Table2
Meaning if the select query was SELECT super_id FROM Table1 WHERE job_type = “Instructor”
RF34323 through RF34328 would appear would each be inserted once into Table2 where the View column is always View1 and time is the current date.
How can an Select Insert query like this written?
The following is an example of the 2 tables:
Is this what you want?
insert into table2 (super_id, `view`, `time`)
select super_id, 'view1', now()
from table1
where job_type = 'Instructor';
Note that view and time are very BAD choices for column names, because they are keywords in SQL.
If you want to create table2, then use create table table2 as instead of insert.
Also, you can default the time column to the insertion time, if you set up the table properly.

MySQL join doesn't return results even when it should

I have a seemingly straight forward problem. I'm matching a list of ids with another list of ids in a second table. The following queries execute fine and return a result:
select * from dataTable where id = 3888;
select * from moreIDs where mmid = 3888;
The join statement, however, returns no results.
select * from dataTable inner join moreIDs on dataTable.id = moreIDs.mmID;
Any idea why I'm not getting any results from the join?
As you've figured out int the comments, your issue is related with data types.
The following fiddle shows some tests: fiddle.
First, I've created three tables as the following:
CREATE TABLE table1 (id varchar(15));
CREATE TABLE table2 (id varchar(15));
CREATE TABLE table3 (id int);
And inserted some data:
INSERT INTO table1 values ('3888');
INSERT INTO table2 values (' 3888 '); -- extra spaces
INSERT INTO table3 values (3888);
If you query a varchar column comparing it with an int value, the varchar will be implicity cast to int and extra spaces will be removed. The following examples return 3888:
SELECT * FROM table1 WHERE id = 3888;
SELECT * FROM table2 WHERE id = 3888;
But if you try this match in a JOIN operation, you will be comparing varchar with varchar, so '3888' = ' 3888 ' will be evaluated as false.
To solve this, you may convert one of the columns to int (so cast will be used) or use the TRIM() function, like:
SELECT *
FROM table1
INNER JOIN table2
ON TRIM(table1.id) = TRIM(table2.id);
Note: If possible, convert both columns to int to get a SARGABLE query. The cast operation (varchar to int) in each row will have a performance impact if you use indexes.

mysql insert value if it doesn't exist

I'm trying to insert an ingredient to an ingredients table if it doesn't exist.
I'm using the following syntax:
INSERT INTO ingredient(Name)
(
SELECT 'ingName' FROM dummytable WHERE
(SELECT count(*) FROM ingredient WHERE Name = 'ingName')=0)
This does not seem to work (0 rows affected), even though the SELECT query seem to return the desired result (an entry which contains "ingName").
The "ingredient" table has 2 columns: Name, id (id is auto incremented)
Thanks,
Li
Its better to add unique index on the name column:
ALTER TABLE `ingredient` ADD UNIQUE(`Name`)
After doing that you can use INSERT IGNORE:
INSERT IGNORE INTO `ingredient` ... /* anything */
That's because your inner query SELECT count(*) FROM ingredient WHERE Name = 'ingName' is returning a value > 0 and hence the upper query SELECT 'ingName' FROM dummytable WHERE is not selecting any rows and so no insert is happening.
I tried the same with a test table having 2 column name|value and it did worked fine
INSERT INTO test1(name) (
SELECT 'name' FROM test2 WHERE
(
SELECT count(*) FROM test2 WHERE name = 'bilboa'
)
=0
)
Inserted 2 rows with value name cause that's what I am selecting in select query and my test table 2 rows.

How to insert multiple values in a table with an equal second cell

I have s MySQL database and I need to insert some specific data in a table. The data should be as follows:
SELECT id FROM a_table WHERE ... returns me a list of ids.
I need to insert n rows in second_table where n is the count of the returned rows from the first query. The second table requires 2 fields - The first one will be a record from the first query and the second one will be an integer, that I will pass from my script.
For example: If the first query returns (12,14,17,18) and the integer from my script is 5 I need to create a query, that will insert (12,5),(14,5),(17,5),(18,5) and I need this done in the database layer - I don't want to create a select statement, then create a query and then run it.
I need something like this (this is not a real query - It just shows what I need):
INSERT INTO second_table (user_id,group_id) VALUES ((12,14,17,18),5)
or to be more precise like this:
INSERT INTO second_table (user_id,group_id) VALUES ((SELECT id FROM a_table WHERE ...),5)
Is there a way to do this in SQL only (no tsql - sql only)
You can include a literal value in a SELECT:
INSERT INTO second_table (user_id, group_id)
SELECT id, 5
FROM a_table
WHERE ...
INSERT INTO
second_table
(
user_id
,group_id
)
SELECT
id
,5
FROM
first_table
WHERE
...
see the MySQL docs for more details on INSERT...SELECT syntax:
http://dev.mysql.com/doc/refman/5.1/en/insert-select.html
Hi you can try query given below
Insert into items select item_sold_qty , 5 from sales
INSERT INTO second_table
SELECT id , 5 FROM a_table WHERE ...
thanks

mysql - union with creating demarcated field

I need UNION two tables with creating new field, where 1 for first table, and 2 for second.
I tried
(
SELECT field, 1 AS tmp
FROM table1
)
UNION
(
SELECT field, 2 AS tmp
FROM table2
)
But in result, tmp field was full of "1".
How it can be implemented?
Your query should work fine. The only thing you should change is UNION should be UNION ALL to give better performance. Without the ALL it defaults to UNION DISTINCT which causes the rows to be compared for duplicates*, but the way you have constructed them guarantees that there cannot be duplicates so this extra check is a waste of time. Here is some test code I used to verify that what you are doing ought to work:
CREATE TABLE table1 (field NVARCHAR(100) NOT NULL);
INSERT INTO table1 (field) VALUES
('foo1'),
('bar1'),
('baz1');
CREATE TABLE table2 (field NVARCHAR(100) NOT NULL);
INSERT INTO table2 (field) VALUES
('foo2'),
('bar2'),
('baz2');
SELECT field, 1 AS tmp
FROM table1
UNION ALL
SELECT field, 2 AS tmp
FROM table2
Result:
'foo1', 1
'bar1', 1
'baz1', 1
'foo2', 2
'bar2', 2
'baz2', 2
If you only get rows where tmp was equal to 1, maybe your table2 was empty?
*See the documentation for UNION.
The default behavior for UNION is that duplicate rows are removed from the result. The optional DISTINCT keyword has no effect other than the default because it also specifies duplicate-row removal. With the optional ALL keyword, duplicate-row removal does not occur and the result includes all matching rows from all the SELECT statements.
You are very close
Create YourNewTable
SELECT field, 1 AS tmp
FROM table1
UNION ALL
SELECT field, 2 AS tmp
FROM table2