I have two tables named A and B, here you can See A and B
A | id | title
-------------------------
1 | A1
2 | A2
3 | A3
B | A_id | title
-------------------------
1 | B1
1 | B2
1 | B3
what i want to do is to count The number of A_id's in B, i've tried the following query :
select A.title as "title",count(title) as "count" from A left join B on A.id = B.A_id
This will give me the following result :
title | count
---------------
A1 | 3
A2 | 1
A3 | 1
A4 | 1
what i need to have is :
title | count
---------------
A1 | 3
A2 | 0
A3 | 0
A4 | 0
Issues with your query:
You query is missing a GROUP BY clause. You seem to be using a version of MySQL where option ONLY_FULL_GROUP_BY is disabled, so, instead of throwing a proper error at you, MySQL happily executes your query.
count(title) is ambiguous, since the column exists in both tables. This should generate an error. You actually want to count on a column that is coming from table B; I would use B.A_id, just in case some records in B have an null title.
Consider:
select A.title, count(B.A_id) as `count`
from A
left join B on A.id = B.A_id
group by A.title
Side notes:
in MySQL, I would suggest using backticks for identifiers rather than double quotes; that's the MySQL way does it
A.title as title is redondant: it is equivalent to just A.title
try like below by adding B.A_id inside count
select A.title as "title",count(B.A_id) as "count"
from A left join B on A.id = B.A_id
group by A.title
Related
Is it possible to reduce the number of rows returned from a joined query by having results from individual tables returned in some array-like container
E.g. for a query:
SELECT a.col, b.col, c.col FROM
a INNER JOIN b ON a.id = b.id
INNER JOIN c ON a.id = c.id
where it is known a.id uniquely matches 1 row in a, b.id matches 2 rows in b and c.id matches 3 rows in c, the results would then be
+-------+-------+-------+
| a.col | b.col | c.col |
+-------+-------+-------+
| A0 | B1 | C1 |
| A0 | B2 | C1 |
| A0 | B1 | C2 |
| A0 | B2 | C2 |
| A0 | B1 | C3 |
| A0 | B2 | C3 |
+-------+-------+-------+
6 rows in set
So question is if it some how would be possible to reduce output to something like (or similar)
+-------+----------+--------------+
| A.col | b.... | c.... |
+-------+----------+--------------+
| A0 | [B1, B2] | [C1, C2, C3] |
+-------+----------+--------------+
Perhaps instead of array-like structure form strings (array like to me...), e.g. "B1,B2", "C1,C2,C3"
Note, can't use DISTINCT as b.col may contain identical values.
What if one wishes more than one column from table b, e.g.
SELECT a.col, b.col, b.col2, c.col FROM
a INNER JOIN b ON a.id = b.id
INNER JOIN c ON a.id = c.id
```
how to get a result on form (or similar)
```
+-------+------------------------+--------------+
| A.col | b.... | c.... |
+-------+------------------------+--------------+
| A0 | [[B1, B11], [B2, B21]] | [C1, C2, C3] |
+-------+------------------------+--------------+
```
Would it perhaps be possible/wise to prior to `JOIN` table a and b create a temporary table btmp with the desired output (as a string or similar).
At the end of the day I wish to access a mysql data base remotely over a line that sometimes may be quite bad, so wish to reduce the amount of data sent as far as possible without loosing required information.
This is a job for GROUP_CONCAT(). It doesn;t create arrays of values, but it does create delimited string lists. MySQL doesn't of course, have array-valued columns either in tables or result sets, so you're stuck with strings.
I believe this will do something close to what you want.
SELECT a.col,
GROUP_CONCAT(DISTINCT b.col) b
GROUP_CONCAT(DISTINCT c.col) c
FROM a
INNER JOIN b ON a.id = b.id
INNER JOIN c ON a.id = c.id -- you had a.id = b.id but that won't work.
GROUP BY a.col
It should be oh so simple, but perhaps the wine has gone to my head.
Table A (things that need parts)
id | Name | part1 | part2 | part 3 | part 4 | etc
1 | This thing | 1 | 2 | 3 | 2 | etc
2 | another thing | 1 | 1 | 4 | 5 | etc
3 | even more | 11 | 2 | 2 | 2 | etc
Table B (parts)
id | Description
1 | I am a part
2 | I am another Part
3 | Im a very imprtant part
A;; i actually need to do is select all the "parts" that each "thing" needs by its "DESCRIPTION"
so I get a each line in English rather than ID no's
ie
id | Thing name | part 1 | part 2 | part 3 | part 4
1 | This Thing | name of part | name of part | name of part | name of part
Like i said, complete memory overload here and Ive lost the will to live. Any help very gratefull recieved. Thanks in advance.
It will look something like this. Its been a while since I wrote a MySQL query. I am sure somebody could improve on it.
SELECT
a.id,
a.name,
b1.description,
b2.description,
b3.description,
b4.description
FROM
table_a `a`
LEFT JOIN
table_b `b1`
ON a.part1 = b1.id
LEFT JOIN
table_b `b2`
ON a.part2 = b2.id
LEFT JOIN
table_b `b3`
ON a.part3 = b3.id
LEFT JOIN
table_b `b4`
ON a.part4 = b4.id
Your data model has doomed you to complexity from the start.
select
*
from TableA A
left join TableB B1 on A.part1 = B1.id
left join TableB B2 on A.part2 = B1.id
left join TableB B3 on A.part3 = B1.id
left join TableB B4 on A.part4 = B1.id
This is untested, but if you "unpivot" TableA many more possibilities open up.
e.g.
SELECT
A.id
, A.Name
, GROUP_CONCAT(B.Description ORDER BY A.rowno) as PartsList
FROM (
SELECT
A1.id
, A1.Name
, cj.rowno
, CASE
WHEN cj.rowno = 1 THEN part1
WHEN cj.rowno = 2 THEN part2
WHEN cj.rowno = 3 THEN part3
WHEN cj.rowno = 4 THEN part4
END AS LinkID
FROM TableA a1
CROSS JOIN ( 1 AS rowno
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
) cj
) A
LEFT JOIN TableB B ON A.LinkId = B.ID
GROUP BY
A.id
, A.Name
and, if TableA was normalized permanently you would not need these complexities.
I have tables A, B and C and I want to get matching values for from all tables (tables have different columns).
Table A (primary key = id)
+------+-------+
| id | name |
+------+-------+
| 1 | Ruby |
| 2 | Java |
| 3 | JRuby |
+------+-------+
Table B (pid is reference to A(id) - No primary key)
+------+------------+
| pid | name |
+------+------------+
| 1 | Table B |
+------+------------+
Table C (primary key = id, pid is reference to A(id))
+------+------+------------+
| id | pid | name |
+------+------+------------+
| 1 | 2 | Table C |
+------+------+------------+
So my below query returned nothing. Whats wrong here? Is it treated as AND when multiple inner joins present?
Select A.* from A
inner join B ON a.id = b.pid
inner join C ON a.id = c.pid;
As you first join
1 | Ruby | Table B
and then try to join Table C, there is no match for pid 2 in the aforementioned result, the result is therefore empty.
An inner join excludes everything that doesn't match. So after you joined against B, you were left with only one record (id=1). Your inner join against C doesn't have any matches from what's left, so you get nothing.
I suppose a union would do the trick:
select A.* from A join B on a.id = b.pid
union
select A.* from A join C on a.id = c.pid
Or there are other ways, like where a.id in (select pid from b) or a.id in (select pid from c)
When you inner-join like this, a single row from A needs to exist such that a.id = b.pid AND a.id = c.pid are true at the same time. If you examine the rows in your examples, you would find that there is a row in A for each individual condition, but no rows satisfy both conditions at once. That is why you get nothing back: the row that satisfies a.id = b.pid does not satisfy a.id = c.pid, and vice versa.
You could use an outer join to produce two results:
select *
from A
left outer join B ON a.id = b.pid
left outer join C ON a.id = c.pid;
a.id a.name b.pid b.name c.id c.pid c.name
1 | Ruby | 1 | Table B | NULL | NULL | NULL
2 | Java | NULL | NULL | 1 | 2 | Table C
Of course you return nothing!
Table A and B inner join returns 1st record of Table A (table A ID = 1)
then you join table C, there is no matching rows to join table C, and vice versa.
Simple problem. Given example tables:
Table A:
id | type
---+-----
1 | A
2 | B
3 | C
Table B:
id | a_id | type
---+------+-----
1 | 1 | X
2 | 2 | Y
3 | 1 | X
4 | 3 | Z
(there are additional columns, which I omitted, in order to clarify the problem)
The query:
SELECT a.*
FROM a a
INNER JOIN b b ON b.a_id = a.id
WHERE b.type = 'X'
Result:
id | type
---+-----
1 | A
1 | A
SQL Fiddle: http://sqlfiddle.com/#!2/e6138f/1
But I only want to have distinct rows of Table A. I know, I could do SELECT DISTINCT a.*, but our Table A has about 40 columns, and this SELECT can return 100-10000 rows. Isn't that extremely slow, if the database has to compare each column?
Or is MySQL intelligent enough, to just focus on the Primary Key for the DISTINCT operation?
Thanks in advance :)
Use exists instead of an explicit join:
select a.*
from tablea a
where exists (select 1 from tableb b where b.a_id = a.id and b.type = 'x');
For performance, create an index on tableb(a_id, type).
I have seen various examples for this, but I can't find a definitive example of how to return all rows from table_A that are not related to a row in table_B using relate table_A_B without a given value for either table_A.id or table_B.id. The closest matchs I can find to this are:
Get a list of A not related to one or more rows in B but without knowing which value in B is the issue.
Get a list of A not related to given B.
Get list of A with comma-separated field of unrelated B (not sure I saw that, but it seemed like one example could expand as such).
A list of As and Bs not related to each other but no indication of which is not related to the other.
I can also get a list of all potential A_B tuples with:
SELECT A.id, B.id FROM A
INNER JOIN B ON A.id <> B.id
And I could hypothetically use one of the EXCEPT workarounds (I think) against the relate table, but all attempts were unsuccessful and I imagine that once there are millions of potential combinations returned by that join it will be much less efficient anyway.
So given the table values:
A
id | name
1 | X
2 | y
3 | z
B
id | name
7 | e
8 | f
9 | g
A_B
id | a_id | b_id
1 | 1 | 7
2 | 1 | 8
3 | 1 | 9
1 | 2 | 7
2 | 2 | 8
1 | 3 | 7
Is there a query that would return:
A | B
2 | 9
3 | 8
3 | 9
Or even better:
A | B
y | g
z | f
z | g
Or is this asking for trouble?
Start with a cross join between A and B to get all possible pairs. Then do a left join to the relation table and choose where there is no match:
select driver.aID, driver.bID
from (select a.id as aID, b.id as bID
from table_A A cross join table_B B
) driver left outer join
table_A_B ab
on ab.aID = driver.aID and ab.bID = bID
where ab.aID is null
This works, assuming that the ids are never NULL.
I haven't tested the SQL so it might have syntax errors.
This version gets you the names:
select driver.aName, driver.bName
from (select a.id as aID, b.id as bID, a.name as aName, b.name as Bname
from table_A A cross join table_B B
) driver left outer join
table_A_B ab
on ab.aID = driver.aID and ab.bID = bID
where ab.aID is null