I have a table for rating an item.
The field rating holds a numeric value that I used to simply increase.
This method has its upsides but the downside is, that I can't have a rating of the past month/30 days because I don't have the individual ratings.
How would I go through the table, check if the ratingvalue is higher than 1 and if so add a new line for each rating?
eg
The table now
id | item_id | rating
1 | 2198 | 42
So I would like to have 42 individual entries.
Question:
Can I do this with only mysql if so how?
You need a stored procedure to do it, but you can do it in mysql.
Since you didn't add your table definitions I will assume id is an auto_increment key and that you don't want to preserve your original values.
Otherwise change the key or use a new (temporary) table with an auto_increment key.
DELIMITER $$
drop PROCEDURE if exists individualizemytable $$
CREATE PROCEDURE individualizemytable()
BEGIN
while (select count(*) from TheTable where rating > 1) do
insert into TheTable (item_id, rating)
select item_id, 1
from TheTable where rating > 1;
update TheTable
set rating = rating - 1
where rating > 1;
end while;
end $$
DELIMITER ;
call individualizemytable();
Simply use INSERT for each time rather than UPDATE while adding rating to an item. Also use current timestamp for the entry.
This will allow you to sum up ratings for an item between two dates easily.
Other but some lengthy solution would be UPDATE the rating count each time for an item and add last modified timestamp.
While updating, you can compare month from last modified timestamp and the current month. If they are the same the you can do UPDATE and if they are different, you will do INSERT. This way you can have direct count of total ratings for an item for all the months individually.
But again this method will have deep checking like comparing year, also it will impose extra overheads for fetching last modified timestamp every time etc.
Related
I'm trying to make a blog system of sort and I ran into a slight problem.
Simply put, there's 3 columns in my article table:
id SERIAL,
category VARCHAR FK,
category_id INT
id column is obviously the PK and it is used as a global identifier for all articles.
category column is well .. category.
category_id is used as a UNIQUE ID within a category so currently there is a UNIQUE(category, category_id) constraint in place.
However, I also want for category_id to auto-increment.
I want it so that every time I execute a query like
INSERT INTO article(category) VALUES ('stackoverflow');
I want the category_id column to be automatically be filled according to the latest category_id of the 'stackoverflow' category.
Achieving this in my logic code is quite easy. I just select latest num and insert +1 of that but that involves two separate queries.
I am looking for a SQL solution that can do all this in one query.
This has been asked many times and the general idea is bound to fail in a multi-user environment - and a blog system sounds like exactly such a case.
So the best answer is: Don't. Consider a different approach.
Drop the column category_id completely from your table - it does not store any information the other two columns (id, category) wouldn't store already.
Your id is a serial column and already auto-increments in a reliable fashion.
Auto increment SQL function
If you need some kind of category_id without gaps per category, generate it on the fly with row_number():
Serial numbers per group of rows for compound key
Concept
There are at least several ways to approach this. First one that comes to my mind:
Assign a value for category_id column inside a trigger executed for each row, by overwriting the input value from INSERT statement.
Action
Here's the SQL Fiddle to see the code in action
For a simple test, I'm creating article table holding categories and their id's that should be unique for each category. I have omitted constraint creation - that's not relevant to present the point.
create table article ( id serial, category varchar, category_id int )
Inserting some values for two distinct categories using generate_series() function to have an auto-increment already in place.
insert into article(category, category_id)
select 'stackoverflow', i from generate_series(1,1) i
union all
select 'stackexchange', i from generate_series(1,3) i
Creating a trigger function, that would select MAX(category_id) and increment its value by 1 for a category we're inserting a row with and then overwrite the value right before moving on with the actual INSERT to table (BEFORE INSERT trigger takes care of that).
CREATE OR REPLACE FUNCTION category_increment()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE
v_category_inc int := 0;
BEGIN
SELECT MAX(category_id) + 1 INTO v_category_inc FROM article WHERE category = NEW.category;
IF v_category_inc is null THEN
NEW.category_id := 1;
ELSE
NEW.category_id := v_category_inc;
END IF;
RETURN NEW;
END;
$$
Using the function as a trigger.
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
Inserting some more values (post trigger appliance) for already existing categories and non-existing ones.
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
Query used to select data:
select category, category_id From article order by 1,2
Result for initial inserts:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
Result after final inserts:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
Postgresql uses sequences to achieve this; it's a different approach from what you are used to in MySQL. Take a look at http://www.postgresql.org/docs/current/static/sql-createsequence.html for complete reference.
Basically you create a sequence (a database object) by:
CREATE SEQUENCE serials;
And then when you want to add to your table you will have:
INSERT INTO mytable (name, id) VALUES ('The Name', NEXTVAL('serials')
I'm trying to make a blog system of sort and I ran into a slight problem.
Simply put, there's 3 columns in my article table:
id SERIAL,
category VARCHAR FK,
category_id INT
id column is obviously the PK and it is used as a global identifier for all articles.
category column is well .. category.
category_id is used as a UNIQUE ID within a category so currently there is a UNIQUE(category, category_id) constraint in place.
However, I also want for category_id to auto-increment.
I want it so that every time I execute a query like
INSERT INTO article(category) VALUES ('stackoverflow');
I want the category_id column to be automatically be filled according to the latest category_id of the 'stackoverflow' category.
Achieving this in my logic code is quite easy. I just select latest num and insert +1 of that but that involves two separate queries.
I am looking for a SQL solution that can do all this in one query.
This has been asked many times and the general idea is bound to fail in a multi-user environment - and a blog system sounds like exactly such a case.
So the best answer is: Don't. Consider a different approach.
Drop the column category_id completely from your table - it does not store any information the other two columns (id, category) wouldn't store already.
Your id is a serial column and already auto-increments in a reliable fashion.
Auto increment SQL function
If you need some kind of category_id without gaps per category, generate it on the fly with row_number():
Serial numbers per group of rows for compound key
Concept
There are at least several ways to approach this. First one that comes to my mind:
Assign a value for category_id column inside a trigger executed for each row, by overwriting the input value from INSERT statement.
Action
Here's the SQL Fiddle to see the code in action
For a simple test, I'm creating article table holding categories and their id's that should be unique for each category. I have omitted constraint creation - that's not relevant to present the point.
create table article ( id serial, category varchar, category_id int )
Inserting some values for two distinct categories using generate_series() function to have an auto-increment already in place.
insert into article(category, category_id)
select 'stackoverflow', i from generate_series(1,1) i
union all
select 'stackexchange', i from generate_series(1,3) i
Creating a trigger function, that would select MAX(category_id) and increment its value by 1 for a category we're inserting a row with and then overwrite the value right before moving on with the actual INSERT to table (BEFORE INSERT trigger takes care of that).
CREATE OR REPLACE FUNCTION category_increment()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE
v_category_inc int := 0;
BEGIN
SELECT MAX(category_id) + 1 INTO v_category_inc FROM article WHERE category = NEW.category;
IF v_category_inc is null THEN
NEW.category_id := 1;
ELSE
NEW.category_id := v_category_inc;
END IF;
RETURN NEW;
END;
$$
Using the function as a trigger.
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
Inserting some more values (post trigger appliance) for already existing categories and non-existing ones.
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
Query used to select data:
select category, category_id From article order by 1,2
Result for initial inserts:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
Result after final inserts:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
Postgresql uses sequences to achieve this; it's a different approach from what you are used to in MySQL. Take a look at http://www.postgresql.org/docs/current/static/sql-createsequence.html for complete reference.
Basically you create a sequence (a database object) by:
CREATE SEQUENCE serials;
And then when you want to add to your table you will have:
INSERT INTO mytable (name, id) VALUES ('The Name', NEXTVAL('serials')
I will try to walk you through the problem that I am facing so that you could understand how I got to this point.
This was my initial db:
The idea was to let one user update the value of a product. It was working fine though like this I can't record every update that the user has made because if that user updates the same product again it will just rewrite the last update and not write in the latest as intended. That was the case because the id's of user and product were matching on the two updates. So I tried to add another table just for the recording of updates like so:
Though the problem consists. Do I have to make another many to many relationship whose one end will be user_product or is there an more elegant way to resolve a problem like this?
you only need a "histiory"table that references
the productID and the changes made with timestamp and if more users are allowed to change the product also the userid
As Id you have an autoincrement
When you want to know the latest changes You select all rows for that productid and sort it by timestamp Or only the price
like
history_products
id
product_id
alcohol
amount
mass
name
picture
price
timecreated
And use a select like
SELECT price,timecreated FROM history_products WHERE product_id = 10000 ORDER by timecreated;
You can insert automatically by using a trigger
DELIMITER $$
CREATE TRIGGER afterupdateproduct
AFTER UPDATE
ON products FOR EACH ROW
BEGIN
INSERT INTO history_products (product_id,alcohol,amount,mass,name,picture, price,timecreated)
VALUES (OLD.alcohol,OLD.amount,OLD.mass,OLD.name,OLD.picture, OLD.price, Now());
END$$
DELIMITER ;
I have a customer table, the fields in the table are id_customer, name, birthday.
The id_customer datatype is CHAR(20) and the format is 'CUSTyyyymmdd00000000' the yyyymmdd in the id is the customer's birthday. The last 8 digit is increased based on the birthday on the id_customer field.
the output example :
CUST1995020100000001, CUST1995020100000002, CUST1995030300000001, CUST1995030300000002 and so on.
I already created a function to increase the last digit :
DELIMITER $$
CREATE
FUNCTION get_increment_id_cust()
RETURNS INT
BEGIN
DECLARE id INT;
SET id =( SELECT IFNULL(MAX(CONVERT(RIGHT(id_customer,8),INT)),0) AS id
FROM customer );
RETURN id+1;
END$$
DELIMITER ;
and with this code :
SELECT SUBSTRING(CONCAT('00000000',get_increment_id_cust()),LENGTH(CONCAT('00000000',get_increment_id_cust()))-7,8);
i have the 8 digit like 00000001, 00000002 and so on.
I've tried to use another concat to add the prefix, but it cant add a different birthday.
And how do i implement it on Before Insert Trigger so it's increased automatically when i add another row?
I'm going to suggest that you depart from your current approach, and instead maintain a table including the following two columns:
(id, date_of_birth, ...)
That is, just store the date of birth in a separate bona-fide column. As for the ID value, you may rely on an auto increment column, which MySQL guarantees will always generate a new unique value. If you still have the need for an id_customer, as you have described it, you may always generate it when you query, e.g.
SELECT
CONCAT('CUST', DATE_FORMAT(date_of_birth, '%Y%m%d'), id) AS id_customer
FROM yourTable;
Your id_customer consists of several different parts, each of which really belongs in a separate column. I suggest the above to simplify your maintenance and make your life easier.
I'm trying to make a blog system of sort and I ran into a slight problem.
Simply put, there's 3 columns in my article table:
id SERIAL,
category VARCHAR FK,
category_id INT
id column is obviously the PK and it is used as a global identifier for all articles.
category column is well .. category.
category_id is used as a UNIQUE ID within a category so currently there is a UNIQUE(category, category_id) constraint in place.
However, I also want for category_id to auto-increment.
I want it so that every time I execute a query like
INSERT INTO article(category) VALUES ('stackoverflow');
I want the category_id column to be automatically be filled according to the latest category_id of the 'stackoverflow' category.
Achieving this in my logic code is quite easy. I just select latest num and insert +1 of that but that involves two separate queries.
I am looking for a SQL solution that can do all this in one query.
This has been asked many times and the general idea is bound to fail in a multi-user environment - and a blog system sounds like exactly such a case.
So the best answer is: Don't. Consider a different approach.
Drop the column category_id completely from your table - it does not store any information the other two columns (id, category) wouldn't store already.
Your id is a serial column and already auto-increments in a reliable fashion.
Auto increment SQL function
If you need some kind of category_id without gaps per category, generate it on the fly with row_number():
Serial numbers per group of rows for compound key
Concept
There are at least several ways to approach this. First one that comes to my mind:
Assign a value for category_id column inside a trigger executed for each row, by overwriting the input value from INSERT statement.
Action
Here's the SQL Fiddle to see the code in action
For a simple test, I'm creating article table holding categories and their id's that should be unique for each category. I have omitted constraint creation - that's not relevant to present the point.
create table article ( id serial, category varchar, category_id int )
Inserting some values for two distinct categories using generate_series() function to have an auto-increment already in place.
insert into article(category, category_id)
select 'stackoverflow', i from generate_series(1,1) i
union all
select 'stackexchange', i from generate_series(1,3) i
Creating a trigger function, that would select MAX(category_id) and increment its value by 1 for a category we're inserting a row with and then overwrite the value right before moving on with the actual INSERT to table (BEFORE INSERT trigger takes care of that).
CREATE OR REPLACE FUNCTION category_increment()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE
v_category_inc int := 0;
BEGIN
SELECT MAX(category_id) + 1 INTO v_category_inc FROM article WHERE category = NEW.category;
IF v_category_inc is null THEN
NEW.category_id := 1;
ELSE
NEW.category_id := v_category_inc;
END IF;
RETURN NEW;
END;
$$
Using the function as a trigger.
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
Inserting some more values (post trigger appliance) for already existing categories and non-existing ones.
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
Query used to select data:
select category, category_id From article order by 1,2
Result for initial inserts:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
Result after final inserts:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
Postgresql uses sequences to achieve this; it's a different approach from what you are used to in MySQL. Take a look at http://www.postgresql.org/docs/current/static/sql-createsequence.html for complete reference.
Basically you create a sequence (a database object) by:
CREATE SEQUENCE serials;
And then when you want to add to your table you will have:
INSERT INTO mytable (name, id) VALUES ('The Name', NEXTVAL('serials')