Update using join and group with count - mysql

I am able to do an update between tables based on a count in the second table like so:
Update TableJ J
Inner Join (Select B_ID,C,S from TableC group by C,S having count=1) C
On J.C=C.C and J.S=C.S
Set T1.B_ID=T2.B_ID
The problem is my TableC does not contain S, that is stored in another table and related via B call it Table_BS (no jokes please :| ). If I didn't have to worry about count therefore I could do:
Update TableJ J
Inner Join TableC C
Inner Join TableBS BS
On J.C=C.C and C.S=BS.S
Set J.B_ID=BS.B_ID
Except the issue is, as with the original count, I only want to return B_ID when there is only one C record with an S record in TableBS.
Update:
Well this is how far I've gotten (select wise):
Select J.ID,B.B_ID
From DBJ J Inner Join LBS B Inner Join C
On J.C=C.C And (
J.S_ID = B.S_ID
or J.S_ID=B.CS_ID)
and B.B_ID=C.B_ID
Which in my case returns three records:
+----+------+
| ID | B_ID |
+----+------+
| 88 | 100 |
+----+------+
| 90 | 200 |
+----+------+
| 90 | 200 |
+----+------+
ID being the record I want to update, B_ID being the value I want to update with. In this case it turns out the count I am trying to limit is the ID column in the output, in other words I only want to update TableJ, record 88 with the value 100. TableJ record 90 turns out to have >1 result so I want to skip it. Just not sure where to put the group by or count here.
Update: Not sure why this solution remains just outside my grasp though getting closer, I can get the select to now return the ID of the record to update and the value to update with only on those records with one result like so:
Select J.ID,B.B_ID
From DBJ J Inner Join LBS B Inner Join C
On J.C=C.C And (
J.S_ID = B.S_ID
or J.S_ID=B.CS_ID)
and B.B_ID=C.B_ID group by J.ID having count(*)=1
which returns
+----+------+
| ID | B_ID |
+----+------+
| 88 | 100 |
+----+------+
And still unable to now get that to update TableJ record 88 field B_ID with the value of 100.

I am not sure if I understood correctly the problem,but here is my solution
Update TableJ J
Inner Join (
Select B_ID,TableC.C, TableBS.S
from TableC Inner Join TableBS
on TableC.B= TableBS.B
group by TableC.C,TableBS.S
having count(*)=1
) C
On J.C=C.C
Set J.B_ID=C.B_ID

This seems to have done the trick so far:
Update TableJ T1
Inner Join
(Select J.ID,B.B_ID
From TableJ J Inner Join TableBS B Inner Join TableC C
On J.C=C.C
And J.S = B.S
And B.B_ID=C.B_ID
group by J.ID having count(*)=1) T2
On T1.ID=T2.ID Set T1.B_ID=T2.B_ID
Basically solved it first with a select that returned the ID of the Update TableJ and the B_ID from TableBS where the C in TableC matched the C in TableJ and the S in TableBS matched the S in TableJ. I did a count on the results based on the ID in TableJ so that I only returned values when I got one result.

Related

Fetch record from 1st table which are not in 2nd table mysql

I have following records in these two mysql tables.
Table-A
Question_No
1
2
3
4
5
Table-B
Roll_No Question_No Ans_Option
1001 1 NULL
1001 2 D
1001 3 NULL
1002 1 C
1002 2 NULL
Here the word "NULL" is explicitly inserted into column , nothing to be confused.
How can I display the following result by mysql query?
Questions not attempted by roll no 1001 are : 1, 3, 4, 5
Questions not attempted by roll no 1002 are : 2, 3, 4, 5
I tried with following code but not working
select distinct a.* from table_A a NATURAL LEFT JOIN table_B b where
b.Question_No IS NULL and b.Roll_No=1001;// where I am wrong here ? I have
not set any column as primary key , should I set?
Thanks a lot in Advance
When you put WHERE condition on LEFT OUTER JOIN it is literally the same as INNER JOIN:
select distinct a.*
from table_A a
NATURAL LEFT JOIN table_B b
where b.Question_No IS NULL
and b.Roll_No=1001; -- this condition makes it `NATURAL JOIN`
You could rewrite it as:
SELECT DISTINCT a.*
FROM table_A a
LEFT JOIN table_b b
ON a.Question_No = b.Question_No
AND b.Roll_No=1001
WHERE b.Ans_Option_No IS NULL
db<>fiddle demo
Use a cross join to generate the rows and then filter them out:
select r.roll_no, b.Question_No
from (select distinct roll_no from b) r cross join
a left join
b
on b.roll_no = r.roll_no and b.Question_No = a.Question_No
where b.roll_no is null;
This gets the question that are not in b.

How do I count in a left join query

