mysql getting difference of 2 result sets - mysql

So I have two tables. One is called superIDs which has columns "superID BIGINT" and I have another one called mainIDs which has a column called "subid BIGINT". I know that mainIDS is a subset of superIDs. How can I see the rows that are ONLY in superID but not in mainIDs.
here is my attempt at a solution:
SELECT * FROM atlas_comparables.superIDs WHERE NOT EXISTS
(SELECT * FROM atlas_comparables.mainIDs);
However, this is returning me an empty set. Any help?

Try this
SELECT * FROM atlas_comparables.superIDs WHERE the_id_column NOT IN
(SELECT the_idcolumn_ofcomparable FROM tlas_comparables.mainIDs);
Note: the_id_column is in superIDs table
the_idcolumn_ofcomparable is in MainIdstable

If the ids only appear (at most) once in each table, then you can do this relatively easily with a left outer join:
select si.*
from atlas_comparables.superIDs si left join
atlas_comparables.mainIDs mi
on si.SuperID = mi.SubID
where mi.SubId is NULL;
If you are trying to compare all the columns (as except does in other databases), then you need a more complicated query, where you include all the columns on the on clause.

Related

SQL: How do add a prefix to column names in a JOIN?

I have sql query like this
SELECT * FROM phlegm WHERE JOIN mucus ON phlegm.id = mucus.id JOIN snot ON phlegm.id = snot.id
The problem is those tables contain several columns with identical names.
For example all 3 tables contain the column named test
If I retrieve the result of the query in PHP, then I will only get one value named test ($query->get_result()->fetch_object()->test;), because the other two get overwritten.
Is there some way to edit that query so that it adds a prefix to all columns from a table? For example, column test from table mucus would be referenced in the query as mucus_test and column test from phlegm would be phlegm_test.
One way would be doing
SELECT phlegm.test as phlegm_test, mucus.test as mucus_test FROM phlegm...
But I have a LOT of columns and tables and it would make the query longer than the Great Wall of China if I had to name each field one by one.
So is there some way to add the prefix en masse?
SELECT *, phlegm.test as phlegm_test, mucus.test as mucus_test FROM phlegm...
Used aliasing to retrieve all values associated from all three tables. if you want to reference only specific column do so by using the alias_name.column_name instead of p.*, where * means all columns belonging to table that the alias is associated with( ie. p refers to phlegm).
SELECT p.*, m.*, s.*
FROM phlegm p
JOIN mucus m ON p.id = m.id
JOIN snot s ON p.id = s.id;
I removed the WHERE from your original query above, not sure why it was there.

Natural join works but not with all values

I can't understand whats happening...
I use two sql queries which do not return the same thing...
this one :
SELECT * FROM table1 t1 JOIN table1 t2 on t1.attribute1 = t2.attribute1
I get 10 rows
this other :
SELECT * FROM table1 NATURAL JOIN table1
I get 8 rows
With the NATURAL JOIN 2 rows aren't returned... I look for the missing lines and they are the same values ​​for the attribute1 column ...
It's impossible for me.
If anyone has an answer I could sleep better ^^
Best regards
Max
As was pointed out in the comments, the reason you are getting a different row count is that the natural join is connecting your self join using all columns. All columns are being compared because the same table appears on both sides of the join. To test this hypothesis, just check the column values from both tables, which should all match.
The moral of the story here is to avoid natural joins. Besides not being clear as to the join condition, the logic of the join could easily change should table structure change, e.g. if a new column gets added.
Follow the link below for a small demo which tried to reproduce your current results. In a table of 8 records, the natural join returns 8 records, whereas the inner join on one attribute returns 10 records due to some duplicate matching.
Demo
You need to 'project away' the attribute you don't want used in the join e.g. in a derived table (dt):
SELECT *
FROM table1
NATURAL JOIN ( SELECT attribute1 FROM table1 ) dt;

SELECT * query, excluding columns

