Join only with first row that refers to parent table - mysql

I have following tables:
A B
id | a | id | b
-------- -------
1 | . | 1 | 1
-------- -------
2 | . | 1 | 2
-------- -------
3 | . | 2 | 1
-------
2 | 2
B.id is a foreign key which references on A.id.
I would like to display A.id, A.a, B.b. But columns from table A should be joined only with the first row from table B which refers to A.id. I also want to select rows from table A which don't have corresponding row in table B.
So the result should looks like this:
A.id | A.a | B.b
----------------
1 | . | 1
----------------
2 | . | 1
----------------
3 | . |
Thanks in advance for any help.

Simply use GROUP BY and LEFT JOIN clauses :
SELECT A.id, A.a, B.b
FROM A
LEFT JOIN B ON B.id = A.id
GROUP BY A.id
ORDER BY A.id ASC

Try this -:
SELECT A.id, A.a, B.b
FROM A
LEFT JOIN (
SELECT b1.id, b1.b
FROM B b1, B b2
WHERE b1.b < b2.b
)B
ON A.id = B.id
GROUP BY A.id
ORDER BY A.id asc

Related

Is there any way to do calculate the MAX() quickly?

I am trying to do this query:
SELECT
A.*
, (SELECT MAX(B.Date2) FROM Tab2 B WHERE A.ID = B.ID AND A.Date > B.Date2) AS MaxDate
FROM
Tab A
This works but it takes a lot of time to run when you have a lot of rows. Is there any quicker way to do this which give the same results?
Thank you!
Edit:
The table définitions are as follow:
Tab : (dd-mm-yyyy)
ID | Date
1 | 19-01-2018
1 | 14-01-2018
2 | 18-02-2019
3 | 20-03-2019
Tab2:
ID | Date2
1 | 10-01-2018
1 | 15-01-2018
1 | 20-01-2018
2 | 15-02-2019
2 | 21-02-2019
3 | 25-03-2019
I want my query returns:
ID | Date | MaxDate
1 | 19-01-2018 | 15-01-2018
1 | 14-01-2018 | 10-01-2018
2 | 18-02-2019 | 15-02-2019
3 | 20-03-2019 | NULL
Thanks!
It was unexpected for me but this query worked:
SELECT
A.ID
, A.Date
, MAX(B.Date2) AS MaxDate
FROM
Tab A
left outer join Tab2 B
on A.ID = B.ID and A.Date > B.Date2
GROUP BY
A.ID, A.Date
;
I didn't know that we can put a column from a table in a group by when the column of the MAX() is in another table.

How to get total "active" users using Mysql?

I have four tables:
Table A: users_table
Table B: users_account_table
Table C: fangates_table
Table D: downloads_table
Table A(users_table) contains three columns: ID, NAME and GATE_COUNT.
Table C(fangates_table) contains users gates.
Table D(downloads_table) contains fangates_table_id and account_id.
TABLE A
ID | NAME | GATE_COUNT
---------------------------
1 | Joy | 2
---------------------------
2 | Ash | 0
---------------------------
3 | Nik | 2
---------------------------
4 | Wox | 0
TABLE B
ID | A_ID | ACCOUNT_ID
---------------------------
1 | 1 | 123456
---------------------------
2 | 1 | 654321
---------------------------
3 | 3 | 5888
---------------------------
4 | 3 | 8787
TABLE C
ID | A_ID | TITLE
---------------------------
1 | 1 | ABCD
---------------------------
2 | 1 | DFCV
---------------------------
3 | 3 | FGTG
---------------------------
4 | 3 | FRGTG
TABLE D
ID | C_ID | ACCOUNT_ID
---------------------------
1 | 1 | 123456
---------------------------
2 | 2 | 123456
---------------------------
3 | 3 | 7859
---------------------------
4 | 1 | 7585
From the above tables, I am trying to get the total "active" users (where an active user is defined as a user with fangates having any downloads other not themself)
I have tried the following query, but it has failed.
SELECT COUNT(*) FROM D
WHERE (C_ID,ACCOUNT_ID)
NOT IN
(SELECT C.ID, B.ACCOUNT_ID FROM A
LEFT JOIN B ON A.ID = B.A_ID
LEFT JOIN C ON A.ID = C.A_ID
WHERE A.GATE_COUNT >0);
The error, as I see it, is that you are failing to provide a join parameter in the initial selection of your table. If I am to understand your table design correctly, the following query would retrieve all the information in your tables:
SELECT *
FROM A,B,C,D
WHERE B.A_ID = A.ID AND C.A_ID = A.ID AND D.C_ID = C.ID;
If my presumption is correct, and you are trying to get the active users, you could simply place your parameters as an appended AND and continue onward. However, doing this many joins could greatly slow down any code; joins are a very taxing process, no matter how small the tables are. Since you are looking to find the count of downloads
SELECT COUNT(*) FROM D
WHERE (C_ID)
NOT IN
(SELECT C.ID FROM A, C
WHERE GATE_COUNT >0 AND A.ID = C.A_ID);
From what I can tell, you don't need to specify the distinct ACCOUNT_ID from the B table, as the information is distinctly paired to the B table. Otherwise, your columns would mismatch.
Otherwise, you can do a second lookup and try adding the B lookup as an AND parameter
SELECT COUNT(*) FROM D
WHERE (C_ID)
NOT IN (SELECT C.ID FROM A, C
WHERE GATE_COUNT >0 AND A.ID = C.A_ID) AND ACCOUNT_ID NOT IN
(SELECT DISTINCT B.ACCOUNT_ID FROM A,B WHERE A.ID = B.A_ID AND A.GATE_COUNT >0);
SELECT COUNT(DISTINCT(B.A_ID))
FROM TABLE_B B
JOIN TABLE_C C ON (B.A_ID = C.A_ID)
JOIN TABLE_D D ON (D.C_ID = C.C_ID AND B.ACCOUNT_ID <> D.ACCOUNT_ID)

