update statement after the condition met in select statement (mysql) - mysql

im having trouble with update if selected table is true...
IF this select statement is true
(SELECT COUNT(*) FROM Add_bonus WHERE value > 0) > 0)
THEN do
UPDATE bonus SET amount = amount + 10 WHERE 1

The if statement is only allowed in stored procedures, functions, and triggers in MySQL. You can do this with a single update:
UPDATE bonus
SET amount = amount + 10
WHERE exists (select 1 from Add_Bonus where value > 0);
Note that this query will update all rows in the bonus table when any appropriate row exists in the add_bonus table. That appears to be the intention of your original query. More commonly, there might be an employee id linking the two tables.
Also note the use of exists. This is typically more efficient than using count(*), because it can stop processing on the first row that matches.

Related

Determining whether each row exists in another MySQL table

I have two tables that are very similar. For example, let's say that each row has two ID numbers, and a data value. The first ID number may occur once, twice, or not be included, and the second ID number is either 1 or -1. The data value is not important, but for the sake of this example, we'll say it's an integer. For each pair of ID numbers, there can only be one data value, so if I have a data point where the ID's are 10 and 1, there won't be another 10 and 1 row with a different data value. Similarly, in the other table, the data point with ID's 10 and 1 will be the same as in the first table. I want to be able to select the rows that exist in both tables for the sake of changing the data value in all of the rows that are in both. My command for MySQL so far is as follows:
SELECT DISTINCT * FROM schema.table1
WHERE EXISTS (SELECT * from schema.table1
WHERE schema.table1.ID1 = schema.table2.ID1
and schema.table1.ID2 = schema.table2.ID2);
I want to be able to have this code select all the rows in table1 that are also in table2, but allow me to edit table1 values.
I understand that by creating a union of the two tables, I can see the rows that exist in both tables, but would this allow me to make changes to the actual data values if I changed the values in the merged set? For example, if I did:
SELECT DISTINCT * FROM schema.table1 inner join schema.table2
WHERE schema.table1.ID1 = schema.table2.ID1
schema.table1.ID2 = schema.table2.ID2;
If I call UPDATE on the rows that I get from this query, would the actual values in table1/table2 be changed or is this union just created in dynamic memory and I would just be changing values that get deleted when the query is over?
Update as follows:
UPDATE table1 SET data = whateverupdate
WHERE ID1 IN (SELECT ID1 from schema.table1
WHERE schema.table1.ID1 = schema.table2.ID1
and schema.table1.ID2 = schema.table2.ID2);
In your inner select statement, you cannot do a select * you'll have to select a particular column. This should work because your inner select finds the row in question and feeds it to your update statement. That being said, your inner select has to return the right row you need, else, the wrong row will be updated. Hope this helps.

How to update a counter field from a different table in mysql

I have 3 tables in MySQL ParkIn{ parkin_id,InTime} ,ParkOut{parkout_id,OutTime} and Counter{ Counter_ID, Counter}.
Everytime there is an Insert in the Parkin table I need the Counter column to add 1 to its previous value and whenever there is a Insert in the ParkOut table I need the counter column to subtract 1. The counter table doesnt necessarily have to insert new lines everytime but rather just keep updating the counter value.
You're doing this the hard way.
You can do
SELECT (parkin.rowcount - parkout.rowcount) Counter
FROM (SELECT COUNT(*) rowcount FROM ParkIn) parkin
JOIN (SELECT COUNT(*) rowcount FROM ParkOut) parkout
when you need the value you described. You can trust that databases are made to do this kind of thing.
If you really want the illusion that you have a Counter table, you can create a view.
CREATE OR REPLACE VIEW Counter AS
SELECT (parkin.rowcount - parkout.rowcount) Counter
FROM (SELECT COUNT(*) rowcount FROM ParkIn) parkin
JOIN (SELECT COUNT(*) rowcount FROM ParkOut) parkout
Your Counter table, as you described it in your question, is known as a "materialized view" in the DBMS trade. It's "materialized" because it's an actual table that you actually maintain in real time. I am suggesting using an ordinary view, not a materialized view, to solve your problem.

Subquery returns more than 1 row solution for update query using select statement

