I have a problem with my SQL query.
Situation is as follows:
I have two tables, A and B.
Table A:
---------------------------------------------
*| A.id | A.t_id | A.f_id | A.type |*
---------------------------------------------
| 1 | 32 | 3 | Loading |
| 2 | 34 | 5 | Discharge |
| 3 | 32 | 3 | Discharge |
---------------------------------------------
Table B:
-----------------------
*| B.id | B.shipid |*
-----------------------
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
-----------------------
I need all the rows from A where A.type=Loading, A.t_id is B.id -> B.shipid=2 and . My query so far is:
SELECT * FROM A, B WHERE (A.type='Loading' AND B.shipid=2 AND A.t_id=B.id)
but this doesn't return the right records (none, actually) while the data should fit the query. Where does my query goes wrong?
Try this::
SELECT
*
FROM
A
INNER JOIN B ON A.t_id=B.id
WHERE A.type='Loading' AND B.shipid=2
Try this
SELECT * FROM A a JOIN B b ON a.t_id = b.id WHERE b.shipid = 2 AND a.type = 'Loading'
-- a and b are aliases for A and B. If you have any bigger table names, it's useful
And you should lookup SQL JOIN http://www.w3schools.com/sql/sql_join.asp
If you need all rows from A then it sounds like a left join... so please also provide your expected results anyway to confirm..
SELECT A.* FROM A
INNER JOIN B
ON A.f_id=B.id
AND A.type='Loading' AND B.shipid=2
;
Since you have a condition to get records for loading, and the only issue is that id aren't matching as per the above comments pointed out..
SQLFIDDLE DEMO
Related
I'm trying to join two tables together in MySQL. I need to join based on the full string from one field (Table a:ID) and the sub-string from the other table (Table b:caseID). A mock-up of the table structure can be seen at the bottom of this post. ID and caseID are defined as unique.
The output I'm looking for is similar to:
|-------------|--------------|------------|
| ID | name | age |
|-------------|--------------|------------|
| 1 | Bob | 22 |
| 2 | Bill | 23 |
| 3 | Ben | 24 |
|-------------|--------------|------------|
I know how to extract a substring based on a delimiter:
SELECT SUBSTRING(caseID, LOCATE('-', caseID)+1, LENGTH(caseID)) AS ExtractString FROM b
but I'm unclear how to combine this with the usual SQL JOIN statement to return all joined records. I keep getting error like 'returns more than one row'.
Any help much appreciated.
Table a:
|-------------|--------------|
| ID | name |
|-------------|--------------|
| 1 | Bob |
| 2 | Bill |
| 3 | Ben |
|-------------|--------------|
Table b:
|-------------|--------------|
| caseID | age |
|-------------|--------------|
| 24-1 | 22 |
| 24-2 | 23 |
| 24-3 | 24 |
|-------------|--------------|
SELECT *
FROM a
LEFT JOIN b ON a.ID = SUBSTRING(b.caseID, LOCATE('-', b.caseID)+1, LENGTH(b.caseID))
SELECT *
FROM a
JOIN b ON a.ID = SUBSTRING_INDEX(b.caseID, '-', -1)
Typical, as soon as I ask the question I work out the answer!
SELECT a.*, b.*
FROM a
JOIN b
ON b.id = SUBSTRING(a.caseID, LOCATE('-', a.caseID)+1, LENGTH(a.caseID))
This question already has answers here:
Understanding the number of matched rows in LEFT JOIN
(5 answers)
Closed 4 years ago.
Here is my table structure:
// mytable
+----+---------+----------+
| id | related | subject |
+----+---------+----------+
| 1 | NULL | subject1 |
| 2 | 1 | |
+----+---------+----------+
And there are two queries which seem identical to me, but have different results in tests:
SELECT a.id, IFNULL(b.subject, a.subject)
FROM mytable a
LEFT JOIN mytable b ON a.id = b.related
+----+----------+
| 1 | subject1 |
| 2 | |
+----+----------+
SELECT a.id, IFNULL(b.subject, a.subject)
FROM mytable a
LEFT JOIN mytable b ON b.id = a.related
+----+----------+
| 1 | subject1 |
| 2 | subject1 |
+----+----------+
Look, it is self-join. So why the result of ON a.id = b.related and ON b.id = a.related is different?
Running your queries with SELECT * to uncover some of the mystery:
Your first query:
SELECT *
FROM mytable a
LEFT JOIN mytable b ON a.id = b.related;
Produces the following:
+----+---------+----------+--------+----------+----------+
| id | related | subject | id1 | related1 | subject1 |
+----+---------+----------+--------+----------+----------+
| 2 | 1 | <null> | <null> | <null> | <null> |
| 1 | <null> | subject1 | 2 | 1 | <null> |
+----+---------+----------+--------+----------+----------+
Your second query:
SELECT *
FROM mytable a
LEFT JOIN mytable b ON b.id = a.related;
Produces this:
+----+---------+----------+--------+----------+----------+
| id | related | subject | id1 | related1 | subject1 |
+----+---------+----------+--------+----------+----------+
| 2 | 1 | <null> | 1 | <null> | subject1 |
| 1 | <null> | subject1 | <null> | <null> | <null> |
+----+---------+----------+--------+----------+----------+
Your first query is joining id 2 to related 2. There is no related 2 and since id 2 has no subject, you get no subject out of your ifnull().
Your second query is joining related 1 to id 1 for a.id 2. This pulls a subject from b.id 1 and you get a subject back for id 2 as a result.
You really have to mentally map out how a LEFT JOIN works here and how it is affected by your ON clause. You have two very different queries here as a result.
Both queries are getting all rows from a.
Both queries are doing an outer join to b.
What's different is the condition that is used for finding a "match" from b.
(The queries might seem to be identical, but the truth is that they are significantly different.)
As a demonstration, run a query like this:
SELECT a.id AS `a_id`
, a.related AS `a_related`
, a.subject AS `a_subject`
, b.id AS `b_id`
, b.related AS `b_related`
, b.subject AS `b_subject`
FROM mytable a
LEFT
JOIN mytable b
ON b.related = a.id
And then change the ON clause
ON b.id = a.related
You might also want to repeat both of those queries removing the LEFT keyword (to make it an inner join instead of an outer join.)
One way to look at an outer join... when a matching row from b is not found, a dummy row from b is invented. That dummy row consists entirely of NULL values, and the dummy row is joined to a, as if it were a matching row. (This isn't necessarily what the database engine actually does, but thinking about it this way gives us an insight to the results that the outer join returns.)
Take a close look at the results of the queries, and you will be able to see why the results by the queries are different.
The fact that a and b refer to the same table is a special case. We would see the same results if those were two different tables. It really doesn't matter... to the query, those are two different sources which just happen to refer to the same table. Don't let the fact that a and b refer to the same table cause any confusion.
I have a table A that contains tree columns, id, users ids and vehicle id. And a table B that contains vehicleid, and vehicle name.
Table A
---------------------------
| Id | User_id |Vehicle_id|
---------------------------
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 1 | 4 |
| 4 | 2 | 2 |
| 5 | 2 | 3 |
| 6 | 4 | 5 |
---------------------------
Table B
-------------------
| Id |Vehicle_name|
-------------------
| 1 | Car |
| 2 | Bike |
| 3 | Plane |
| 4 | Boat |
| 5 | Rocket |
-------------------
Given a user id, I need to get all vehicle names, that doesn't match with table A. I've tried Outer joins, but I can't manage to do get the info that i need.
For example: Given user id 1, the query should return Car and Rocket.
thanks in advance
This is simple enough using not in or not exists:
select b.*
from b
where not exists (select 1
from a
where a.vehicle_id = b.id and a.user_id = #a_user_id
);
I also thought of using a cross join and was able to get the output in case you are more comfortable with join logic.
SELECT CJOIN.USER_ID, CJOIN.VEHICLE_ID, CJOIN.VEHICLE_NAME
FROM
(SELECT DISTINCT A.USER_ID, B.ID AS VEHICLE_ID, B.VEHICLE_NAME FROM TABLE_A A CROSS JOIN TABLE_B B) CJOIN
LEFT JOIN
TABLE_A D
ON CJOIN.USER_ID = D.USER_ID AND CJOIN.VEHICLE_ID = D.VEHICLE_ID
WHERE D.USER_ID IS NULL AND D.VEHICLE_ID IS NULL;
First, I got all possible combinations of USER_ID x VEHICLE_ID by a cross join and used this table in a left join to pull records for which there is no match.
I have three tables
Table a
+-----+-------+
| aid | value |
+-----+-------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
+-----+-------+
Table b
+-----+------+
| bid | name |
+-----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+-----+------+
Table ba (mapping of table a and table b)
+-----+-----+
| bid | aid |
+-----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 3 | 2 |
| 1 | 3 |
| 2 | 3 |
| 2 | 4 |
+-----+-----+
From these tables I want a query like
SELECT aid, mapped('true'-if(aid exist in ba) 'false'-otherwise)
FROM a
JOIN b
JOIN ba
WHERE bid=1
to get a result from where I can generate a list
(when bid=1)
A-mapped
B-not mapped
C-mapped
D-not mapped
(when bid=2)
A-mapped
B-not mapped
C-mapped
D-mapped
(when bid=3)
A-mapped
B-mapped
C-not mapped
D-not mapped
Right now I am generating the list in a while loop for all the rows of table 'a' and inside the loop a query is executed for each iteration to check the existence in table 'ba'.
I think this is supposed to be table b independent:
SELECT CONCAT_WS('-', a.value, IF(ba.aid IS NULL, "-not mapped", "-mapped"))
FROM a LEFT JOIN ba ON a.aid = ba.aid AND ba.bid = 1
ORDER BY a.aid
Note: I took "a" table as the base table since your samples included all values from "a" table.
This is a tricky question, but the difficult part is in figuring out how to formulate the query. Once that is out of the way, it is downhill from there. One approach is to use a cross join between the A and B tables to obtain all possible mappings. Then LEFT JOIN to the mapping table to determine which pairs are being mapped and which are not. Try the following query:
SELECT tb.bid, ta.value,
CASE WHEN ba.bid IS NOT NULL THEN 'mapped' ELSE 'not mapped' END AS label
FROM tb INNER JOIN ta -- cross join to obtain all bid/aid pairs
LEFT JOIN ba -- to determine which pairs are mapped/not mapped
ON ta.aid = ba.aid AND tb.bid = ba.bid
ORDER BY tb.bid, ta.value
Demo here:
SQLFiddle
This is a bit difficult to explain, but I'll give my best:
Let's say, I have table A:
event | task | ref_person
------+------+-----------
1 | 20 | 1
2 | 9 | 2
And I have table B (containing person):
id | name
---+-----
1 | foo
2 | bar
3 | jim
What does a MySQL-query look like, that produces this sort of table:
event | task | person
------+------+-------
1 | 20 | foo
1 | NULL | bar
1 | NULL | jim
2 | NULL | foo
2 | 9 | bar
2 | NULL | jim
My current approach is by using a RIGHT JOIN, but this won't get me the event combined with the NULL-value.
This is what my current statement looks like:
SELECT
a.*,
b.name
FROM
a
RIGHT JOIN b
ON b.id = a.ref_person
ORDER BY
a.event,
b.name
Notice
sqlfiddle seems down, I'll add one as soon as it's up again
You want to do a cross join to get all the rows, then case logic to get the task:
select a.event,
(case when a.ref_person = b.id then a.task end) as task,
b.name
from tablea a cross join
tableb b ;