SQL Join: Select rows with no match in second table

I am trying to join two tables while still getting the results from table A even if there is no matching record in table B. I think the where clause is causing the problem but I can't seem to fix it.
SELECT a.id, a.title, a.validation, b.data
FROM client_option_detail AS a LEFT OUTER JOIN client_data AS b
ON a.id = b.client_option_detail_id
WHERE a.client_option_id = ?
AND (b.client_id IS NULL OR b.client_id = ?)
UPDATE:
database layout
client_option client_option_detail
------------- -------------------
id id
title
validation
client_option_id
client client_data
------- ------------
id client_id
client_option_detail_id
data
database sample:
client_option client_option_detail
------------- -------------------------------------------
id id | title | validation | client_option_id
------------- -------------------------------------------
1 1 | test1 | | 1
2 2 | test2 | | 1
3 | test3 | | 1
4 | test4 | | 2
client client_data (primary key - client_id + client_option_detail_id)
-------- -------------------------------------------
id client_id | client_option_detail_id | data
-------- -------------------------------------------
1 1 | 1 | data1
2 1 | 2 | data2
1 | 4 | data3
2 | 3 | data4
2 | 1 | data5
sample query:
SELECT a.id, a.title, a.validation, b.data
FROM client_option_detail AS a LEFT OUTER JOIN client_data AS b
ON a.id = b.client_option_detail_id
WHERE a.client_option_id = 1
AND (b.client_id IS NULL OR b.client_id = 1)
required output:
-------------------------------------------
id | title | validation | data
-------------------------------------------
1 | test1 | | data1
2 | test2 | | data2
3 | test3 | |
SELECT client_option_detail.id, title, validation, data
FROM client_option_detail LEFT OUTER JOIN client_data
ON client_option_detail.id = client_data.client_option_detail_id
It should be okey. I think is your where condition has some problem.
For example : client_option_detail.client_option_id = ?
,? is it contain all the id in client_option_detail ?
You do not need the AND (b.client_id IS NULL OR b.client_id = ?)
SELECT a.id, a.title, a.validation, b.data
FROM client_option_detail AS a
LEFT JOIN client_data AS b
ON a.id = b.client_option_detail_id
WHERE a.client_option_id = ?
output will be something like:
id title validation data
1 foo bar sample_data1
2 apple oranges null
3 try it sample_data2
Like in the sample output number 2, data will be null if there is not matched from table B and information from table A will still be shown
also, if you really wanted to filter based on specified client_id from B, then just put or on the last part like below. It means that if the data contains either specified client_id from B or if it has the specified client_option_id from A, then it will be retrieved.
SELECT a.id, a.title, a.validation, b.data
FROM client_option_detail AS a
LEFT JOIN client_data AS b
ON a.id = b.client_option_detail_id
WHERE a.client_option_id = ? OR b.client_id = ?
for more information, you might want to look at this post
UPDATE:
Try below codes for your update:
SELECT a.id, a.title, a.validation, b.data
FROM client_option_detail AS a
LEFT JOIN client_data AS b
ON a.id = b.client_option_detail_id AND b.client_id = a.client_option_id
WHERE a.client_option_id = 1
or this, i dont know which is right or the one that best suits for your needs but both yields same result based on your sample data:
SELECT a.id, a.title, a.validation, b.data
FROM client_option_detail AS a
LEFT JOIN client_data AS b
ON a.id = b.client_option_detail_id AND b.client_id = 1
WHERE a.client_option_id = 1
tried using SQLize:
I hope I got it right this time. Good luck

