MySql. How can i get count from 2 tables - mysql

I have 2 tables, TableA and TableB
TableA
IdA | Date | Description
--- | ---------- | -----------
1 | 2017-01-01 | Sometext1
2 | 2017-01-01 | Sometext2
3 | 2017-01-02 | Sometext3
4 | 2017-01-03 | Sometext4
TableB
IdB | IdA | Type
--- | --- | ----
1 | 1 | A
2 | 1 | A
3 | 2 | A
4 | 2 | A
5 | 2 | B
6 | 3 | B
7 | 4 | A
How can I get value like this :
Count(IdA) | Type
---------- | ----
3 | A
I have tried to code using INNER or LEFT JOIN like
SELECT COUNT(tablea.IdA), tableb.Type
FROM tablea INNER JOIN tableb
ON tablea.IdA=tableb.IdA
WHERE tableb.Type='A'
But it always get me like this
Count(IdA) | Type
---------- | ----
5 | A
I just want to count TableA row with WHERE clause from TableB.
Is it possible to do something like that?

You probably want COUNT(DISTINCT col).
Try this:
SELECT
COUNT(DISTINCT a.IdA), b.Type
FROM
tablea a
INNER JOIN
tableb b ON a.IdA = b.IdA
WHERE
b.Type = 'A'
GROUP BY b.type

Yes, you need distinct column ids (but here's an answer using alias)
SELECT COUNT(distinct A.IdA), B.Type
FROM tablea A
INNER JOIN tableb B ON (A.IdA = B.IdA)
WHERE B.Type = 'A'
And you don't even need to put an ON clause if you join by the same column name so, making the sql even shorter.
SELECT COUNT(distinct A.IdA), B.Type
FROM tablea A
INNER JOIN tableb B
WHERE B.Type = 'A'

Related

how to perform an outer join in mysql

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.

Select value from left table and full join right table

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 ;

SQL select distinct where exist row for each id in other table

I have table A and B with a relationship: A n<->1 B relationship.
They are joined over field A.b = B.id, where B.id is unique
I have a parameter which is a bunch of ids of B.
I want to get distinct A.id that have all given B.ids assigned.
Example:
Table B
| id | ...
| 1 |
| 2 |
| 3 |
Table A
| id | b | ...
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
<-- id=2 is not assigned to b=3 !
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
Expected result for parameter B.ids="1,2,3": 1, 3 (2 misses the required B.id=3)
How can I do this?
You can do this with aggregation and a having clause:
select id
from tableA a join
tableB b
on a.b = b.id
group by id
having count(distinct b) = (select count(distinct b) from tableB);
Note that this can possibly be simplified with some assumptions. For instance, if you know the b ids are unique, then you don't need the count(distinct) (count() is then sufficient.)
EDIT:
If you want a list of ids that you want to check, you can use:
select id
from tableA a
where find_in_set(a.b, IDLISTHERE) > 0
group by id
having count(distinct b) = (select count(distinct b) from tableB where find_in_set(a.b, IDLISTHERE) > 0);
select id from tableA a join tableB b on a.b = b.id
group by id
having count(distinct b) = (select count(distinct b) from tableB);

MSQL select regardless of distinct or not distinct (count greater than zero)

I've found many ways to show only distinct results, but how would I select both the distinct and the non distinct together? Consider these tables:
A
---------------------------------
| id | col1 | col2 |
---------------------------------
| 1 | aa | dd |
---------------------------------
| 1 | bb | ee |
---------------------------------
| 2 | cc | ff |
---------------------------------
B
---------------------------------
| id | col1 | col2 |
---------------------------------
| 1 | a | d |
---------------------------------
| 2 | b | e |
---------------------------------
| 3 | c | f |
---------------------------------
C
---------------------------------
| id | col1 | col2 |
---------------------------------
| 1 | x | 1a |
---------------------------------
| 2 | y | 2b |
---------------------------------
| 3 | x | 3c |
---------------------------------
A user supplies to me an id and a list of columns, say id = 1 and columns = (a.col1, b.col1, and c.col2). How would I construct a query to give me all column information where the id matches, regardless of how many times the id appears?
My current query is:
SELECT a.col1, b.col1, c.col2
FROM a
LEFT JOIN b
ON b.id = a.id
LEFT JOIN c
ON c.id = b.id
WHERE a.id = 1
The problem is that this only gives me one result from table A when I'd like to get both results (or all results from any table that happens to have repeating ids that match). Note: In table A, the columns id and col1 together make up the primary key which is why I have repeating ids.
Suggestions?
Thanks!
In the data in the question, there is no repeating id in table A. The query should be returning only one row from A, then.
However, your query has an error. The second join should be back to the first table, not the second:
SELECT a.col1, b.col1, c.col2
FROM a
LEFT JOIN b
ON b.id = a.id
LEFT JOIN c
ON c.id = a.id
WHERE a.id = 1
You had c.id = b.id and b.id could be NULL if there is no match in that table.
Also, from your description, I wonder if a union would be the best approach:
select a.col1, 'a'
from a
where id = 1
union all
select b.col1, 'b'
from b
where id = 1
union all
select c.col2, 'c'
from c
where id = 1

Performance improvement for SQL count query

What type of sql query would I use to turn the following;
| ID | SERIAL | LCN | INITLCN |
|------|----------|-------|---------|
| 1 | A | A1 | |
| 2 | B | A2 | |
| 3 | C | A3 | A1 |
| 4 | D | A4 | A2 |
| 5 | E | A5 | A1 |
|------|----------|-------|---------|
into a result similar to this;
| ID | COUNT |
|------|---------|
| 1 | 2 |
| 2 | 1 |
|------|---------|
Using my low SQL skills, I have managed to write the below query however it is extremely slow;
select
a.id,
count (b.id) as parent
from assets a
left join assets b
ON (a.lcn = b.initlcn)
group by a.id
order by a.id;
select
t1.ID,
t1.LCN,
COUNT(*)
from
Table1 t1
INNER JOIN Table1 t2 ON t1.LCN = t2.INITLCN
GROUP BY t1.LCN
See it working live in an sqlfiddle.
maybe two table join is not nesecerry .
try this
select
a.id
,b.cnt
from assets a
join (
select
initlcn
count(1) cnt
from assets
group by initlcn
)
b on (a.lcn=b.initlcn)
you can test following query also -
I have checked the execution plan for your posted query and the following query and I am getting good difference between both -
SELECT t_1.Id, t_2.Cnt
FROM Assets t_1,
(SELECT Initlcn, COUNT(*) Cnt FROM Assets GROUP BY Initlcn) t_2
WHERE t_1.Lcn = t_2.Initlcn