I'm trying to update a column of a table so that is equal to the count of something in another table. Like this:
UPDATE TABLE
SET TOTAL = (SELECT COUNT(f1)
FROM TABLE2
GROUP BY f2);
But I keep getting sub query returns more than 1 row, and I can't think of how to fix it.
UPDATE (copied from the comment)
f2 is the relation between TABLE and TABLE2 – Thomasd d
Based on your comment
f2 is the relation between TABLE and TABLE2
you probably want something like this
UPDATE TABLE T1, (SELECT f2, COUNT(F1) cnt FROM TABLE2 GROUP BY f2) T2
SET T1.TOTAL = T2.cnt
WHERE T1.f2=T2.f2
adapt T1.f2 if necessary
UPDATE t1
SET total = ( SELECT COUNT(f1)
FROM t2
WHERE t1.f2 = t2.f2 );
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=91de17deff657f66fa54b42fe20ed3c5
Add WHERE total IS NULL if you do not need to recalculate values for rows which have a value already.
Your subquery is returning multiple values and your SET statement is only expecting one. This might fix your code if that is what you are looking for.
UPDATE TABLE
SET TOTAL = (SELECT COUNT(f1)
FROM TABLE2)
Related
I have an empty table (t1) and I want to insert or update the t1.uid column from another table's (t2) GROUP BY uid values.
So far I have tried like this:
UPDATE table1 t1 JOIN
(SELECT uid FROM table2 GROUP BY uid) t2
SET t1.uid = t2.uid;
but it's not working for me.
N.B. I've got a massive data set for which group by (uid from table-t2) results giving me total 1114732 results which I have to insert/update in t1 table's uid column.
Please try this:
Insert into table1(uid)
select distinct uid from table2
If table1 is empty, then UPDATE is not the correct verb. Would this suit your needs?
INSERT into table1 SELECT distinct uid from table2;
INSERT ... SELECT docs
I need to update a table consisting of million rows
there are two tables table1 and table2
SELECT ID
FROM (
select ID from table1 where<condition>
) as result1
INNER JOIN table2 ON result1.field=table2.field
GROUPBY table2.field
HAVING <condtion>
and on this #resultset1 ID, I have to update table 1
UPDATE table1
SET x=true
where ID EXISTS IN (#resultset1)
there are millions of rows in both table. how do i do it?
And Can anyone say whats wrong with this, i am trying some alternative over join
UPDATE table1 t1
SET x=true
WHERE <condition> AND EXISTS(
SELECT* FROM (
SELECT *
FROM table2 t2
WHERE t2.field = t1.field
) AS result
WHERE<condition on resultset field>
);
Output the results of the first query to a file.
Convert the output to update statements, one update per id (using sed or whatever)
Split the statements into separate files, maybe a 1000 per file (using split or whatever)
Run each file as an sql script with a pause (eg 10 seconds) between each execution (to allow logs to update etc and spread the load), using a simple runner script the loops over the files
Why can't you simply do like below. Though I don't really see a need of group by and having provided if this is your actual query.
UPDATE table1
SET x=true
where ID IN (
SELECT ID
FROM (
select ID from table1 where<condition>
) as result1
INNER JOIN table2 ON result1.field=table2.field
GROUPBY table2.field
HAVING <condtion>
)
Another good option would be JOIN both result set and do the UPDATE like
UPDATE table1 t1
JOIN
(
SELECT ID
FROM (
select ID from table1 where<condition>
) as result1
INNER JOIN table2 ON result1.field=table2.field
GROUPBY table2.field
HAVING <condtion>
) X ON t1.ID = X.ID
SET t1.x=true
EDIT:
You can as well store the result of fist query in a temporary table (As already suggested by a_horse_with_no_name) and then do the UPDATE using a JOIN with the temporary table. Somethig like below
create temporary table idtemp(ID INT);
insert into idtemp
SELECT ID
FROM (
select ID from table1 where<condition>
) result1
INNER JOIN table2 ON result1.field=table2.field
GROUPBY table2.field
HAVING <condtion>
Finally do the update like
UPDATE table1 t1
JOIN idtemp it ON t1.ID = it.ID
SET t1.x=true
I've got a weird one, and I don't know if it's my syntax (which seems straightforward) or a bug (or just unsupported).
Here's my query that works but is needlessly slow:
UPDATE table1
SET table1column1 =
(SELECT COUNT(DISTINCT table2column1) FROM table2view WHERE table2column1 <= (SELECT table2column1 FROM table2 WHERE table2.id = table1.id) )
/
(SELECT COUNT(DISTINCT table2column1) FROM table2)
+ (SELECT COUNT(DISTINCT table2column2) FROM table2view WHERE table2column2 <= (SELECT table2column2 FROM table2 WHERE table2.id = table1.id) )
/
(SELECT COUNT(DISTINCT table2column2) FROM table2)
+ (SELECT COUNT(DISTINCT table2column3) FROM table2view WHERE table2column3 <= (SELECT table2column3 FROM table2 WHERE table2.id = table1.id) )
/ (SELECT COUNT(DISTINCT table2column3) FROM table2);
It's just the sum of three percentiles (of table2column1, table2column2, and table2column3) with duplicates removed.
Here's where it gets weird. I have to use a view for this to work on the subquery with the WHERE or it will only UPDATE the first row of table1, and set the rest of the rows' table1column1 to 0. That table2view is an exact duplicate of table2. Yeah, weird.
If I don't use DISTINCT, I can do it without the view. Does that make sense? Note: I have to have DISTINCT because I have lots of duplicates.
I tried making it SELECT only from the view, but that slowed it down worse.
Does anyone know what the problem is and the best way to rework this query so it doesn't take so long? It's in a TRIGGER, and the updated data is pretty on demand.
Many thanks in advance!
Details
I'm testing the speed in phpMyAdmin's command line.
I'm pretty sure the degradation is coming from the view since the more of the view and the less of the actual table I use, the slower it gets.
When I do the one without DISTINCT, it's lightning fast.
Only works on views?
OK, so I just set up a copy of table2. I tried first to do the original query substituting the view with the copy. No go.
I tried to do the query below with the copy instead of the view. No go.
Hopefully the introduction of these constants will better show what I'm trying to do.
SET #table2column1_distinct_count = (SELECT COUNT(DISTINCT table2column1) FROM table2);
SET #table2column2_distinct_count = (SELECT COUNT(DISTINCT table2column2) FROM table2);
SET #table2column3_distinct_count = (SELECT COUNT(DISTINCT table2column3) FROM table2);
UPDATE table1, table2
SET table1.table1column1 = (SELECT COUNT(DISTINCT table2column1) FROM table2view WHERE table2column1 <= table2.table2column1) / #table2column1_distinct_count
+ (SELECT COUNT(DISTINCT table2column2) FROM table2view WHERE table2column2 <= table2.table2column2) / #table2column2_distinct_count
+ (SELECT COUNT(DISTINCT table2column3) FROM table2view WHERE table2column3 <= table2.table2column3) / #table2column3_distinct_count
WHERE table1.id = table2.id;
Again, when I use table2 instead of the table2view, it only updates the first row properly and sets all other rows' table1.table1column1 = 0.
Math
I'm trying to set table1.table1column1 = to the sum of the percentiles of table2column1, table2column2, and table2column3 by id.
I do a percentile by (counting the distinct values of a table2columnX <= to the current table2columnX ) / (the total count of distinct table2columnXs).
I use DISTINCT to get rid of the excessive duplicates.
View
Here's the SELECT for the view. Does this help?
CREATE VIEW myTable.table2view AS SELECT
table2.table2column1 AS table2column1,
table2.table2column2 AS table2column2,
table2.table2column2 AS table2column3,
FROM table2
GROUP BY table2.id;
Is there something special about the GROUP BY in the view's SELECT that makes this work (that I'm not seeing)?
I would probably say that the query is slow because it is repeatedly accessing the table when the trigger fires.
I am no SQL expert but I have tried to put together a query using temporary tables. You can see if it helps speed up the query. I have used different but similar sounding column names in my code sample below.
EDIT : There was a calculation error in my earlier code. Updated now.
SELECT COUNT(id) INTO #no_of_attempts from tb2;
-- DROP TABLE IF EXISTS S1Percentiles;
-- DROP TABLE IF EXISTS S2Percentiles;
-- DROP TABLE IF EXISTS S3Percentiles;
CREATE TEMPORARY TABLE S1Percentiles (
s1 FLOAT NOT NULL,
percentile FLOAT NOT NULL DEFAULT 0.00
);
CREATE TEMPORARY TABLE S2Percentiles (
s2 FLOAT NOT NULL,
percentile FLOAT NOT NULL DEFAULT 0.00
);
CREATE TEMPORARY TABLE S3Percentiles (
s3 FLOAT NOT NULL,
percentile FLOAT NOT NULL DEFAULT 0.00
);
INSERT INTO S1Percentiles (s1, percentile)
SELECT A.s1, ((COUNT(B.s1)/#no_of_attempts)*100)
FROM (SELECT DISTINCT s1 from tb2) A
INNER JOIN tb2 B
ON B.s1 <= A.s1
GROUP BY A.s1;
INSERT INTO S2Percentiles (s2, percentile)
SELECT A.s2, ((COUNT(B.s2)/#no_of_attempts)*100)
FROM (SELECT DISTINCT s2 from tb2) A
INNER JOIN tb2 B
ON B.s2 <= A.s2
GROUP BY A.s2;
INSERT INTO S3Percentiles (s3, percentile)
SELECT A.s3, ((COUNT(B.s3)/#no_of_attempts)*100)
FROM (SELECT DISTINCT s3 from tb2) A
INNER JOIN tb2 B
ON B.s3 <= A.s3
GROUP BY A.s3;
-- select * from S1Percentiles;
-- select * from S2Percentiles;
-- select * from S3Percentiles;
UPDATE tb1 A
INNER JOIN
(
SELECT B.tb1_id AS id, (C.percentile + D.percentile + E.percentile) AS sum FROM tb2 B
INNER JOIN S1Percentiles C
ON B.s1 = C.s1
INNER JOIN S2Percentiles D
ON B.s2 = D.s2
INNER JOIN S3Percentiles E
ON B.s3 = E.s3
) F
ON A.id = F.id
SET A.sum = F.sum;
-- SELECT * FROM tb1;
DROP TABLE S1Percentiles;
DROP TABLE S2Percentiles;
DROP TABLE S3Percentiles;
What this does is that it records the percentile for each score group and then finally just updates the tb1 column with the requisite data instead of recalculating the percentile for each student row.
You should also index columns s1, s2 and s3 for optimizing the queries on these columns.
Note: Please update the column names according to your db schema. Also note that each percentile calculation has been multiplied by 100 as I believe that percentile is usually calculated that way.
I am trying to think of a query that will search a table for matching values across 2 fields.
For example, what would be the query to identity tbl_id 202 and tbl_id 203 as having matching values in both tbl_row and tbl_col?
Thanks
tatty27
This isn't the cleanest way to do it, as it'll double-up on the number of rows returned, but it'll show you the dupes. Assuming the table name is tbl:
select t1., t2. from tbl t1, tbl t2 where t1.tbl_row = t2.tbl_row and t1.tbl_col = t2.tbl_col;
select distinct t1.tbl_id
from
tbl as t1
inner join tbl as t2
on t1.tbl_row = t2.tbl_row
and t1.tbl_col = t2.tbl_col
and t1.tbl_id <> t2.tbl_id
Select T1.tbl_id, T2.tbl_id
FROM Table T1, Table T2
WHERE T1.tbl_row = T2.tbl_row and T1.tbl_col = T2.tbl_col and T1.tbl_id <> T2.tbl_id
I use a MySQL DB, and I would like to update a field in a table based on another. Something like:
UPDATE table1
SET field1 = table2.id
WHERE field2 IN (
SELECT table2.name
FROM table2
);
I know that this query wouldn't work, but here is the idea. Is that even possible to do?
You can use a correlated sub query as below. This assumes there will be exactly one matching value returned. It will raise an error if more than one matching value is returned or set the field to null if zero are returned. If that last behaviour isn't desirable you will need a where clause.
UPDATE table1
SET field1 = (SELECT DISTINCT table2.ValueColumn
FROM table2
WHERE table2.JoinColumn = table1.JoinColumn)
Edit
To review records with 0 or more than 1 matches you could use
SELECT table1.JoinColumn, COUNT(DISTINCT table2.ValueColumn)
FROM table1
LEFT JOIN table2
ON table2.JoinColumn = table1.JoinColumn
GROUP BY table1.JoinColumn
HAVING COUNT(DISTINCT table2.ValueColumn) <> 1