MYSQL joining 2 tables accross multiple fields

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.

Select * as well as count/sum from another table

I am trying to write a MySQL query to select all rows from table a, as well as information from table b, while also querying the count and sum of values in another table c, for each row of a.
I will try to break that down a bit better, here is a simplified version of my tables:
Table A
+---------+----------+-----------+
| id | name | bid |
+---------+----------+-----------+
| 1 | abc | 1 |
| 2 | def | 1 |
| 3 | ghi | 2 |
+--------------------------------+
Table B
+---------+----------+
| id | name |
+---------+----------+
| 1 | STAN |
| 2 | UCLA |
+--------------------+
Table C
+---------+----------+-----------+
| id | aid | cnumber |
+---------+----------+-----------+
| 1 | 1 | 40 |
| 2 | 1 | 20 |
| 3 | 2 | 10 |
| 4 | 3 | 40 |
| 5 | 3 | 20 |
| 6 | 3 | 10 |
+--------------------------------+
What I need is a query that will return rows containing
a.id | a.name | b.id | b.name | SUM(c.cnumber) | COUNT(c.cnumber)
I am not sure if such a thing is even possible in MySQL.
My current solution is trying to query A + B Left Join and then UNION with A + C Right Join. It's not giving me the results I'm looking for however.
Thanks.
edit:
current query re-written for this problem:
SELECT
a.id,
a.name,
b.id,
b.name
"somecolumn" as dummy_column
"somecolumn1" as dummy_column1
FROM a
LEFT OUTER JOIN b ON a.b.id = b.id
UNION
SELECT
"somecolumn" as dummy_column
"somecolumn1" as dummy_column1
"somecolumn2" as dummy_column2
"somecolumn3" as dummy_column3
COUNT(c.cnumber) AS ccount
SUM(c.cnumber) AS sum
FROM a
RIGHT OUTER JOIN c ON a.id = c.a.id;
Unfortunately MySQL doesn't have FULL OUTER JOIN, and this is my temporary work around, although I don't think it's even the proper idea.
My desired output is all the rows from table A with some info from table B, as well as their totaled inputs in table C.
edit2:
SELECT
a.id,
a.name,
b.id,
SUM(c.cnumber) as totalSum,
(SELECT count(*) FROM c as cc WHERE cc.aid = a.id) as totalCount
FROM
a
LEFT JOIN b ON a.bid = b.id
LEFT JOIN c ON c.aid = a.id;
For future similar questions, solution:
SELECT
a.id AS aid,
a.name,
b.id,
(SELECT SUM(c.rating) FROM c WHERE c.aid = aid) AS totalSum,
(SELECT COUNT(c.rating) FROM c WHERE c.aid = aid) AS totalCount
FROM
a
LEFT JOIN b ON a.bid = b.id;
Your query should be :-
SELECT
a.id,
a.name,
b.id,
(SELECT SUM(c.cnumber) FROM c as cd WHERE cd.aid = a.id) as totalSum,
(SELECT count(*) FROM c as cc WHERE cc.aid = a.id) as totalCount
FROM
a
LEFT JOIN b ON a.bid = b.id
LEFT JOIN c ON c.aid = a.id;
It may help you.
I have tried your example.
SELECT * ,
(SELECT SUM(cnumber) FROM `table_c` WHERE `table_c`.`iaid` = `table_a`.`id`),
(SELECT COUNT(cnumber) FROM `table_c` WHERE `table_c`.`a.id` = `table_a`.`id`)
FROM `table_a`,`table_b` WHERE `table_b`.`id` = `table_a`.`b.id`
i got the Following output.