mySQL date column is messed up - php

I've made a table:
+---------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | date | NO | | NULL | |
| user_id | int(8) | YES | | NULL | |
| isbn | varchar(13) | NO | | NULL | |
| price | decimal(6,2) | NO | | NULL | |
+---------+--------------+------+-----+---------+----------------+
And, the date colomn isn't working. I figured I need to modify the table to default to "CURDATE()". That's what I've got from googling. I'm not even sure if that's the problem, but my alter statement isn't work.
I'm trying to alter with this:
mysql> ALTER TABLE buybacks MODIFY date date not null default curdate();
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'curdate()' at line 1
Can someone help?

It's generally not a good idea to have column (or table) names that are MySQL reserved words. If you must do this, then use backticks (`) around the name
ALTER TABLE buybacks MODIFY `date` date not null default curdate();
EDIT
However, you can't set a date column to a default of curdate()
See this reference from the MySQL buglist for details
The exception is that you can specify CURRENT_TIMESTAMP as the default for a TIMESTAMP
column. This might be a viable alternative to give you that default
EDIT 2
Another alternative would be a trigger:
CREATE TRIGGER buybacks_insert BEFORE INSERT ON `buybacks`
FOR EACH ROW
SET NEW.`date` = CURDATE();
But watch out that you update a trigger when you do change the name of the date column

Related

Mysql error Cannot add foreign key constraint when i add foreign key

IN my mysql database i have two table review and products
mysql> desc review;
+---------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| review | varchar(255) | YES | | NULL | |
| rating | varchar(255) | YES | | NULL | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | |
| updated_at | timestamp | NO | | CURRENT_TIMESTAMP | |
| reviewer_name | varchar(255) | YES | | NULL | |
| product_id | int(11) | YES | | NULL | |
+---------------+--------------+------+-----+-------------------+----------------+
mysql> desc products;
+---------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| details | text | NO | | NULL | |
+---------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
When i try to make product_id in review table as foreign key that refer to id in products table i found this error and the query what i gave was:
mysql> ALTER TABLE review ADD FOREIGN KEY (product_id) REFERENCES products(id);
ERROR 1215 (HY000): Cannot add foreign key constraint
Please help me out what the problem is and how can i figure it out
The "precision" of the int types means nothing. It's just a hint for display width. It makes no difference to the size of the data type.
What caused your error was that your products.id was int unsigned, but you were trying to declare a foreign key for review.product_id which was int (signed).
The difference between signed and unsigned int was what makes the data types incompatible for referential integrity. You could make one int(10) unsigned and the other int(327) unsigned and it would be okay.
There may be two reasons for the error.
The datatype precision is different for two columns i.e.
products -> id | int(10) unsigned // here int(10)
product_id | int(11) // here int(11)
make the precision same by altering the table structure
To create foreign key relation ship the parent table column must be
unique or a primary column.
So check if products(id) is primary or unique, if not make it primary or unique.
alter your table structure
id | int(11)
or set
product_id | int(10) unsigned
do which way is batter for you. also you can also get better understanding about FOREIGN KEY from here

Know the last modified row or id's row in a mysql table

I'm using Mysql 5.5 and by example I have a table like this
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| idgroups | int(11) | NO | PRI | NULL | auto_increment |
| group_id | int(11) | YES | | NULL | |
| group_name | varchar(45) | YES | | NULL |
Where some people are allowed to do inserts,update and delete but I want to know which is the last modified row or row's id in a given time
Any ideas?
Thanks in advance
My suggestion would be to create a second table. something like edit_history for recording modifications. You can put triggers on your groups table above that says "Any time a record is inserted, deleted, or updated, create a record in my edit_history table".
A trigger can be created as follows:
CREATE TRIGGER trigger_name
AFTER INSERT
ON table_name FOR EACH ROW
BEGIN
-- For each row inserted
-- do something...
END;
Since your field is auto_increment, you can just select the maximum value of idgroups to get the most recently inserted value:
select max(idgroups) from tbl
to get last modified in general will require additional structure to your table. In particular, if you are deleting, you will need to store what you have most recently deleted somewhere.

How can i update the Records included in another query using SUM and GROUP By in mysql

I am having a mysql table
content_votes_tmp
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| up | int(11) | NO | MUL | 0 | |
| down | int(11) | NO | | 0 | |
| ip | int(10) unsigned | NO | | NULL | |
| content | int(11) | NO | | NULL | |
| datetime | datetime | NO | | NULL | |
| is_updated | tinyint(2) | NO | | 0 | |
| record_num | int(11) | NO | PRI | NULL | auto_increment |
+------------+------------------+------+-----+---------+----------------+
surfers can vote up or vote down on posts i.e. content, a record gets inserted everytime a vote is given same as rating , in the table along with other data like ip , content id
Now i am trying to create cronjob script in php which will SUM(up) and SUM(down) of votes
like this,
mysqli_query($con, "SELECT SUM(up) as up_count, SUM(down) as down_count, content FROM `content_votes_tmp` WHERE is_updated = 0 GROUP by content")
and then by using while loop in php i can update the main table for the specific content id,
but i would like to set the records which are part of SUM to be marked as updated i.e. SET is_updated = 1, so the same values wont get summed again and again.
How can i achieve this ? using mysql query ? and work on same data set as , every second/milisecond the records are getting inserted in the table ,.
i can think of another way of achieving this is by getting all the non-updated records and doing sum in the php and then updating every record.
The simplest way would probably be a temporary table. Create one with the record_num values you want to select from;
CREATE TEMPORARY TABLE temp_table AS
SELECT record_num FROM `content_votes_tmp` WHERE is_updated = 0;
Then do your calculation using the temp table;
SELECT SUM(up) as up_count, SUM(down) as down_count, content
FROM `content_votes_tmp`
WHERE record_num IN (SELECT record_num FROM temp_table)
GROUP by content
Once you've received your result, you can set is_updated on the values you just calculated over;
UPDATE `content_votes_tmp`
SET is_updated = 1
WHERE record_num IN (SELECT record_num FROM temp_table)
If you want to reuse the connection to do the same thing again, you'll need to drop the temporary table before creating it again, but if you just want to do it a single time in a page, it will disappear automatically when the database is disconnected at the end of the page.

