MySQL UPDATE with SELECT statement - convert to JOIN - mysql

Problem: MySQL - Get the sum of IBB for each PersonID in Batting and update that IBB for each PersonID in Batting_Career
Could someone help me figure out the JOIN?
What I have that is not working:
UPDATE Batting_Career
SET Batting_Career.IBB = Batting.IBB WHERE PersonID IN
( SELECT DISTINCT
PersonID,
SUM(IBB) AS IBB
FROM
Batting
GROUP BY PersonID )
AND Batting_Career.PersonID = Batting.PersonID;
The Batting select statement works (...) - it gets me the sum of IBB in a column IBB for all playerIDs but when I add to the update using it does not work.
The error that I am getting is
Operand should contain 1 column(s)
I believe the rules are You can only select one column from such a query. Which mean I may have to Join the tables. Could anyone help me figure this out?

Aggregate in Batting and join to Batting_Career:
UPDATE Batting_Career bc
JOIN (
SELECT PersonID, SUM(IBB) as IBB
FROM Batting
GROUP BY PersonID
) b ON b.PersonID = bc.PersonID
SET bc.IBB = b.IBB;

I have written a query that will do your work :)
UPDATE Batting_Career t2
SET t2.IBB = t1.IBB where PersonID IN (
SELECT
PersonID,
SUM(IBB) AS IBB
FROM
Batting
WHERE
PersonID IN(
SELECT DISTINCT
PersonID
FROM
Batting
)
GROUP BY
PersonID
) t1
WHERE
t2.PersonID = t1.PersonID;

Related

SQL trying to use a column from a joined table in a subquery

