Mysql update row value in table based on different row - mysql

I have the following table structure
TABLE A
Productid price groupId
1 100 A
2 99 A
3 0 A
4 50 B
5 49 B
6 0 B
I populate table A with prices from table B joining on Id. Sometimes table B doesn't have prices.
In cases were b doesn't have price I want to update the price to be another price from that same group, as I can't have a price of zero.
Is there an way to update table a price column using itself based on group? e.g. update productId 3 price to be the price of another product in it's group (1 or 2)
TABLE A after update
Productid price groupId
1 100 A
2 99 A
3 100 A
4 50 B
5 49 B
6 49 B
It seems silly but these are the business rules (it makes sense irl I simplified the problem for the example)
When I tried the following I got Error:
update 'Table A' t1
join (select price ,groupId from 'table A' where Price > 0 group by
groupId) as t2
on t1.groupId = t2.GroupId
SET t1.Price = t2.Price
(conn=58292) Can't reopen table: 'Table A'
I've thought of creating a third temporary table but that seems.... wrong? I am sure there must be a way to do this using update statement and joins

I would phrase the query as:
update tablea a
inner join (select groupId, max(price) price from tablea group by groupId) a1
on a1.groupId = a.groupId
set a.price = a1.price
where a.price = 0 and a1.price > 0
Notes:
the table name should be surrounded with single quotes (those stand for literal strings) - if your table name really contains spaces, then use backticks for quoting (or better, yet, fix the table name!)
I changed the subquery to make it a valid aggregation query - yours has non-aggregated columns that do not belong to the group by clause, which is not a good practice, and might generate errors, depending on the SQL mode of your database
In this demo on DB Fiddlde with your sample data, the content of the table after update is:
Productid | price | groupId
--------: | ----: | :------
1 | 100 | A
2 | 99 | A
3 | 100 | A
4 | 50 | B
5 | 49 | B
6 | 50 | B

Related

Remove continuous duplicated values with different IDs in MySQL

I know there is a ton of same questions about finding and removing duplicate values in mySQL but my question is a bit different:
I have a table with columns as ID, Timestamp and price. A script scrapes data from another webpage and saves it in the database every 10 seconds. Sometimes data ends up like this:
| id | timestamp | price |
|----|-----------|-------|
| 1 | 12:13 | 100 |
| 2 | 12:14 | 120 |
| 3 | 12:15 | 100 |
| 4 | 12:16 | 100 |
| 5 | 12:17 | 110 |
As you see there are 3 duplicated values and removing the price with ID = 4 will shrink the table without damaging data integrity. I need to remove continuous duplicated records except the first one (which has the lowest ID or Timestamp).
Is there a sufficient way to do it? (there is about a million records)
I edited my scraping script so it checks for duplicated price before adding it but I need to shrink and maintain my old data.
Since MySQL 8.0 you can use window function LAG() in next way:
delete tbl.* from tbl
join (
-- use lag(price) for get value from previous row
select id, lag(price) over (order by id) price from tbl
) l
-- join rows with same previous price witch will be deleted
on tbl.id = l.id and tbl.price = l.price;
fiddle
I am just grouping based on price and filtering only one record per group.The lowest id gets displayed.Hope the below helps.
select id,timestamp,price from yourTable group by price having count(price)>0;
My query is based on #Tim Biegeleisen one.
-- delete records
DELETE
FROM yourTable t1
-- where exists an older one with the same price
WHERE EXISTS (SELECT 1
FROM yourTable t2
WHERE t2.price = t1.price
AND t2.id < t1.id
-- but does not exists any between this and the older one
AND NOT EXISTS (SELECT 1
FROM yourTable t3
WHERE t1.price <> t3.price
AND t3.id > t2.id
AND t3 < t1.id));
It deletes records where exists an older one with same price but does not exists any different between
It could be checked by timestamp column if id column is not numeric and ascending.

How can I join these MYSQL tables?