removing duplicate row from mysql where value equals something

I've all the way to the end of the internet and I'm proper stuck. Whilst I can find partial answer I'm unable to modify it to make it work.
I have a table named myfetcher like:
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| fid_id | int(11) | NO | PRI | NULL | auto_increment |
| linksetid | varchar(200) | NO | | NULL | |
| url | varchar(200) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
The url field would sometimes contain dupes but rather than remove all duplicates in the table, I need only where the field linksetid is equal to X.
The SQL below removes all duplicates in the table (which is not what I want)... but what I want is only the duplicates within a set range in the field linksetid. I know I'm doing something wrong, just not sure what is it.
DELETE FROM myfetcher USING myfetcher, myfetcher as vtable
WHERE (myfetcher.fid>vtable.fid)
AND (myfetcher.url=vtable.url)
AND (myfetcher.linksetid='$linkuniq')
Delete only records with linksetid=X. First EXISTS check case when all records are with linksetid=X then only one with min(fid) remains. The second EXISTS check case when there is a record with linksetid<>X then all records with linksetid=X will be removed:
NOTE: this query works in Oracle or MSSQL. For MYSql use next workaround:
DELETE FROM myfetcher
where (myfetcher.linksetid='$linkuniq')
and
(
exists
(select t.fid from myfetcher t where
t.fid<myfetcher.fid
and
t.url=myfetcher.url
and
t.linksetid='$linkuniq')
or
exists
(select t.fid from myfetcher t where
t.url=myfetcher.url
and
t.linksetid<>'$linkuniq')
)
In MYSql you can't use update/delete command with subquery for the target table. So for MySql you can use following script. SqlFiddle demo:
create table to_delete_tmp as
select fid from myfetcher as tmain
where (tmain.linksetid='$linkuniq')
and
(
exists
(select t.fid from myfetcher t where
t.fid<tmain.fid
and
t.url=tmain.url
and
t.linksetid='$linkuniq')
or
exists
(select t.fid from myfetcher t where
t.url=tmain.url
and
t.linksetid<>'$linkuniq')
) ;
delete from myfetcher where myfetcher.fid in (select fid from to_delete_tmp);
drop table to_delete_tmp;

Speed Up MySQL (MyISAM) COUNTs with WHERE Clauses

We are implementing a system that analyses books. The system is written in PHP, and for each book loops through the words and analyses each of them, setting certain flags (that translate to database fields) from various regular expressions and other tests.
This results in a matches table, similar to the example below:
+------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| regex | varchar(250) | YES | | NULL | |
| description | varchar(250) | NO | | NULL | |
| phonic_description | varchar(255) | NO | | NULL | |
| is_high_frequency | tinyint(1) | NO | | NULL | |
| is_readable | tinyint(1) | NO | | NULL | |
| book_id | bigint(20) | YES | | NULL | |
| matched_regex | varchar(255) | YES | | NULL | |
| [...] | | | | | |
+------------------------+--------------+------+-----+---------+----------------+
Most of the omitted fields are tinyint, either 0 or 1. There are currently 25 fields in the matches table.
There are ~2,000,000 rows in the matches table, the output of analyzing ~500 books.
Currently, there is a "reports" area of the site which queries the matches table like this:
SELECT COUNT(*)
FROM matches
WHERE is_readable = 1
AND other_flag = 0
AND another_flag = 1
However, at present it takes over a minute to fetch the main index report as each query takes about 0.7 seconds. I am caching this at a query level, but it still takes too long for the initial page load.
As I am not very experienced in how to manage datasets such as this, can anyone advise me of a better way to store or query this data? Are there any optimisations I can use with MySQL to improve the performance of these COUNTs, or am I better off using another database or data structure?
We are currently using MySQL with MyISAM tables and a VPS for this, so switching to a new database system altogether isn't out of the question.
You need to use indexes, create them on the columns you do a WHERE on most frequently.
ALTER TABLE `matches` ADD INDEX ( `is_readable` )
etc..
You can also create indexes based on multiple columns, if your doing the same type of query over and over its useful. phpMyAdmin has the index option on the structure page of the table at the bottom.
Add multi index to this table as you are selecting by more than one field. Below index should help a lot. Those type of indexes are very good for boolean / int columns. For indexes with varchar values read more here: http://dev.mysql.com/doc/refman/5.0/en/create-index.html
ALTER TABLE `matches` ADD INDEX ( `is_readable`, `other_flag`, `another_flag` )
One more thing is to check your queries by using EXPLAIN {YOUR WHOLE SQL STATEMENT} to check which index is used by DB. So in this example you should run query:
EXPLAIN ALTER TABLE `matches` ADD INDEX ( `is_readable`, `other_flag`, `another_flag` )
More info on EXPLAIN: http://dev.mysql.com/doc/refman/5.0/en/explain.html

Categories