How do I count the number of participants in the event_participants table. This is my table
event_place
id | name
1 | New York
2 | Canada
event_participants
id | event_place_id | name
1 | 1 | Jon
2 | 1 | Mike
3 | 2 | Van
and I am getting a wrong result on my query
SELECT count(*) as count
FROM event_participants as t1
LEFT JOIN event_place as t2
ON t1.event_place_id = t2.id;
and the result is 3
I should be getting a result like this
New York | 2
Canada | 1
your query like this.
select pl.id,pl.name,count(*) from
event_place pl
left join event_participants ep
on pl.id = ep.event_place_id
group by pl.id;
You are getting correct results because you are counting all the records.
If you want the counts per event place, you should GROUP BY event place
SELECT t1.event_place_id, t2.name, count(*) as count
FROM event_participants as t1
LEFT JOIN event_place as t2
ON t1.event_place_id = t2.id
GROUP BY t1.event_place_id, t2.name,;
select a.name, count(1) from event_place a, event_participants b
where b.event_place_id = a.id
group by a.name;
There appear to be a couple of issues.
I presume you want a list of all the even places, and the number of people at each one. If so that suggests that you need to LEFT OUTER JOIN the event_participants table to the event_place table, rather than the other way round. This way you can have places listed which have no participants.
You also need a GROUP BY clause.
And if you use COUNT(*) you are counting the returned rows (prior to the grouping). However if there is no matching participants then a row is still returned for the place, hence you would get 1 as the count. To avoid this specify a column in the COUNT() which is on the participants table. COUNT with a column name counts the number of non NULL values of that column, hence if no participants it will return 0 for that place:-
SELECT t2.name,
COUNT(t1.id) AS count
FROM event_place t2
LEFT JOIN event_participants t1
ON t1.event_place_id = t2.id
GROUP BY t2.name

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

SQL query for joining one or another table

I have two tables TableA and TableB with some data:
IDA|TDATA IDB|TDATA
---+----- ---+-----
1 | A1 1 | B1
2 | A2 2 | B2
and one central table:
ID|TID|TAB|CDATA
--+---+---+-----
10| 1 | A | C1
11| 2 | B | C2
12| 2 | A | C3
Data from central table should be joined with data from TableA or TableB (joining columns TID and TAB). TID is reference to ID in joined table IDA or IDB and column TAB defines which table should be joined. So the final result from query should look like:
ID|TDATA|CDATA
--+-----+-----
10| A1 | C1
11| B2 | C2
13| A2 | C3
How this SQL query should look like?
You can do something like
SELECT c.id,
coalesce( a.tdata, b.tdata ) tdata,
c.cdata
FROM central_table c
LEFT OUTER JOIN tableA a
ON( c.tid = a.ida AND
c.tab = 'A' )
LEFT OUTER JOIN tableB b
ON( c.tid = b.idb AND
c.tab = 'B' )
I would seriously question the data model here, however. If you don't know whether a column in C references a column in A or B, something is generally incorrect in the data model. Fixing the data model will make this (and all your other queries, most likely) much easier to write and much easier to optimize.
If all you want is TAB followed by TID, then the following will work:
SELECT ID, CONCAT(TAB, CAST(TID AS CHAR[2])) AS TDATA, CDATA FROM CentralTable;
If the table names are constant (e.g., nothing other than A or B will be in there), then you can do:
(SELECT ID, TDATA, CDATA FROM CentralTable a
JOIN TableA b ON (a.ID = b.IDA) WHERE a.TAB = 'A')
UNION ALL
(SELECT ID, TDATA, CDATA FROM CentralTable a
JOIN TableB b ON (a.ID = b.IDB) WHERE a.TAB = 'B')

MySQL SELECT via xref table plus get count of another table's rows

Sorry about the title. I'm not sure how to properly describe the problem.
I have four tables, tables A, B, X and D. A and B have a many-to-many relationship so I'm using X as the link table.
Here's the structure:
Assuming all I have is an ID corresponding to a row in table A, I want to select the rows in table B that match up with that ID plus a count of all rows in table D that have the same b_id. Eh, I suck at explaining in words.
Here's what I would like (all I have to search with is an ID which corresponds to a row in table A -- let's just say I have an "A"):
-------------------------------------------------------------
| b.id | (A COUNT of how many rows in D have a b_id = b.id) |
-------------------------------------------------------------
| 1 | 20 |
-------------------------------------------------------------
| 4 | 12 |
-------------------------------------------------------------
So, according to the above results, this particular "A" has two "B"s. One of those "B"s has 20 "D"s and the other has 12 "D"s.
How can I write a single query to give me the results I'm after (again, all I'm searching with is an ID in table A)?
Try this:
SELECT b.id, COUNT(1)
FROM a,x, b,c
WHERE a.id = <YOUR_ID_FOR_A>
AND a.id = x.id
AND x.b_id = b.id
AND b.id = d,b_id
GROUP BY b.id
If the table x has b_id entries that must exist in table b then you can by pass one join and use the query below:
SELECT b.id, COUNT(1)
FROM a,x,c
WHERE a.id = <YOUR_ID_FOR_A>
AND a.id = x.id
AND x.b_id = d,b_id
GROUP BY b.id
EDIT: Corrected the typo, changed . to , as column separator.
try
SELECT A.id, B.id, COUNT(B.id) AS cnt
FROM A
INNER JOIN X ON A.id = X.a_id
INNER JOIN B ON X.b_id= B.id
INNER JOIN D ON B.id = D.b_id
GROUP BY B.id