I'm having 2 tables. Table A contains a list of people who booked for an event, table B has a list of people the booker from table A brings with him/her. Both tables have many colums with unique data that I need to do certain calculations on in PHP , and as of now I do so by doing queries on the tables with a recursive PHP function to resolve it. I want to simplify the PHP and reduce the amount of queries that come from this recursive function by doing better MYSQL queries but I'm kind of stuck.
Because the table has way to many columns I will give an Excerpt of table A instead:
booking_id | A_customer | A_insurance
1 | 134 | 4
Excerpt of table B:
id | booking_id | B_insurance
1 | 1 | 0
2 | 1 | 1
3 | 1 | 1
4 | 1 | 3
The booking_id in table A is unique and set to auto increment, the booking_id in table b can occur many times (depending on how many guests the client from table A brings with him). Lets say I want to know every selected insurance from customer 134 and his guests, then I want the output like this:
booking_id | insurance
1 | 4
1 | 0
1 | 1
1 | 1
1 | 3
I have tried a couple of joins and this is the closest I've came yet, unfortunately this fails to show the row from A and only shows the matching rows in B.
SELECT a.booking_id,a.A_customer,a.A_insurance,b.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134
Can someone point me into the right direction ?
Please note: I have altered the table and column names for stackoverflow so it's easy for you guys to read, so it's possible that there is a typo that would break the query in it right now.
I think you need a union all for this:
select a.booking_id, a.insurance
from a
where a.a_customer = 134
union all
select b.booking_id, b.insurance
from a join
b
on a.booking_id = b.booking_id
where a.a_customer = 134;
The simplest way I can think of to achieve this is to use a UNION:
SELECT booking_id, A_insurance insurance
FROM A
WHERE booking_id = 134
UNION
SELECT booking_id, B_insurance insurance
FROM B
WHERE booking_id = 134
As my understanging of your isso is right, that should give you the result you need:
SELECT a.booking_id,a.insurance FROM a WHERE a.booking_id = 134
union
SELECT a.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134

MYSQL - How to increment fields in one row with values from another row