Hello i have query in which i have written update statement using select statement. But unfortunately getting errors subquery returns more than 1 row. I know where the error is coming. But i dont know solution for the same.Thank you.
Here is the query:
UPDATE adsetest.dashboard_widget_users
SET configuration=
(SELECT DISTINCT ad_news_texte.headline
FROM autodo.ad_news_texte
INNER JOIN autodo.ad_news_oe
ON ad_news_texte.news_id = ad_news_oe.id_ad_news
INNER JOIN autodo.ad_news
ON ad_news_oe.id_ad_news = ad_news.id
WHERE ad_news.datum_archiv BETWEEN
curdate() - INTERVAL DAYOFWEEK(curdate()) + 28 DAY AND curdate())
WHERE dsnr_yw_user = 1 AND dsnr_dashboard_widget = 1
When you use update with SET configuration=(SELECT ...) the subquery has to return no more than one value (one row). If it returns more than one value how do you assign two rows table for example to scalar configuration field. So you should figure out WHY your subquery returns more than one row and fix the subquery or decide which ONE value to select for update in case of more than one row. For example you can select maximum value
SELECT MAX(ad_news_texte.headline)...
or any one first value
(SELECT ad_news_texte.headline)... LIMIT 1)
and so on...
If you need to concatenate all rows and put it into one row configureation you can use GROUP_CONCAT() mysql function:
SET configuration=(SELECT GROUP_CONCAT(DISTINCT ad_news_texte.headline) FROM ....
You have to first think about what you want to do.
Do you want to fetch one value and save it somewhere else?
Then use SET value = (SELECT...). For this you need to make sure, the inner statement doesn't return more than one value.
Or
Do you need to be able to handle fetching multiple values?
What do you want to do with these? Save all of them? All in one (use concat) or store them individually (one update per result)? Or select one of them? Maybe the first (LIMIT 1) or highest (MAX) or lowest (MIN) value?

Better way to write these SQL statements

I want to read data for reporting purpose. Currently, I populate a table using another table's calculated data, and read data for reporting from the populated table. My current logic is too delete the old data, and insert the new data, all within a transaction.
UPDATE
Requirements
1) The logic below is to run once every second. Please note that other processes also udpates tableB with the same refresh rate.
2) TableB is used for reporting purpose. TableA and TableB resides in different databases.
3) TableB contains around 10 millions rows, around 4 millions rows will be updated once every second by the code below. Other processes also update the other part of data (6 = 10-4 millions) in tableB at the same refresh rate.
My concern is that:
1) three statements use similar sum, and where clauses, which might be improved.
2) There are about 1-2 millions row in tablea to update to tableB. Using an explicit temporary table might slow down.
3) Using transaction might slow down, but it seems the only way.
4) Update the data might be a better option than delete and insert (which one should I choose?)
I want to find a better performant way (including table redesign etc.). Below is the current way:
pseudocode below:
start/begin transaction here
DELETE from tableb data that I want to insert below, e.g. delete data where Code = 'code'
INSERT INTO tableb(Code, Total)
SELECT sum(a.Code, price)
FROM tablea a
GROUP BY a.Code;
IINSERT INTO tableb(Code, Total)
SELECT sum(a.Code price) -- use price
FROM tablea a
WHERE a.meanPrice IS NOT NULL
GROUP BY a.Code;
INSERT INTO tableb(Code, Total)
SELECT sum(a.Code, meanPrice ) -- use meanPrice
FROM tablea a
WHERE a.meanPrice IS NOT NULL
GROUP BY a.Code;
Commit transaction here
It is for MySQL, but ideally it should be generic.
Any idea?
Do you actually need to update values in the table? They are not tagged with any id or names to identify them.
The following SELECT statement returns the data you want:
SELECT code,
sum(price),
sum(case when a.meanPrice is not null then price else 0 end),
sum(case when a.meanPrice is not null then meanprice else 0 end)
FROM tablea a
GROUP BY a.Code;
If you needed to insert this into a temp table, you can unpivot the data. However, that format does not make sense to me. Can you explain why you are using a table with one numeric column in this way?
This query does your INSERT task in 1 step, but ... kids, don't do this at home without actually measuring actual performance:
http://sqlfiddle.com/#!2/381e2/9
INSERT INTO tableb(Total)
SELECT
CASE
WHEN t.v = 1
THEN SUM( price )
WHEN t.v = 2
THEN SUM(
CASE
WHEN meanPrice IS NOT NULL THEN price
ELSE 0
END
)
WHEN t.v = 3
THEN SUM( meanPrice )
END AS Total
FROM tablea
INNER JOIN
( SELECT 1 AS v UNION ALL
SELECT 2 AS v UNION ALL
SELECT 3 AS v
) AS t
GROUP BY tablea.Code, t.v;
Point 3 is false.
Solution 1: Create an store procedure.
Solution 2: Create a trigger on the impacted tables.
Solution 3: Don't ask for a sum every time, do the sum the first time and then save the number on another table. On every modification of this table, do the sum over your new table, I wont be 1 millions records, only one per table.
Pivot tables!

MySQL - Update view column every time the row is SELECTed

I have a table that has a "view_count" column.
I would like to increment said column every time I select the row (even with a generic SELECT, such as SELECT * FROM table WHERE 1.. This would increment by 1 the view_count of all rows).
Is there a way to do it automatically "server-side" (where mysql is the server and my application is the client), ie without an UPDATE every time?
EDIT: Since a couple of people asked me why I wanted to do this, and a few misunderstood my request, imagine that's a forum software, and the table is the thread table. Each thread has a view count, and you want to update it every time you display the thread in the main page (I know usually the threads' view count are only updated when you actually view it, but it's the best example i could come up with, my particular case is kinda long and complicated T_T)
Can't be done. You basically want a trigger on SELECT, and triggers are only supported for INSERT, UPDATE, and DELETE. The closest you could get would be to run all your interactions with the table through a stored procedure, and it sounds like you want this behavior to be enforced under all conditions.
Why not just issue one SQL statement like so:
UPDATE tableName SET viewCount = viewCount + 1; SELECT tableName.col1, tableName.col2;
That could even be dynamically created with ease in any language.
You can do it in the session scope:
SET #view_count := 0;
SELECT v.*,
#view_count := #view_count + 1 AS view_count
FROM view
You will have an incrementing value for each row viewed:
SELECT q.*,
#view_count := #view_count + 1 AS view_count
FROM (
SELECT 1 AS col
UNION ALL
SELECT 2 AS col
) q;
-- --
1 1
2 2
SELECT q.*,
#view_count := #view_count + 1 AS view_count
FROM (
SELECT 1 AS col
UNION ALL
SELECT 2 AS col
) q;
-- --
1 3
2 4
This, however, will only count the views within your session, not the total views.
I don't believe there's a simple way to do this server-side; triggers only execute on UPDATEs, INSERTs, and DELETEs.
Stored procedures, but it's a pain. I would implement security elsewhere.