MySQL: Combine multiple disparate tables into one - mysql

I have multiple tables, say A, B, and C where B and C have a foreign key to A.
I want to write a query that will return a result set where the columns of the result set are the columns of A and B and C combined, i.e.
A.id A.name B.id B.name C.id C.name
-----------------------------------
1 Thing 2 Bee NULL NULL
1 Thing NULL NULL 1 Cow
That is, essentially a combination of the results of an individual LEFT OUTER JOIN on B and C, but combined into a single result set. I am ok with there being multiple NULL columns.
EDIT: The result set will always have the entries of A, but only ONE of either B or C.
Is this possible? Or is there a better way of joining this information?

Since you never want a single row to contain both B and C, you might UNION together two separate join queries, substituting NULL literals for the opposite table to get the columns to align. Each part of the UNION supplies the relationship between A->B or A->C, but must return NULL for all the columns of the opposite table. Supply a NULL literal to leave empty every column from the other table.
In the end to sort them, you can conditionally check that the B columns are NOT NULL to force the B row to sort ahead of the C row, after first ordering by A.id.
(
SELECT
A.id AS a_id,
A.name AS a_name,
B.id AS b_id,
B.name AS b_name,
/* Substitute NULLs... for the other table C, for *all columns* */
NULL AS c_id,
NULL AS c_name,
NULL AS other_c
/* etc, other cols from C */
FROM A
LEFT JOIN B ON A.id = B.a_id
/* UNION, rather than UNION ALL in case both tables have NULLs */
) UNION (
SELECT
A.id AS a_id,
A.name AS a_name,
/* This time substitute NULLs for B, again *all columns* */
NULL AS b_id,
NULL AS b_name,
C.id AS c_id,
C.name AS c_name
C.other_c
FROM A
LEFT JOIN C ON A.id = C.a_id
)
ORDER BY
a_id,
/* sort the non-null B ahead... */
CASE WHEN b_id IS NOT NULL THEN 0 ELSE 1 END

Related

Select unmatched records from two tables with a filter on second table

I have 2 mysql tables a and b. I need to show all records in a that are not in b using a common column 'ID'. Normally this is pretty straight forward but my problem here is this: I need to put a where clause on table b because I'm not interested in all unmatched records just the ones that meet the table 2 where clause criterion:
SELECT a.ID, a.Description
FROM a
LEFT JOIN b ON a.ID = b.ID
WHERE a.Inactive = 0
AND b.Room = '101'
AND b.ID Is Null
This returns nothing. However if I remove the AND b.Room = '101' part, it displays the expected results. But I need that condition because I need only unmatched records specific to a 'room' and not all unmatched records
Move the conditions involving table b from WHERE to ON clause:
SELECT a.ID, a.Description
FROM a
LEFT JOIN b ON a.ID = b.ID AND b.Room = '101'
WHERE a.Inactive = 0
AND b.ID Is Null
It'll find rows where a does not have a match in b (id matches and room number = 101).

How to complete this query function?

I have three tables.
Table A ###(Code, Value are combined primary key)
Code Value
1 | b
1 | c
3 | c
Table B
Value
b
Table C
Value
c
I would like to write a query of 'Code' from Table A.
The condition is that 'Code' should contain Value 'c'.
If 'Code' contains Value'b', this Code shouldn't be queried. (that's, Code 1 has value b and value c, so Code 1 needs to be excluded)
But I'm not available to do that query.
The expected outcome might be '3'
I want to use intersect but MySql doesn't contain this function yet.
So I tried some codes.
I'm sure that my codes have problems but I have no idea how to fix it.
SELECT DISTINCT A.*
FROM A B C
WHERE A.Value IN
(SELECT Value FROM B)
AND A.Value NOT IN
(SELECT Value FROM C);
Could you give me some tips on my questions?
the problem is that you are joining a, b and c. you almost got it.
select distinct a.value
from a
where a.value in (select value from b)
and a.value not in (select value from c)
or you can use join
select *
from a
inner join b where b.value = a.value
and not in (select value from c)

SQL Query to compare two tables for names