I have a table that we'll call 'Sales' with 4 rows: uid, date, count and amount. I want to increment the count and amount values for one row with the count/amount values from a different row in that table. Example:
UID | Date | Count | Amount|
1 | 2013-06-20 | 1 | 500 |
2 | 2013-06-24 | 2 | 1000 |
Ideal results would be uid 2's count/amount values being incremented by uid 1's values:
UID | Date | Count | Amount|
1 | 2013-06-20 | 1 | 500 |
2 | 2013-06-24 | 3 | 1500 |
Please note that my company's database is an older version of MYSQL (3.something) so subqueries are not possible. I am curious to know if this is possible outside of doing an "update sales set count = count + 1" and likewise for the amount columns. I have a lot of rows to update and incrementing the values individually is quite time consuming if you can imagine. Thanks for any help or suggestions!
Without using a subselect you may be able to do a JOIN. Not sure from your description on what columns you are linking the rows to each other to decide which to update, but the following might give you the idea
UPDATE Sales a
INNER JOIN Sales b
ON ..........
SET a.Count = a.Count + b.Count,
a.Amount = a.Amount + b.Amount
However not sure if this works on archaic versions of MySQL
If you are just updating row 2 based on the values in row 1 then the following should do it
UPDATE Sales a
INNER JOIN Sales b
ON a.uid = 2 AND b.uid = 1
SET a.Count = a.Count + b.Count,
a.Amount = a.Amount + b.Amount
Most of the time, subqueries could be rewritten as join ... and even MySQL 3.23 has multiple table UPDATE
Something like that would probably do the trick ... but I am unable to test it (since your the only one still using such an old version of MySQL ;)
UPDATE Sales AS S1, Sales AS S2
SET S1.`count` = S1.`count̀€ +S2.`count`, S1.Amount = S1.Amount + S2.Amount
WHERE S1.uid = 2 AND S2.uid = 1
For simplicity here I explicitly set S1.uid to "2" and S2.uid to "1" -- if that works for this line, you should be able to use the WHERE clause that correspond to your specific needs.

MySQL How can I add values of a column together and remove the duplicate rows?

Good day,
I have a MySQL table which has some duplicate rows that have to be removed while adding a value from one column in the duplicated rows to the original.
The problem was caused when another column had the wrong values and that is now fixed but it left the balances split among different rows which have to be added together. The newer rows that were added must then be removed.
In this example, the userid column determines if they are duplicates (or triplicates). userid 6 is duplicated and userid 3 is triplicated.
As an example for userid 3 it has to add up all balances from rows 3, 11 and 13 and has to put that total into row 3 and then remove rows 11 and 13. The balance columns of both of those have to be added together into the original, lower ID row and the newer, higher ID rows must be removed.
ID | balance | userid
---------------------
1 | 10 | 1
2 | 15 | 2
3 | 300 | 3
4 | 80 | 4
5 | 0 | 5
6 | 65 | 6
7 | 178 | 7
8 | 201 | 8
9 | 92 | 9
10 | 0 | 10
11 | 140 | 3
12 | 46 | 6
13 | 30 | 3
I hope that is clear enough and that I have provided enough info. Thanks =)
Two steps.
1. Update:
UPDATE
tableX AS t
JOIN
( SELECT userid
, MIN(id) AS min_id
, SUM(balance) AS sum_balance
FROM tableX
GROUP BY userid
) AS c
ON t.userid = c.userid
SET
t.balance = CASE WHEN t.id = c.min_id
THEN c.sum_balance
ELSE 0
END ;
2. Remove the extra rows:
DELETE t
FROM
tableX AS t
JOIN
( SELECT userid
, MIN(id) AS min_id
FROM tableX
GROUP BY userid
) AS c
ON t.userid = c.userid
AND t.id > c.min_id
WHERE
t.balance = 0 ;
Once you have this solved, it would be good to add a UNIQUE constraint on userid as it seems you want to be storing the balance for each user here. That will avoid any duplicates in the future. You could also remove the (useless?) id column.
SELECT SUM(balance)
FROM your_table
GROUP BY userid
Should work, but the comment saying fix the table is really the best approach.
You can create a table with the same structure and transfer the data to it with this query
insert into newPriceTable(id, userid, balance)
select u.id, p.userid, sum(balance) as summation
from price p
join (
select userid, min(id) as id from price group by userid
) u ON p.userid = u.userid
group by p.userid
Play around the query here: http://sqlfiddle.com/#!2/4bb58/2
Work is mainly done in MSSQL but you should be able to convert the syntax.
Using a GROUP BY UserID you can SUM() the Balance, join that back to your main table to update the balance across all the duplicates. Finally you can use RANK() to order your duplicate Userids and preserve only the earliest values.
I'd select all this into a new table and if it looks good, deprecate your old table and rename then new one.
http://sqlfiddle.com/#!3/068ee/2

Select row belonging to multiple categories

I've got 2 tables. The first table is full of entries. The second table defines what categories that entry belongs to:
Table 1:
entry_id | title
1 | Entry1
2 | Entry2
3 | Entry3
Table 2
entry_id | cat_id
1 | 233
1 | 234
1 | 678
2 | 235
2 | 453
2 | 21
3 | 234
3 | 233
I'm trying to select an entry with a single query of all posts belonging to multiple categories. For example, I want to return the entries belonging to category ids, 233 and 234. I believe this needs a subquery although I'm not quite sure. Any help anybody? :)
Learn about SQL joins.
SELECT * FROM tbl1 JOIN tbl2 USING (entry_id) WHERE cat_id IN (233,234);
See it on sqlfiddle.
UPDATE
To select all entries in both categories, you could group the results of the join and only select those groups that have contain both categories:
SELECT tbl1.*
FROM tbl1 JOIN tbl2 USING (entry_id)
WHERE cat_id IN (233,234)
GROUP BY entry_id
HAVING COUNT(DISTINCT cat_id) = 2
See it on sqlfiddle.
The COUNT(DISTINCT cat_id) can obviously be replaced with the (much less expensive) COUNT(*) if (entry_id, cat_id) is known to be unique in tbl2.
Try this:
select * from entity e
where exists (select * from category c where c.entry_id=e.entry_id AND c.cat_id=233)
and exists (select * from category c where c.entry_id=e.entry_id AND c.cat_id=234)
This returns rows that belong to both 233 and 234 (this is how I read your question, anyway; I may have misunderstood the "belonging to multiple categories" part).