Sql insert ignore does not work because of timestamp now() - php

I am trying to prevent duplicate entries like this
INSERT IGNORE INTO myTable( `val_1`, `val_2`, `val_3`, `date` )
VALUES ( '$var_1', '$var_2', '$var_3', now() )
The values i would like to check are the 3 val_x but because now() will be a unique value, insert ignore does not work.
How can i not check that last variable as unique?
note: this is kind of like a cart, so i cannot make the first 3 values unique. There is a session variable that allows each user to see a a unique collection.
From this diagram, the first 2 rows are duplicate since they belong to the same user session. The 3rd row is not a duplicate becase it belongs to a different user session
+---------+-------+--------+
| session | var 1 | var 2 |
+---------+-------+--------+
| abc1234 | aaaaa | bbbbb |
+---------+-------+--------+
| abc1234 | aaaaa | bbbbb |
+---------+-------+--------+
| 5678def | aaaaa | bbbbb |
+---------+-------+--------+
| 5678def | aaaaa | ccccc |
+---------+-------+--------+
as paqogomez suggested i removed now() from the query and altered the table but it looks like i need a primary key for insert ignore to work, but for my scenario i cant make these 3 columns unique
ERROR 1062: Duplicate entry 'aaaaa' for key 'var 1'

I would suggest moving the date into the default value of the column.
ALTER TABLE mytable CHANGE `date` `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
This way, you can still deal with the duplicates in the data in PHP. The alternative, as others have suggested would result in a database foreign key error if you attempted to insert a duplicate.
Then this sql would work and give the same result:
INSERT IGNORE INTO myTable( `val_1`, `val_2`, `val_3` )
VALUES ( '$var_1', '$var_2', '$var_3' )
EDIT:
You still need a unique index to make it work. See #Gordon's answer

Create a unique index on the first three columns:
create unique index myTable_session_val2_val3 on myTable(session, val_1, val_2);
This will guarantee that combinations of these three are unique, without taking into account any other columns.

You should probably define the UNIQUE keys for the combination of columns you don't want to be duplicated. So, don't specify column date as UNIQUE. Did you verify that? Define rest of three values as unique columns. It will probably work.

Related

Prevent inserting matching rows in MySql

I have a table in MySql Database. I would like to prevent inserting matching rows in MySql. Like I have 4 columns in a table. I would not like to insert any row which has matching values of these 4 columns. I am trying to show that below
My table
----------
product_name| product_sku |product_quantity| product_price
----------
Computer | comp_007 | 5 | 500
I would like to prevent to insert same row again. How can I do that using MySql Query ??
UPDATE
I would not like to insert again
Computer | comp_007 | 5 | 500
But I would like to insert below rows
mouse | comp_007 | 5 | 500
Computer | comp_008 | 5 | 500
Computer | comp_007 | 50 | 500
Computer | comp_007 | 5 | 100
mouse | mou_007 | 5 | 500
Create a combined unique key / composite key on the columns in question:
ALTER TABLE `table` ADD UNIQUE (
`product_name` ,
`product_sku` ,
`product_quantity`,
`product_price`
);
Any attempts to insert duplicate rows will result in a MySQL error.
If possible you should add a Unique Key to your columns:
ALTER TABLE `table_name`
ADD UNIQUE INDEX `ix_name` (`product_name`, `product_sku`, `product_quantity`, `product_price`);
and then use INSERT IGNORE:
INSERT IGNORE INTO table_name (product_name, product_sku, product_quantity, product_price) VALUES (value1, value2, value3, value4);
If the record is unique MYSQL inserts it as usual, if the record is a duplicate then the IGNORE keyword discards the insert without generating an error.
SQLfiddle
The simplest way would be to make your columns unique. On undesired inserts, your MySQL driver should throw an exception then, which you can handle.
From a domain logic point of view, this is a bad practice, since exceptions should never handle expected behaviour. By the way, your DB table could use a primary key.
So, to have a better solution, your approach could be:
- Define a unique field (the SKU seems suitable); think about using this as the primary key as well
- With MySQL, use a REPLACE statement:
REPLACE INTO your_tablename
SET product_name='the name'
-- and so on for other columns
WHERE product_sku = 'whatever_sku';
REPLACE does the Job of trying to INSERT, and doing an UPDATE instead if the PK exists.

Change existing row ID based on AUTO_INCREMENT (unique key)

I have a table that records tickets that are separated by a column that denotes the "database". I have a unique key on the database and cid columns so that it increments each database uniquely (cid has the AUTO_INCREMENT attribute to accomplish this). I increment id manually since I cannot make two AUTO_INCREMENT columns (and I'd rather the AUTO_INCREMENT take care of the more complicated task of the uniqueness).
This makes my data look like this basically:
-----------------------------
| id | cid | database |
-----------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
-----------------------------
This works perfectly well.
I am trying to make a feature that will allow a ticket to be "moved" to another database; frequently a user may enter the ticket in the wrong database. Instead of having to close the ticket and completely create a new one (copy/pasting all the data over), I'd like to make it easier for the user of course.
I want to be able to change the database and cid fields uniquely without having to tamper with the id field. I want to do an UPDATE (or the like) since there are foreign key constraints on other tables the link to the id field; this is why I don't simply do a REPLACE or DELETE then INSERT, as I don't want it to delete all of the other table data and then have to recreate it (log entries, transactions, appointments, etc.).
How can I get the next unique AUTO_INCREMENT value (based on the new database value), then use that to update the desired row?
For example, in the above dataset, I want to change the first record to go to "database #2". Whatever query I make needs to make the data change to this:
-----------------------------
| id | cid | database |
-----------------------------
| 1 | 3 | 2 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
-----------------------------
I'm not sure if the AUTO_INCREMENT needs to be incremented, as my understanding is that the unique key makes it just calculate the next appropriate value on the fly.
I actually ended up making it work once I re-read an except on using AUTO_INCREMENT on multiple columns.
For MyISAM and BDB tables you can specify AUTO_INCREMENT on a
secondary column in a multiple-column index. In this case, the
generated value for the AUTO_INCREMENT column is calculated as
MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is
useful when you want to put data into ordered groups.
This was the clue I needed. I simply mimic'd the query MySQL runs internally according to that quote, and joined it into my UPDATE query as such. Assume $new_database is the database to move to, and $id is the current ticket id.
UPDATE `tickets` AS t1,
(
SELECT MAX(cid) + 1 AS new_cid
FROM `tickets`
WHERE database = {$new_database}
) AS t2
SET t1.cid = t2.new_cid,
t1.database = {$new_database}
WHERE t1.id = {$id}

MySQL Occasionally Returns Wrong Value

This is a general question, one that I've been scratching my head on for a while now. My company's database handles about 2k rows a day. 99.9% of the time, we have no problem with the values that are returned in the different SELECT statements that are set up. However, on a very rare occasion, our database will "glitch" and return the value for a completely different row than what was requested.
This is a very basic example:
+---------+-------------------------+
| row_id | columnvalue |
+---------+-------------------------+
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
| 4 | 40 |
+---------+-------------------------+
SELECT columnvalue FROM table_name WHERE row_id = 1 LIMIT 1
Returns: 10
But on the very rare occasion, it may return: 20, or 30, etc.
I am completely baffled as to why it does this sometimes and would appreciate some insight on what appears to be a programming phenomena.
More specific information:
SELECT
USERID, CONCAT( LAST, ', ', FIRST ) AS NAME, COMPANYID
FROM users, companies
WHERE users.COMPANYCODE = companies.COMPANYCODE
AND USERID = 9739 LIMIT 1
mysql> DESCRIBE users;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| USERID | int(10) | NO | PRI | NULL | auto_increment |
| COMPANYCODE| varchar(255)| NO | MUL | | |
| FIRST | varchar(255)| NO | MUL | | |
| LAST | varchar(255)| NO | MUL | | |
+------------+-------------+------+-----+---------+----------------+
mysql> DESCRIBE companies;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| COMPANYID | int(10) | NO | PRI | NULL | auto_increment |
| COMPANYCODE| varchar(255)| NO | MUL | | |
| COMPANYNAME| varchar(255)| NO | | | |
+------------+-------------+------+-----+---------+----------------+
What the results were suppose to be: 9739, "L----, E----", 2197
What the results were instead: 9739, "L----, E----", 3288
Basically, it returned the wrong company id based off the join with companycode. Given the nature of our company, I can't share any more information than that.
I have run this query 5k times and have made very modification to the code imaginable in order to generate the second set of results and I have no been able to duplicate it. I'm not quick to blame MySQL -- this has been happening (though rarely) for over 8 years, and have exhausted all other possible causes. I have suspected the results were manually changed after the query was ran, but the timestamps states otherwise.
I'm just scratching my head as to why this can run perfectly 499k out of 500k times.
Now that we have a more realistic query, I notice right away that you are joining the tables, not on the primary key, but on the company code. Are we certain that the company code is being enforced as a unique index on companies? The Limit 1 would hide a second row if such a row was found.
From a design perspective, I would make the join on the primary key to avoid even the possibility of duplicate keys and put company code in as a unique indexed field for display and lookup only.
This behavior is either due to an incredibly unlikely SERIOUS bug in MySQL, -or- MySQL is returning a result that is valid at the time the statement is run, and there is some other software that is garfing up the displayed result.
One possibility to consider is that the row had been modified (by some other statement) at the time your SQL statement executed, and then the row was changed again later. (That's the most likely explanation we'd have for MySQL returning an unexpected result.)
The use of the LIMIT 1 clause is curious, because if the predicate uniquely identifies a row, there should be no need for the LIMIT 1, since the query is guaranteed to return no more than one row.
This leads me to suspect that row_id is not unique, and that the query actually returns more than one row. With the LIMIT clause, there is no guarantee as to which of the rows will get returned (absent an ORDER BY clause.)
Otherwise, the most likely culprit is out dated cache contents, or other problems in the code.
UPDATE
The previous answer was based on the example query given; I purposefully omitted the possibility that EMP was a view that was doing a JOIN, since the question originally said it was a table, and the example query showed just the one table.
Based on the new information in the question, I suggest that you OMIT the LIMIT 1 clause from the query. That will identify that the query is returning more than one row.
From the table definitions, we see that the database isn't enforcing a UNIQUE constraint on the COMPANYCODE column in the COMPANY table.
We also know there isn't a foreign key defined, due to the mismatch between the datatypes.
Normally, the foreign key would be defined referencing the PRIMARY KEY of the target table.
What we'd expect the users table to have a company_id column, which references the id (primary key) column in the companies table.
(We note the datatype of the companycode column (int) matches the datatype of the primary key column in the companies table, and we note that the join condition is matching on the companycode column, even though the datatypes do not match, which is very odd.)
There are several reasons this could happen. I suggest you look at the assumptions you're making. For example:
If you're using GROUP BY and one of the columns isn't an aggregate or the grouping expression, you're going to get an unpredictable value in that column. Make sure you use an appropriate aggregation (such as MAX or MIN) to get a predictable result on each column.
If you're assuming a row order without making it explicit, and using LIMIT to get only the first row, the actual returned order of rows differs depending on that result's execution plan, which is going to differ in large resultsets based on the statistics available to the optimiser. Make sure you use ORDER BY in such situations.

How to add a series of string in incrementing id in any table?

I have MySQL Table with an Order table in a DB this table has an auto-incremental id. Up-till now we have general numeric Order-ID likewise 1,2,3,4,5... From now onwards I have to append the series A20 to my id like A20103, A20104, A20105 and so on and when the last three digits reaches 999 the series appended should get changed to A21001, A21002, A21003 and so on, the same series has to be added in the previously added orders..
How can i achieve this task? please guide
Altering an existing auto_increment column does not sound like a good idea - do you really have to do this? Instead, why not just modify your select query to return a suitably formatted id? By doing so, you maintain referential integrity, and you are also free to change the order id format at any time in the future, without having to update your database.
SELECT id, CONCAT('A2', LPAD(id, 4, '0')) AS order_id FROM <table>;
Example output:
+------+----------+
| id | order_id |
+------+----------+
| 1 | A20001 |
| 2 | A20002
...
| 999 | A20999 |
| 1000 | A21000 |
| 1001 | A21001 |
+------+----------+
something along the lines of:
"AR2" . str_pad((int) $ordernumber, 4, "0", STR_PAD_LEFT);
jim
[edit] - i'm assuming this is for display purposes as stated elsewhere, the ID field on the DB is integer!!
You can't have an auto-increment which is not a numeric field. You will better keep the current auto-incrementing column, and add a new one which you will compute manually according to your rules.
You'll probably want to use the MAX() function to get the latest order and generate the next value: remember to do it within a transaction.
You could create a function or a trigger, to do the insert cleanly for you.
You can't add prefixes directly to the database. However, when selecting it you can prepend it.
SELECT concat('A', id) as id FROM table
To get the effect of starting from 20000 you can set the auto increment starting value.

Get rowid from Mysql

i develop a project, in that i display the values from mysql database using PHP , in that i need to set a unique id[Not manually] for each row that i fetched from database.Can anyone help me please. Thanks in Advance.
Take a look at this article for how to create an auto incremented field to generate unique ID for the record:
http://www.plus2net.com/sql_tutorial/mysql_auto_increment.php
Basicly you use AUTO_INCREMENT attribute on the column.
This
CREATE TABLE animals (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO animals (name) VALUES
('dog'),('cat'),('penguin'),
('lax'),('whale'),('ostrich');
SELECT * FROM animals;
Will create this output:
+----+---------+
| id | name |
+----+---------+
| 1 | dog |
| 2 | cat |
| 3 | penguin |
| 4 | lax |
| 5 | whale |
| 6 | ostrich |
+----+---------+
How to automatically generate ids has already been answered. Additional info: If you want to see which id was inserted for a row, use mysql_insert_id()
Alternatively, you should already have a primary key or compound key, get a hash of these using the md5 function and store in memory. However, creating an auto incrementing field or a UUID field in the database would be the most preferable option.
HI, Even i have come across the same situation, where I need to display the row id. To implement this, i have created a separated table, where I Control the table with Stored Procedure, before it refills, I will delete all the records and reinserts with the latest Ranking systems. I am successful in this and implemented in
http://cricandcric.com/C&Guess/login.php

Categories