Here is my query:
UPDATE student_tests,
(SELECT SUM(olc_sta_i_points_earned) AS total, olc_sta_i_stt_num FROM student_answers
JOIN student_tests ON olc_sta_i_stt_num = olc_stt_i_num
) AS a
SET student_tests.olc_stt_i_score = a.total
WHERE a.olc_sta_i_stt_num = student_tests.olc_stt_i_num
There are no errors but it says zero rows are affected.
Basically I have two tables: student_tests and student_answers the test id is mapped to the student_answers tables. I want a subquery where I can sum all the student answers for the specific test id and then update the score column in the student_tests table in the tests table.
Am i doing something wrong with the where clause here? or is it something else?
You should phrase this as an update/join explicitly, rather than having the join condition in the where clause.
Your problem is that you have no group by in the subquery. The extra join to student_tests seems unnecessary, so try this:
UPDATE student_tests s JOIN
(SELECT SUM(a.olc_sta_i_points_earned) AS total, a.olc_sta_i_stt_num
FROM student_answers a
GROUP BY a.olc_sta_i_stt_num
) AS a
ON a.olc_sta_i_stt_num = t.olc_stt_i_num
SET s.olc_stt_i_score = a.total
Related
I have a complex query which results in a table which includes a time column. There are always two rows with the same time:
The result also contains a value column. The value of two rows with the same time is always different.
I now want to extend the query to join the rows with the same time together. So my thought was to join the derived table like this:
SELECT A.time, A.value AS valueA, B.value as valueB FROM
(
OLD_QUERY
) AS A INNER JOIN A AS B ON
A.time=B.time AND
A.value <> B.value;
However, the JOIN A AS B part of the query does not work. A is not recognized as the derived table. MySQL is searching for a table A in the database and does not find it.
So the question is: How can I join a derived table?
You cannot join a single reference to a table (or subquery) to itself; a subquery must be repeated.
Example: You cannot even do
SELECT A.* FROM sometable AS A INNER JOIN A ...
The A after the INNER JOIN is invalid unless you actually have a real table called A.
You can insert the subquery's results into another table, and use that; but it cannot be a true TEMPORARY table, as those cannot be joined to themselves or referenced twice at all in almost any query. _By referenced twice, I mean joined, unioned, used as an "WHERE IN" subquery when it is already referenced in the FROM.
If nothing else distinguishes the rows, you can just use aggregation to get the two values:
select time, min(value), max(value)
from (<your query here>) a
group by time;
In MySQL 8+, you can use a cte:
with a as (
<your query here>
)
select a1.time, a1.value, a2.value
from a a1 join
a a2
on a1.time = a2.time and a1.value <> a2.value;
I want to update a field, let's call it 'field_A', in table 'table_A' with the maximum value that exists of field 'field_B' in 'table_B', but only IF there is a max value for that field 'field_B' in table 'table_B'.
Table 'table_B' has a 'reference' field which contains the 'id' of the table_A record we want to update.
Now I have the following query, which works perfectly.
UPDATE table_A a SET a.field_A = (SELECT MAX(b.field_B)
FROM table_B WHERE b.reference = a.id)
WHERE a.id IN (
SELECT reference
FROM table_B
GROUP BY reference
HAVING COUNT(reference) > 0
)
So it only updates field_A IF there are records found for that reference because I don't want to end up setting fields 'field_A' to zero when no related records were found.
As I said before, this query already works perfectly, but now I have to run a query for table_B two times, which seems a little bit inefficient and it is probably possible to do it with only 1 join statement but I can't seem to tackle the issue.
Since this query has to cross reference a lot, really a lot, of records, performance is really an issue here.
With these two nested statements, your UPDATE statements seems quite
inefficient to me. Try this SQL statement below, that should do the job.
SQL Fiddle here: http://sqlfiddle.com/#!2/5825a/2
UPDATE table_A a1
JOIN
(
SELECT a.id as id, max(b.field_B) as max_val
FROM
table_A a
LEFT JOIN table_B b ON a.id = b.reference
GROUP BY a.id
) t on a1.id = t.id
SET
a1.field_A = t.max_val
WHERE
(t.max_val IS NOT NULL)
I have a query:
SELECT DISTINCT *
FROM table1 AS s
LEFT OUTER JOIN table2 AS t
ON s.s_id = t.t_id
WHERE (
s.body LIKE '%string%'
OR t.name LIKE '%string%'
)
ORDER BY s.time DESC
but I am still getting duplicate tuples. Why is this?
GROUP BY s.s_id
was the solution.
The result doesn't contain absolutely equal rows here so technically they aren't duplicated
To get rid of duplicates, you need to SELECT DISTINCT or GROUP BY only fields you need non-duplicated and outer join the rest data in subquery on the corresponding key values, taking only 1 (first or last or whatever) row from them.
What would be the best way to return one item from each id instead of all of the other items within the table. Currently the query below returns all manufacturers
SELECT m.name
FROM `default_ps_products` p
INNER JOIN `default_ps_products_manufacturers` m ON p.manufacturer_id = m.id
I have solved my question by using the DISTINCT value in my query:
SELECT DISTINCT m.name, m.id
FROM `default_ps_products` p
INNER JOIN `default_ps_products_manufacturers` m ON p.manufacturer_id = m.id
ORDER BY m.name
there are 4 main ways I can think of to delete duplicate rows
method 1
delete all rows bigger than smallest or less than greatest rowid value. Example
delete from tableName a where rowid> (select min(rowid) from tableName b where a.key=b.key and a.key2=b.key2)
method 2
usually faster but you must recreate all indexes, constraints and triggers afterward..
pull all as distinct to new table then drop 1st table and rename new table to old table name
example.
create table t1 as select distinct * from t2; drop table t1; rename t2 to t1;
method 3
delete uing where exists based on rowid. example
delete from tableName a where exists(select 'x' from tableName b where a.key1=b.key1 and a.key2=b.key2 and b.rowid >a.rowid) Note if nulls are on column use nvl on column name.
method 4
collect first row for each key value and delete rows not in this set. Example
delete from tableName a where rowid not in(select min(rowid) from tableName b group by key1, key2)
note that you don't have to use nvl for method 4
Using DISTINCT often is a bad practice. It may be a sing that there is something wrong with your SELECT statement, or your data structure is not normalized.
In your case I would use this (in assumption that default_ps_products_manufacturers has unique records).
SELECT m.id, m.name
FROM default_ps_products_manufacturers m
WHERE EXISTS (SELECT 1 FROM default_ps_products p WHERE p.manufacturer_id = m.id)
Or an equivalent query with IN:
SELECT m.id, m.name
FROM default_ps_products_manufacturers m
WHERE m.id IN (SELECT p.manufacturer_id FROM default_ps_products p)
The only thing - between all possible queries it is better to select the one with the better execution plan. Which may depend on your vendor and/or physical structure, statistics, etc... of your data base.
I think in most cases EXISTS will work better.
I'm trying to sync store ids on newtable with the ids from the maintable here:
UPDATE newtable t SET t.store_id = (SELECT store_id FROM maintable s
WHERE t.state = s.state AND s.city = t.city AND t.name = s.name)
Whenever a subquery returns more than one row it errors out with "Subquery returns more than 1 row", but when it returns zero rows the subquery is considered to have returned nothing so the store_id on newtable remains NULL. Nothing new here, it's just how it works.
I'd like to know if it's possible to let the subquery output the same as what it does when it has no matches when it has more than one matching row.
This way I'd get the store_id synced only for ONE matching row on the main table and skipped when more than one matching row comes out in the subquery.
I think you might be looking for a HAVING clause to force the query to match exactly once:
UPDATE newtable t
SET t.store_id = (
SELECT store_id
FROM maintable s
WHERE t.state = s.state
AND s.city = t.city
AND t.name = s.name
HAVING COUNT(*) = 1
)
That should make multiple matches behave the same as no matches. The HAVING clause is applied almost at the very end of the query process; if there are no matches from the WHERE or more than one match, then COUNT(*) = 1 will fail and the inner query will return nothing but if there is exactly one row then COUNT(*) = 1 will succeed and the inner query will return that single match.
You might consider putting a LIMIT 1 in your sub-query to better achieve what you are trying to accomplish, depending on your specific needs.
Otherwise, you should be able to get creative with IF or CASE:
UPDATE newtable t SET t.store_id = (
SELECT IF(num>1, NULL, storeid) FROM (
SELECT COUNT(*) AS num, storeid FROM maintable s WHERE t.state=s.state AND s.city=t.city AND t.name=s.name
)
)
Untested, but should get you in the ballpark.
UPDATE newtable t SET t.store_id = IFNULL((SELECT store_id FROM maintable s
WHERE t.state = s.state AND s.city = t.city AND t.name = s.name HAVING COUNT(*) = 1), t.store_id)
IFNULL(use_this_value_if_not_null,value_if_first_isnull)