Changing a value in a column to another from the same column - mysql

I have a table named titles with 3 columns named titleID, price, and pubDate
I've been trying to change the price of a row to the same price as the row with the most recent pubDate
I have
UPDATE titles t
INNER JOIN titles t2
ON t.titleID = t2.titleID
SET
t.price = (
/*Returns the price of the titleID with the most recent date in pubID*/
SELECT t3.price FROM titles t3
ORDER BY t.pubDate DESC LIMIT 1)
WHERE t.titleID = 1001
The error I am getting is
Error Code: 1053. You can't specify target table t for update in FROM clause
How can I correctly change a value to a value from the same column

One workaround to this error is to use an update join:
UPDATE titles t1
INNER JOIN
(
SELECT titleID, MAX(pubDate) AS maxPubDate
FROM titles
GROUP BY titleID
) t2
ON t2.titleID = t1.titleID AND
INNER JOIN titles t3
ON t3.titleID = t1.titleID AND
t3.pubDate = t2.maxPubDate
SET
price = t3.price
WHERE
price <> t3.price;

Another solution is to add an outer query in the select statement:
UPDATE titles t
INNER JOIN titles t2
ON t.titleID = t2.titleID
SET
t.price = ( SELECT t1.price FROM (
SELECT t3.price
FROM titles t3
ORDER BY t.pubDate DESC LIMIT 1) as t1 )
WHERE t.titleID = 1001
For more details check: https://dev.mysql.com/doc/refman/8.0/en/update.html

Both of the above answers didn't give me what I was looking for but they really helped in pointing me in the right direction
Here's the code that finally changed the price, I think I was searching max date row incorrectly I think the first time on top of the other errors as well
UPDATE titles t1
INNER JOIN titles t2
ON t1.titleID = t2.titleID
SET t1.price = ( SELECT t4.price FROM (
SELECT t5.price
FROM titles t5
WHERE t5.pubDate = ( SELECT MAX(t3.pubDate)
FROM titles t3))
AS t4)
WHERE t1.titleID = 1001
Here's the code that fetches the price from the row with the max date
SELECT t5.price
FROM titles t1
WHERE t5.pubDate = ( SELECT MAX(t3.pubDate)
FROM titles t3 )

Related

Select from 1 table sum from 2 but 1 table has a AND condition

Thanks for assisting with the previous query (SQL Query that selects a column in table 1 and uses that to select sum in table 2) of SUM from 2 tables, I now have a additional Condition for 1 of the tables. I would like to add WHERE Group1 = 1 AND IN/OUT = 'OUT'
I have 3 tables,
Names ,Groups
Names ,Payments
Names ,Payments and IN/OUT
I want to only SUM the OUT Payments in Table 3, I am getting total payments only So FAR is have:
SELECT t1.name1, SUM(t2.sale2),SUM(t3.sale3)
FROM table1 t1 JOIN table2 t2 ON t1.name1 = t2.name2
JOIN table3 t3 ON t1.name1 = t3.name3
WHERE group1 = 1
GROUP BY t1.name1
i would also like to add a zero if there is no data to sum instead of removing the whole record, Currently if a name has no payments in Table 3 but has payments in table 2 it deletes the record.
Please check the query below =>
To Get OutPayment group by Name
SELECT t1.Names,SUM(t3.Payments) As OutPayment
FROM TABLE3 as t3
INNER JOIN TABLE1 as t1 ON t1.Names = t3.Names
INNER JOIN TABLE2 as t2 ON t1.Names = t2.Names
WHERE t1.GroupID = 1 AND t3.INOROUT=2 --INOROUT =2 is OUT and 1 is IN
GROUP BY t1.Names;
To Get TotalOutPayment
SELECT SUM(t3.Payments) As TotalOutPayment
FROM TABLE3 as t3
INNER JOIN TABLE1 as t1 ON t1.Names = t3.Names
INNER JOIN TABLE2 as t2 ON t1.Names = t2.Names
WHERE t1.GroupID = 1 AND t3.INOROUT=2; --INOROUT =2 is OUT and 1 is IN
Note: Code is in DBFiddle too Check the Demo Query Link

How to get increment num of row in sorted table to use in another table?

i just want to find someone can help me.
I have two tables:
first:
id,parent_id,level
second:
id,name
I want to correct sort the datatree by name. Of course i can sort it by (level, parent, name) and next get parent_id associative array to print it in the recursion.
But i can see, what if i'm storing not just level, but delta between relative and absolute level, i can get tree without creating associative array, when sort it in (delta_level, parent_id, id).
Of course we need ID for that! The id determines date_add field. But what if i need sorting by name same method?
First query we sort table2 with autoincrement #num := #num + 1, after that - i need somehow join results to table1.
table1
id,parent_id,delta_level
table2 (sorted by name ASC)
id,name,num
I need to get every table1 row in a view like (num,parent_num,delta_level)
Can someone help?
FIRST EDIT:
SET #num1 = 0;
SET #num2 = 0;
SELECT
t2.`name`,
t1.`category_id`,
t1.`path_id`,
t2.`index`,
t3.`index` `parent_index`,
t1.`level` `delta_level`,
t2.`level` `level`
FROM
ht_category_path t1
LEFT JOIN (
SELECT
#num1 := #num1 + 1 `index`,
t1.`category_id`,
t2.`name`,
t3.`level`
FROM
ht_category t1
INNER JOIN
ht_category_description t2 ON t1.category_id = t2.category_id AND t2.language_id = 1
INNER JOIN
ht_category_path t3 ON t3.category_id = t1.category_id AND t3.path_id = t1.category_id
ORDER BY
t2.`name` ASC
) t2 ON t2.category_id = t1.category_id
LEFT JOIN (
SELECT
#num2 := #num2 + 1 `index`,
t1.`category_id`,
t2.`name`
FROM
ht_category t1
INNER JOIN
ht_category_description t2 ON t1.category_id = t2.category_id AND t2.language_id = 1
ORDER BY
t2.`name` ASC
) t3 ON t3.category_id = t1.path_id
WHERE
t1.`level` = 0
ORDER BY
t3.`index` ASC,
t2.`level` ASC,
t2.`index` ASC
Given query works fine. Next question - HOW TO OPTIMIZE THAT QUERY AS WELL?