I am building a SQL query which compares two tables A and B by a [name] column and returns the names from table A that are not in table B
Example
Table A
ID Name Address
1 A ABC
2 B XYZ
3 C PQR
Table B
ID Name Gender
1 A F
2 B M
3 D F
The query I wrote should return third row from table A as it is not in table B and should exclude all other rows
Following is the query I built
Select * from A oa left join B gp ON oa.name!=gp.name
the above doesn't return the results I was expecting.
Can this be corrected?
Easiest way:
select * from A where name not in (select name from B)
Better way:
select * from A where not exists (select 1 from B where B.name = A.name)
"A left join B" means keeping everything in A, and associating records in B if the condition is satisfied.
In your case, if you really wanna use left join, here is what it should be ('=', not '!='):
Select * from A oa left join B gp ON oa.name=gp.name where gp.name is null
Better way would be using 'not exists' performance-wise, or 'except' if null values are not an issue.
Using excpet operator will help
select * from TableA
except
select * from TableB
SELECT a.*
FROM A a
LEFT JOIN B b
ON a.name = b.name
WHERE b.name IS NULL

Get records not present in another table with a specific user id

I've this table (a)
And this table (b)
Now I have to get all records from A which are not present in B (a.id not present as b.idDomanda) and where B.idUser is not 1. So In this case, it should return only id 2 from a, but it returns 1 and 2.
This is my Query
SELECT a.* FROM a LEFT JOIN b ON a.id=b.idDomanda WHERE ( b.idUser <> 1 OR b.idUser IS NULL ) GROUP BY a.id
You want to move the condition on b to the on clause:
SELECT a.*
FROM a LEFT JOIN
b
ON a.id = b.idDomanda and b.idUser <> 1
WHERE b.idUser IS NULL
GROUP BY a.id;
The group by suggests that you might want to use not exists instead:
select a.*
from a
where not exists (select 1
from b
where a.id = b.idDomanda and b.idUser <> 1
);
There should be no results given your data set.
All records from A which are not present in B (a.id not present as b.idDomanda)
Given the test data set all of A is in fact IN b.idDomanda... even when filtering out userId = 1.
but as the previous person pointed out that is the query to check.

MYSQL: evaluating a missing row into a result

I am trying to fetch records from 2 tables mapped by an id where on the second table there may be a row that is missing.
I have a column called name on the second table which contains a string value. The value I need to extract is 'subscriptions' but this does not always exist in the table. There is the possibility to have different values within this column which I do not want to extract.
Is it possible to check to see if the value exists and if it doesn't output null to all the fields.
So far I have this which returns all the records
select COUNT(*)
from PUser a, PAttribute b
where exists (select null
from PAttribute c
where c.name = 'subscriptions' or c.name is null)
and a.id = b.userid;
Hope that explains it.
EDIT
PUser table
id
other columns
PAttribute table
userid mapped to PUser.id
name
Now a userid can have multiple rows each with a different value in name eg, 'subscriptions', 'source', 'etc' 'etc'
I want to fetch all users who have the value 'subscriptions' in the name column or if the row doesnt exist with the value 'subscriptions' as they may not have any.
If they don't have this row the output should be null.
EDIT 2:
Worked this out and I needed
select COUNT(*),(select b.stringValue from PAttribute b where b.userid = a.id and b.name = 'subscriptions') from PUser a order by a.id desc;
Your example is using implicit joins, which are inner joins. This means that a result will only be returned if a row exists in both tables. Instead, you need to use a left join. Change your query to this:
select COUNT(*)
from PUser a LEFT JOIN PAttribute b ON a.id = b.userID
where exists (select null
from PAttribute c
where c.name = 'subscriptions' or c.name is null);
Or (not exactly sure what your desired behavior is), this might work for you:
SELECT count(*)
FROM PUser a LEFT JOIN PAttribute b ON a.id = b.userID
WHERE b.name = 'subscriptions' OR b.name IS NULL;
If you want to exclude rows that do not contain 'subscriptions', you could use the JOIN ON form and in order to keep rows from PUser even there is no matching row from PAttribute with name set to 'subrciptions', and thus obtaining null fields, exploit OUTER JOIN.
select COUNT(*)
from PUser a OUTER JOIN PAttribute b ON ( a.id = b.userid AND b.name = 'subscriptions' )
;
This is a little bit different from your query: EXISTS is less perfomant and, moreover, the SELECT in the EXISTS does search for a row in PAttribute with name equal to null, that is quite different from handling missing rows.