Here is what I currently have which returns 3 columns for patient_id, group_concat_1, and group_concat_2:
SELECT patient_id,
(SELECT GROUP_CONCAT(column1) FROM
table1 where patient_id = patient.id
) group_concat_1,
(SELECT GROUP_CONCAT(column1) FROM
table2 where patient_id = patient.id
) group_concat_2
FROM patient
However, I need to return a single column with group_concat_1 and group_concat_2 combined, so I tried this:
SELECT patient_id,
SELECT CONCAT(group_concat_1, group_concat_2) FROM (
(SELECT GROUP_CONCAT(column1) FROM
table1 where patient_id = patient.id
) group_concat_1,
(SELECT GROUP_CONCAT(column1) FROM
table2 where patient_id = patient.id
) group_concat_2
)
FROM patient
But his clearly doesn't work since now it can't find patient.id in the inner subquery. Any advice? Thanks!
You can concatenate directly the 2 columns:
SELECT p.patient_id,
CONCAT(
(SELECT GROUP_CONCAT(column1) FROM table1 where patient_id = p.patient.id),
(SELECT GROUP_CONCAT(column1) FROM table2 where patient_id = p.patient.id)
)
FROM patient p
I'm pretty sure you want concat_ws() for this purpose:
SELECT patient_id,
CONCAT_WS(','
(SELECT GROUP_CONCAT(t1.column1) FROM table1 t1 where t1.patient_id = p.id
),
(SELECT GROUP_CONCAT(t2.column1) FROM table2 t2 where t2.patient_id = p.id
)
) as combined
FROM patient p;
There are two reasons:
You can distinguish between the last element from table1 and the first from `table2.
If one of the tables has no matching values, this returns the results from the other.
Also note that I added table aliases and qualified column names. This is quite important when working with queries that have multiple table references -- it helps prevent some very hard to debug errors.
I should add that your original query would run in most databases. MySQL and Oracle happen to be two that don't understand nested correlation clauses.

How to retrieve all members from a transitive relationship through one SQL query [duplicate]

I have a table with following structure
Table name: matches
That basically stores which product is matching which product. I need to process this table
And store in a groups table like below.
Table Name: groups
group_ID stores the MIN Product_ID of the Product_IDS that form a group. To give an example let's say
If A is matching B and B is Matching C then three rows should go to group table in format (A, A), (A, B), (A, C)
I have tried looking into co-related subqueries and CTE, but not getting this to implement.
I need to do this all in SQL.
Thanks for the help .
Try this:
;WITH CTE
AS
(
SELECT DISTINCT
M1.Product_ID Group_ID,
M1.Product_ID
FROM matches M1
LEFT JOIN matches M2
ON M1.Product_Id = M2.matching_Product_Id
WHERE M2.matching_Product_Id IS NULL
UNION ALL
SELECT
C.Group_ID,
M.matching_Product_Id
FROM CTE C
JOIN matches M
ON C.Product_ID = M.Product_ID
)
SELECT * FROM CTE ORDER BY Group_ID
You can use OPTION(MAXRECURSION n) to control recursion depth.
SQL FIDDLE DEMO
Something like this (not tested)
with match_groups as (
select product_id,
matching_product_id,
product_id as group_id
from matches
where product_id not in (select matching_product_id from matches)
union all
select m.product_id, m.matching_product_id, p.group_id
from matches m
join match_groups p on m.product_id = p.matching_product_id
)
select group_id, product_id
from match_groups
order by group_id;
Sample of the Recursive Level:
DECLARE #VALUE_CODE AS VARCHAR(5);
--SET #VALUE_CODE = 'A' -- Specify a level
WITH ViewValue AS
(
SELECT ValueCode
, ValueDesc
, PrecedingValueCode
FROM ValuesTable
WHERE PrecedingValueCode IS NULL
UNION ALL
SELECT A.ValueCode
, A.ValueDesc
, A.PrecedingValueCode
FROM ValuesTable A
INNER JOIN ViewValue V ON
V.ValueCode = A.PrecedingValueCode
)
SELECT ValueCode, ValueDesc, PrecedingValueCode
FROM ViewValue
--WHERE PrecedingValueCode = #VALUE_CODE -- Specific level
--WHERE PrecedingValueCode IS NULL -- Root

How to select rows which have the biggest value of a column?

I don't know if my title is understandable or not, may be someone can help edit my title?
All I want to do is, for example:
I have a table like this
Engineering appears 5 times with different article_category_abbr, and I want to select only one row with the biggest value of num.
Here, it will be Engineering-ENG-192, and Geriatrics&Gerontology will be Geriatrics&Gerontology-CLM-26
But I don't know how to do it on the whole table using mysql
Join your table to a subquery which finds the greatest num value for each sc group.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT sc, MAX(num) AS max_num
FROM yourTable
GROUP BY sc
) t2
ON t1.sc = t2.sc AND
t1.num = t2.max_num;
You can have a subquery that gets the largest value for each sc and the resulting rows will then be joined with the table itself based from two columns - sc and num.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT sc, MAX(num) AS Num
FROM tableName
GROUP BY sc
) b ON a.sc = b.sc
AND a.num = b.num
Here's a Demo
USE MAX function and GROUP BY like this. Here is more information.
SELECT myID, classTitle, subField, MAX(score) FROM myTable GROUP BY myID, classTitle, subField

Summing union of counts in a correlated subquery

I have a member table that has a foreign key to various other tables. I am checking each of these tables to see if a member has one or more records in it and if they do I return a value, if not I return 0, this is all selected as a total. This is mostly working except in one place. I need to check two tables and if there is a record in either of them the query will return 5,0 otherwise. I am trying to use a SUM of counts with a UNION for this but I am not getting the results I expect, it seems like only the first record in each of the two tables is being selected and that is it.
I am using(after some help ) a series of correlated queries with COUNT() and IF() to get the total. Here is what part of the query looks like :
SELECT
member_id,
(SELECT IF(COUNT(member_id)>0,10,0) FROM tbl1 WHERE member_id = m.member_id)
+
(SELECT IF(SUM(tbl_count) > 0,5,0) FROM
(
SELECT member_id, COUNT(tbl2.id) as tbl_count
FROM tbl2
UNION ALL
SELECT member_id, COUNT(tbl3.id) as tbl_count
FROM tbl3
) sub WHERE sub.member_id = m.member_id
)
as total
FROM members m
The actual query joins another 10 or so tables, again the only part that is not working is the SUM of COUNT with the UNION. Could anyone suggest how I should do this? Any help would be very much appreciated. Thank you very much.
I think you are looking for this:
First try (FAIL)
SELECT
member_id,
(SELECT IF(COUNT(member_id)>0,10,0) FROM tbl1 WHERE member_id = m.member_id)
+
(SELECT IF(SUM(tbl_count) > 0,5,0) FROM
(
SELECT COUNT(*) as tbl_count
FROM tbl2
WHERE tbl2.member_id = m.member_id
UNION ALL
SELECT COUNT(*) as tbl_count
FROM tbl3
WHERE tbl3.member_id = m.member_id
) sub
)
as total
FROM members m
Second try:
SELECT
member_id,
(SELECT IF(COUNT(member_id)>0,10,0) FROM tbl1 WHERE member_id = m.member_id)
+
(SELECT IF(SUM(tbl_count) > 0,5,0) FROM
(
SELECT member_id, COUNT(*) as tbl_count
FROM tbl2
GROUP BY member_id
UNION ALL
SELECT member_id, COUNT(*) as tbl_count
FROM tbl3
GROUP BY member_id
) sub
WHERE sub.member_id = m.member_id
)
as total
FROM members m
If the query has 10 joins maybe you have to think about refactoring... :-)

Selecting top result from SQL

This is i think a simple problem but i can't seem to solve it.
I want to select the newest result from a table and join it with a single element in another table.
To put it better, here's a simple schema:
Table 1 - Person
personId -PK - INT - AUTO ID
name - VARCHAR
Table 2 - Event
eventId - PK - INT - AUTO ID
personId - FK
timestamp - DATETIME
event - ENUM ('Went Out', 'Came back')
What I'd like to do is return a list of all people and the latest action each person performed
Example Result:
name| personId | timestamp | eventId | event
bob | 1 | 2011-08-7 3 | 'went out'
I did a simple query joining the two tables and then did a group by personId and order by timestamp but the result that was returned was always the first action for the person, not their latest.
Any Ideas?
SELECT
t1.Name,
t1.PersonId,
t2.TimeStamp,
t2.EventId,
t2.Event
FROM Table1 t1
INNER JOIN Table2 t2 ON t2.PersonId = t1.PersonID
INNER JOIN (SELECT
PersonId,
MAX(TimeStamp) as LastEventDateTime
FROM Table2
GROUP BY PersonID) LE
ON LE.PersonID = t2.PersonID
AND LE.LastEventDateTime = t2.TimeStamp
SELECT p.name, p.personId, e.timestamp, e.eventId, e.event
FROM person p
INNER JOIN Event e
ON e.eventId =
( SELECT MAX(eventId)
FROM Event
WHERE personId = p.personId
GROUP BY personId
LIMIT 1 )
OR
SELECT p.Name, p.ID, me.timestamp, me.ID, me.event
FROM person p
INNER JOIN (
SELECT id, timestamp, event
FROM Event
WHERE personId = p.ID
ORDER BY timestamp DESC LIMIT 1
) me
ON p.ID = me.id
PS: sorry but can't test both queries right now
you'd want to do an
ORDER by `timestamp` DESC
(desc from descending) to get the highest timestamp value instead of the lowest
The ANSI standard way would be:
select name, personid, timestamp, eventid, event
from person
join event on event.personid=person.personid
and event.timestamp=(select max(timestamp) from event e2
where e2.personid=person.personid)
I haven't used MySQL in a while and I don't have an installation handy, but you might get what you want with:
select name, personid, timestamp, eventid, event
from person
join event on event.personid=person.personid
group by personid
order by personid, timestamp desc
It's non-standard because by the standard, anything in the select must be in the group-by or be an aggregate, and here we don't want to do either. But as I recall MySQL doesn't require that, so I'd give this a whirl and see what happens.
An alternative solution, making use of a covered key, assumes that order by Id would yield the same results as order by timestamp
SELECT p.Name, p.ID, me.timestamp, me.ID, me.event
FROM person p
JOIN (
SELECT personId, MAX(ID) id
FROM Event
WHERE personId = p.ID
GROUP BY personId
) me
ON p.ID = me.id
Order by timestamp is more natural and probably safer, but this is quicker.