I have done allot of reading about this and it seems that isn't possible.
The thing is, since the amount of columns is dynamic i cant explicitly mention them. I put in aliases but the 'id' column keeps on appearing.
The CREATE doesnt work since there is 3 id columns in there, obiously.
(This query actually is ok, it works so dont evaluate it please)
CREATE TABLE merged as
SELECT *,
wuwebusers.id as wuwebusers_id,
jgwebusers_address.id as jgwebusers_address_id,
jgwebusers.id as jgwebusers_id
FROM wuwebusers
LEFT OUTER JOIN jgwebusers_address ON wuwebusers.id = jgwebusers_address.userid
LEFT OUTER JOIN jgwebusers ON wuwebusers.id = jgwebusers.userid
GROUP BY wuwebusers.id
EDIT:
question: how can i select every column except a few explicit ones. I know SELECT * isn't the correct way, since i am selecting all. I am asking for other way(s).
Since i have to do this a few times and the columns are dynamic and quite a few it isn't maintainable by explicitly writing every column name.
First you are doing a SELECT * Then adding columns as well. * is everything therefore you are getting mulitples of the same column. Those 3 ID's that you gave distinct names are being SELECTed again by the * in your query. Remove the * and type in the columns you need and you'll be fine.
CREATE TABLE merged as
SELECT
wuwebusers.id as wuwebusers_id,
jgwebusers_address.id as jgwebusers_address_id,
jgwebusers.id as jgwebusers_id ,
AllotherColumnsYouNeed as WhateverYouWantToCallthem
FROM wuwebusers
LEFT OUTER JOIN jgwebusers_address
ON wuwebusers.id = jgwebusers_address.userid
LEFT OUTER JOIN jgwebusers
ON wuwebusers.id = jgwebusers.userid
GROUP BY wuwebusers.id
/Edit\ If you changed your tables to not use the generic method of just labling a column ID in the first place you would also solve this problem. If you have a table name product for example call the ID column for that table ProductID. This will also solve your problem.

MySQL query for finding rows that are in one table but not another

Let's say I have about 25,000 records in two tables and the data in each should be the same. If I need to find any rows that are in table A but NOT in table B, what's the most efficient way to do this.
We've tried it as a subquery of one table and a NOT IN the result but this runs for over 10 minutes and almost crashes our site.
There must be a better way. Maybe a JOIN?
Hope LEFT OUTER JOIN will do the job
select t1.similar_ID
, case when t2.similar_ID is not null then 1 else 0 end as row_exists
from table1 t1
left outer join (select distinct similar_ID from table2) t2
on t1.similar_ID = t2.similar_ID // your WHERE goes here
I would suggest you read the following blog post, which goes into great detail on this question:
Which method is best to select values present in one table but missing
in another one?
And after a thorough analysis, arrives at the following conclusion:
However, these three methods [NOT IN, NOT EXISTS, LEFT JOIN]
generate three different plans which are executed by three different
pieces of code. The code that executes EXISTS predicate is about 30%
less efficient than those that execute index_subquery and LEFT JOIN
optimized to use Not exists method.
That’s why the best way to search for missing values in MySQL is using a LEFT JOIN / IS NULL or NOT IN rather than NOT
EXISTS.
If the performance you're seeing with NOT IN is not satisfactory, you won't improve this performance by switching to a LEFT JOIN / IS NULL or NOT EXISTS, and instead you'll need to take a different route to optimizing this query, such as adding indexes.
Use exixts and not exists function instead
Select * from A where not exists(select * from B);
Left join. From the mysql documentation
If there is no matching row for the right table in the ON or USING
part in a LEFT JOIN, a row with all columns set to NULL is used for
the right table. You can use this fact to find rows in a table that
have no counterpart in another table:
SELECT left_tbl.* FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id =
right_tbl.id WHERE right_tbl.id IS NULL;
This example finds all rows in left_tbl with an id value that is not
present in right_tbl (that is, all rows in left_tbl with no
corresponding row in right_tbl).

sql union error

I always get the "the used select statements have different number of columns" error.
select Sublessee_uname, Sublessee_fname, Sublessee_mname, Sublessee_fname from sublessee
union
select Sublessee_space, Sublessee_product from space_reserve
The error is pretty much self-explanatory. In the first SELECT you have 4 columns, whilst in the second you have 2 columns. In order to use UNION, the number of columns in both SELECTs must match.
In Union Case no of columns should be same in query
For you reference check this UNION
In a union the number of column need to match. Try
select Sublessee_uname, Sublessee_fname, Sublessee_mname, Sublessee_fname
from sublessee
union
select Sublessee_space, Sublessee_product, null, null
from space_reserve
Simplified Fiddle example
Based on some of your comments, it seems to me that you need a join of two tables rather than a union thereof.
And often, to join two tables, one of them must have a column or columns referencing the other. As the columns shown in your query do not seem to contain among them the right ones to use in the join condition and I don't know at this point what other columns your two tables possess, I'm going two assume that there's a Sublessee_Id column in both tables. And the query to retrieve the required data would then look something like this:
SELECT
s.Sublessee_uname,
s.Sublessee_fname,
s.Sublessee_mname,
s.Sublessee_fname,
r.Sublessee_space,
r.Sublessee_product
FROM sublessee s
LEFT JOIN space_reserve r /* or, depending on the requirements,
INNER JOIN space_reserve r */
ON s.Sublessee_Id = r.Sublessee_Id
;
If you want to learn more about JOIN syntax, you can try this manual page:
JOIN Syntax (MySQL)