increment a value when a row is selected SQL - mysql

Is there any way to essentially keep track of how many times a row has been pulled from a SQL table?
For example in my table I have a column count. Every time a SQL statement pulls a particular row (lets call it rowA), rowA's 'count' value increases 1.
Either in the settings of the table or in the statement would be fine, but i cant find anything like this.
I know that I could split it into two statements to achieve the same thing, but I would prefer to only send one.

The best way to do this is to restrict read-access of the table to a stored procedure.
This stored procedure would take various inputs (filter options) to determine which rows are returned.
Before the rows are returned, their counter field is incremented.
Note that the update and the select command share the same where clause.
create procedure Select_From_Table1
#pMyParameter varchar(20), -- sample filter parameter
as
-- First, update the counter, only on the fields that match our filter
update MyTable set Counter = Counter + 1
where
MyFilterField like CONCAT('%', #pMyParameter, '%') -- sample filter enforcement
-- Now, return those rows
select
*
from
MyTable
where
MyFilterField like CONCAT('%', #pMyParameter, '%') -- sample filter enforcement
A decent alternative would be to handle it on the application side in your data-access layer.

Related

Increment column value on SELECT query

I am trying to build an API and one of the endpoints will return a random row from my database. In the database I have a table in which I want a "views" column to be updated every time I run a SELECT query on a row.
My table looks something like this:
CREATE TABLE `movies` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(256) NOT NULL,
`description` text,
`views` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
);
The row is selected by ordering the table with rand() and then limiting the result by 1, like so:
SELECT * FROM table ORDER BY rand() LIMIT 1;
Is something like this below possible?
SELECT * FROM table ORDER BY rand() LIMIT 1
UPDATE table SET views = +1 WHERE (selected row?);
I'm new to SQL queries, so I don't know if this is the best way or even possible at all. Should I run a new query after this one has completed that updates the value instead?
Usually, every table has a Primary Key, i.e. a unique ID of every single row. Since you have a result of your SELECT query and it's only 1 row, you always can make a consequent update query like UPDATE table SET views = views + 1 WHERE id = <returned_record_id>. Here we assume that the column id is a Primary Key column. This pair of queries need to be issued by the application code. If you want to achieve SELECT + UPDATE functionality as a single SQL statement, consider using stored procedures.
While the aforementioned approach is technically possible, it might have a few performance problems. First of, ORDER BY rand() often has a poor performance. Also, having an update on each select could have bad performance implications.
No what you want is not possible .as, select and update commands can not be used togethor in a single transaction.
You can do it seperately
You need to create a procedure for this in your database like:
CREATE PROCEDURE `procedure_name`()
BEGIN
SELECT * FROM table ORDER BY rand() LIMIT 1 ;
UPDATE table SET views = +1 WHERE (selected row?) ;
END
and then call it
call procedure_name();
You can check only as there are many ways to write a procedure.
Thanks
Unfortunately, what you want to do is not possible, at least not without a lot of work. SQL in general -- and MySQL in particular -- offer a capability called triggers.
Triggers allow you to do take actions when something happens in the database. For instance, if you want to check that values are correct, you can write an insert/update trigger to check the values and reject improper ones. Or, if you want to stash deleted records into an audit table, a trigger is the way to go.
What you are describing could be implemented using a trigger on a "select". Such a beast does not exist.
What are your options? Well, the simplest is to do this in your application. When a movie is selected, then you can update views. Of course, that only increments the views where you have the code.
You can move this code into a stored procedure. This simplifies the application code. It just has to "know" to use the stored procedure. But, there is no enforcement mechanism.
You can make this more enforceable by using permissions. Basically, don't allow access to the underlying table except through the stored procedure. This is closest to what you want.

How would you add a number to every piece of data in a column in SQL?

So if I have one column of data called credit_debt that has ten different numbers in it, and I wanted to add 100 to each of those, how would I do that? I know that I could do it manually one by one, but how would I do it all in one command?
To update all of the rows in a table, we can issue an UPDATE statement without a WHERE clause.
We can reference the current values stored in columns in the UPDATE statement.
Assuming that credit_debt column is a numeric datatype (e.g. INT, DECIMAL, DOUBLE, et al.)
UPDATE mytable
SET credit_debt = credit_debt + 100
;
Before running an UPDATE like that, I always ensure that I have a good backup, and a way to restore to the current state. And I test my expressions in a SELECT, so I won't have to do a restore. Before running that UPDATE, I'd run a SELECT like this:
SELECT credit_debt
, credit_debt + 100 AS _new_credit_debt
FROM mytable
ORDER BY ...
;
And the verify that the value returned for _new_credit_debt is the value I want to assign to the column. (We can add whatever other expressions to the SELECT list we want, so we can verify the results.

Generic stored procedure to lag a table column

I need to calculate returns at different frequencies. In order to do so, I would like to be able to lag the values in a column by k units. While I have found different specific solutions, I have not been able to make a general stored procedure (most likely due to my inexperience with mysql). How could I best do this?
I have a table with multiple columns, amongst which columns containing info on:
ID
Date
Price
The end result should be a table with all the original columns, plus a column containing the lagged values of Price.
To keep the procedure general, I could imagine the procedure would take the table name, necessary column names (e.g. ID, Date, Price), and number of lags k as input, and append a column to the table.
You can do what you want with a correlated subquery. Here is an example:
select t.*,
(select t2.price
from <tablename> t2
where t2.date < t.date
order by date
limit 1 offset 1 -- change the offset for a bigger lag
) as price_lag_1
from <tablename> t;
Your desire to create a generic stored procedure is not very SQL-y. MySQL doesn't support table-valued functions, so you wouldn't be able to use the resulting table as an actual table.
If you want to put this in a stored procedure that is generic, you will need dynamic SQL to construct the SQL statement, using the particular table and columns that you pass in.
Instead, I would suggest that you simply learn how to express what you want as a query. If you have multiple tables with the same structure, then you may want to revisit your data model. Have multiple similar tables is often an example of an entity being inappropriately spread across too many tables.

How to create a column in MYSQL which automatically SUMs the values from other columns within the same row

Could anybody tell me whether it is possible to have a column within a table in MYSQL that automatically performs the SUM function for a given number of columns.
As a comparative example in Microsoft Excel, it's possible to have a cell that performs the SUM function for a given range of cells and automatically updates i.e. (=SUM E4:E55)
Is it possible to have a column which achieves the same function in MYSQL?
To further elaborate -
I have numerous columns relating to the quantity of different sizes of our products i.e. quantity_size_* and wanted a column that would SUM the value of the quantity columns and update automatically if any of the values are changed.
Any advice would be great. Thanks
Normally you would do that in your select query on-the-fly and don't store those calculation.
select some_column,
col1 * col2 as some_calculation_result
from your_table
But if you have a really good reason not to do it that way then you can use a trigger to calculate those data.
You need an update trigger to catch changes in the data and an insert trigger to calculate on insertion.
An example of an insert trigger goes like this
delimiter |
CREATE TRIGGER sum_trigger AFTER INSERT ON your_table
FOR EACH ROW BEGIN
SET NEW.sum_column = NEW.column1 * NEW.column2;
END
|
delimiter ;
I think you will have to do this with a trigger. A column by itself just store data, it can't do things programmatically.
Mysql also heve the SUM() function which you can use in a select query.
So the best option will be to use a SELECT SUM() query
or else you can even create a VIEW for that , but triggers
are not recommended as they may become troublesome.

mysql peformance INSERT into table SELECT for report

I am working on a mysql query for a report. The idea is to have a simple table say 'reportTable' with the values being fetched from various places. I could then use the reportTable more easily without remembering lots of joins etc and also share this table for other projects.
Should I break down the inner insert part of the query so it does
chunks at a time I will be adding probably tens of thousands of rows?
INSERT INTO reportTable
(
-- long query grabbing results from various places
SELECT var1 FROM schema1.table1
SELECT var2 FROM schema2.table1
SELECT var2 FROM schema2.table1
etc
)
This addresses your concerns that inserting data takes too long and so on. I understood it like you rebuild your table each time. So, instead of doing so, just fetch the data that is new and not already in your table. Since looking up if the data is already present in your report table might be expensive, too, just get the delta. Here's how:
Make sure that in every table you need a column like this is present:
ALTER TABLE yourTable ADD COLUMN created timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
The ON UPDATE clause is of course optionally, don't know if you need to keep track of changes. If so, give me a comment and I can provide you with a solution with which you can keep a history of your data.
Now you need a small table that holds some meta information.
CREATE TABLE deltameta (tablename varchar(50), LSET timestamp, CET timestamp);
LSET is short for Last Successful Extraction Time, CET for Current Extraction Time.
When you get your data it works like this:
UPDATE deltameta SET CET = CURRENT_TIMESTAMP WHERE tablename = 'theTableFromWhichYouGetData';
SELECT #varLSET := LSET, #varCET := CET FROM deltameta WHERE tablename = 'theTableFromWhichYouGetData';
INSERT INTO yourReportTable (
SELECT whatever FROM aTable WHERE created >= #varLSET AND created < #varCET
);
UPDATE deltameta SET LSET = CET WHERE tablename = 'theTableFromWhichYouGetData';
When anything goes wrong during inserting your script stops and you get the same data the next time you run it. Additionally you can work with transactions here, if you need to roll back. Again, write a comment if you need help with this.
I may be wrong, but you seem to be talking about a basic view. You can read an introduction to views here: http://techotopia.com/index.php/An_Introduction_to_MySQL_Views, and here are the mysql view docs: http://dev.mysql.com/doc/refman/5.0/en/create-view.html