compare two values in sql with eachother

I have a database of magento with double images, I want to delete those but first i got to detect them with a sql query.
I have tried this code
select t1.VALUE from catalog_product_entity_media_gallery t1
join catalog_product_entity_media_gallery t2 on (t1.value = t2.value)
this one:
select * from catalog_product_entity_media_gallery where value=value
and this one:
select
*
from
(
select
value
from
catalog_product_entity_media_gallery
group by
value
having count(*) > 1
) as t
inner join catalog_product_entity_media_gallery on (
catalog_product_entity_media_gallery.value = t.value
)
the first gives an error and the second- and third one gives back every product.
Give this one a try:
select
*
from (
select
entity_id,attribute_id,value,
MIN(value_id) value_id
from catalog_product_entity_media_gallery
group by
entity_id,attribute_id,value
having COUNT(*) > 1
) A1
inner join catalog_product_entity_media_gallery A2 on
A1.entity_id = A2.entity_id and
A1.attribute_id = A2.attribute_id and
A1.value = A2.value and
A1.value_id = A2.value_id
You can just get the min id by value, then except the other records:
select
*
from catalog_product_entity_media_gallery t1
where exists
( select * from
(select value, min(value_id) as min_value_id
from catalog_product_entity_media_gallery
group by value
) as t2
where t1.value=t2.value and t1.value_id=t2.min_value_id
)
If you want delete the duplicated rows, change exists to not exists.
delete
from catalog_product_entity_media_gallery t1
where not exists
( select * from
(select value, min(value_id) as min_value_id
from catalog_product_entity_media_gallery
group by value
) as t2
where t1.value=t2.value and t1.value_id=t2.min_value_id
)

complex sql statement to different rows

I have a simple table which has 4 fields:
indexID
UserID
text_1
IsFinal
This table may have multiple values for each UserID, and IsFinal field can have only a single value 1 or 0.
What I'm trying to do is to make a select statement which will return the user IDs if IsFinal only equal 0. The problem there may be multiple records for the same userID, some having IsFinal equal to 0 and only 1 with IsFinal equal to 1.
My problem here is this: for every UserID, if it has a record with Isfinal = 1, I want to ignore all records with the same UserID, otherwise I want to return its records. I don't know if that can be done by SQL statement only or not.
Seems like you want an anti-join, i.e. you first need to establish which user IDs have IsFinal = 1, then use that result set to return all user IDs not in that list.
There are various ways to implement an anti-join.
NOT IN:
SELECT *
FROM atable
WHERE UserID NOT IN (
SELECT UserID
FROM atable
WHERE IsFinal = 1
);
NOT EXISTS:
SELECT *
FROM atable t1
WHERE NOT EXISTS (
SELECT *
FROM atable t2
WHERE t1.UserID = t2.UserID
AND t2.IsFinal = 1
);
LEFT JOIN + WHERE IS NULL:
a)
SELECT *
FROM atable t1
LEFT JOIN (
SELECT *
FROM atable
WHERE IsFinal = 1
) t2 ON t1.UserID = t2.UserID
WHERE t2.UserID IS NULL;
b)
SELECT *
FROM atable t1
LEFT JOIN atable t2
ON t1.UserID = t2.UserID AND t2.IsFinal = 1
WHERE t2.UserID IS NULL;
It may so happen that they will be equally efficient in your database, but it still may be a good idea to test each of them to at least avoid ending up with one that performs worse than the others.
I think this is what you are looking for:
SELECT a.*
FROM translations a
INNER JOIN (SELECT UserID FROM translations WHERE IsFinal = 1) b
ON a.UserID = b.UserID
WHERE IsFinal = 0;
TRY ( not tested )
SELECT t1.* FROM table t1
INNER JOIN table t2 USING(indexID)
WHERE t1.IsFinal <>1
GROUP BY t1.UserID

UPDATE table with SELECT from another but with a field being SUM(someField)

Basically I have something like this:
UPDATE
Table
SET
Table.col1 = other_table.col1,
FROM
Table
INNER JOIN
other_table
ON
Table.id = other_table.id
The problem is that I would like to update col1 with the select being like:
SELECT SUM(col1) FROM other_table WHERE Table.id = other_table.id AND period > 2011
Edit
Correct Answer:
UPDATE bestall
INNER JOIN (SELECT bestid,SUM(view) as v,SUM(rawView) as rv
FROM beststat
WHERE period > 2011 GROUP BY bestid) as t1
ON bestall.bestid = t1.bestid
SET view = t1.v, rawview = t1.rv
You can't use aggregates directly in a set clause. One way around that is a subquery:
update your_table as yt
left join
(
select id
, count(*) as cnt
from other_table
where period < 4
group by
id
) as ot
on yt.id = ot.id
set col1 = coalesce(ot.cnt,0)
Example at SQL Fiddle.