SQL throws an error when two columns have the same value - php

I want to insert a record if it does not exist without using unique ID, and I found this answer here: MySQL: Insert record if not exists in table.
In my case I have a table:
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| ID | dRelIns | vRelIns | dRelDel | vRelDel | cRelAktiv | iRelDateiId | iRelKatId |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| 1 | blabla | blabla | NULL | NULL | J | 3 | 5 |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| 2 | blabla | blabla | blabla | blabla | N | 3 | 1 |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| 3 | blabla | blabla | NULL | NULL | J | 3 | 2 |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
I am getting an array ($_POST) with id iRelKatId and another on id iRelDateiId. I check if the id already exists and cRelAktiv = 'J', if not I want to insert a new one. If some entry exists but it's not in the list, I want to set cRelAktiv to 'N'.
My PHP script with the SQL queries:
$list=implode("','", $_POST["kat"]);
$sql="UPDATE tabRel_UDK SET dRelDel=NOW(),
vRelDel=USER(),
cRelAktiv='N'
WHERE iRelDateiId='$_POST[id]' AND cRelAktiv='J' AND iRelKatId NOT IN('$list')";
$result = mysql_query($sql) or die(Error (" . mysql_error() . ").");
foreach ($_POST["kat"] as $value) {
$sql="INSERT INTO tabRel_UDK (dRelIns, vRelIns, cRelAktiv, iRelDateiId, iRelKatId)
SELECT * FROM (SELECT NOW(), USER(), 'J', '$_POST[id]','$value') AS tmp
WHERE NOT EXISTS (
SELECT iRelDateiId,iRelKatId,cRelAktiv FROM tabRel_UDK
WHERE iRelDateiId = '$_POST[id]' AND iRelKatId='$value' AND cRelAktiv='J') LIMIT 1;";
$result = mysql_query($sql) or die("Error (" . mysql_error() . ").");
}
This script works for me, but when both ids have the same value(for example 5), it throws an error Duplicate column name '5' because of SELECT * FROM (SELECT NOW(), USER(), 'J', '$_POST[id]','$value')
Any ideas how to make it works, or should I make 2-3 SQL queries and check the ids manually in PHP?

I suspect $_POST[id] and $value have the same value, and so you appear to be selecting the same column twice. This should be suppressed in code, so you only select it once - or you should be giving each an alias so this does not happen.
I wouldn't recommend returning a resultset with column names starting with a number anyway - in some database systems that would not be permitted, unless it is quoted. Give them string prefixes as aliases, ending in _<number> if you must.
Thus, your subselect string might look like this:
"SELECT * FROM (
SELECT
NOW(),
USER(),
'J',
'{$_POST['id']}' AS val_1,
'{$value}' AS val_2
) WHERE ..."
More importantly, having $_POST[id] in your code will open you up to SQL injection vulnerabilities - always escape data before using it. Even better, switch to MySQL PDO and use parameterisation.
Lastly, the variable should be $_POST['id'] - PHP assumes that you meant a string index, but it will raise a warning if you skip the quotes. Turn on warnings so you can see mistakes like this.

Related

PHP Mysql Insert Batch if not exist

I have searched that there is already a way in inserting avoiding the duplicate error
ref: MySQL: Insert record if not exists in table
INSERT INTO table_listnames (name, address, tele)
SELECT * FROM (SELECT 'Unknown' AS name, 'Unknown' AS address, '022' AS tele) AS tmp
WHERE NOT EXISTS (
SELECT name FROM table_listnames WHERE name = 'Unknown'
) LIMIT 1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM `table_listnames`;
+----+---------+-----------+------+
| id | name | address | tele |
+----+---------+-----------+------+
| 1 | Rupert | Somewhere | 022 |
| 2 | John | Doe | 022 |
| 3 | Unknown | Unknown | 022 |
+----+---------+-----------+------+
is there a way for this to do in batch?
or how is the format in adding data as a batch
ref: insert multiple rows via a php array into mysql
Planning to integrate this one
$sql = array();
foreach( $data as $row ) {
$sql[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $sql));
is there a way?
I would suggest using the ON DUPLICATE KEY syntax for this. This will simplify the query, and allow the use of the VALUES() statement, which is handy to pass parameters from your application.
For this to work, you need a unique (or primary key) constraint on colum name. Create it if it does not exist:
create unique index idx_table_listnames on table_listnames(name);
Then, you can do:
insert into table_listnames(name, address, tele)
values('Unknown', 'Unknown', '022')
on duplicate key update name = values(name)
The conflict clause traps violations on the unique index, and performs a no-op update.
Side note: use parameterized queries to pass data from your application to the query; escaping input is not enough to make your query safe.

choose rows where 10 columns

I want to get a rows using one string, but this string is used to validate more than 1 column, exactly 5, for example
-----------------------------------------------
| id | code | 1 | 2 | 3 | 4 | 5 |
-----------------------------------------------
| 01 | Number | 5 | 7 | 10 | 21 | 1 |
| 02 | String | v | q | s | f | w |
| | | | | | | |
| | | | | | | |
| | | | | | | |
-----------------------------------------------
I want to make SELECT mysqli where using 5 columns ( 1, 2, 3, 4, 5 ) if i use looping method, it will waste a lot of time
i have tried the problem with this code
$value = "q";
for ($x = 1; $x <= 5; $x++) {
$cek = mysqli_query($con,"SELECT * FROM table where $x='$value' and id='02'")
if(mysqli_num_rows($cek) == 1) {
echo "success";
} else {
echo "fail";
}
}
I use this code successfully, but the process is too long
is there an easier and more practical way to overcome this problem? thank you
As has been pointed out in comments, your database design is sub-optimal. You may want to reconsider and change it. Also, having column names be 1, 2, etc. is a very bad idea. At least have them start with a letter. Better yet, give them some reasonable names indicating what data those columns actually contain.
Now, assuming you figured out what your column names should really be, you can use a simple IN operator to get your data. The usual/common way of using it is
WHERE some_column IN ('value1', 'value2', ...)
Yet, there's nothing preventing you from using it the other way around:
WHERE 'some_value' IN (column1, column2, ...)
This way, your SQL statement becomes something like this:
SELECT *
FROM table
WHERE '$value' IN (column1, column2, column3, column4, column5)
AND id='02'
Now, if you have your column names in an array, you can do it this way:
$testColumns = ['column1', 'column2', 'column3', 'column4', 'column5'];
$value = "q";
$inColumns = implode(',', $testColumns);
$sql = "SELECT * FROM table WHERE '$value' IN ($inColumns) AND id='02'";
$cek = mysqli_query($con, $sql);
UPDATE: If your column names are non-standard, e.g. the aforementioned 1, 2, etc., or have spaces in them, then simple implode will not work, because you need to back-quote each column name. In that case, you would need something like this:
$inColumns = implode(',', array_map(function($c) { return "`$c`"; }, $columns));

Not adding 1, but 2, 3 or 4 when UPDATEing mysql with PHP

I have this table called classes:
+------------+----------+------+-----+----------------+
| Field | Type | Null | Key | Extra |
+------------+----------+------+-----+----------------+
| class_id | int(3) | NO | PRI | auto_increment |
| class_level| int(1) | YES | | |
| class_name | char(1) | YES | | |
+------------+----------+------+-----+----------------+
With data inside like this:
+----------+-------------+------------+
| class_id | class_level | class_name |
+----------+-------------+------------+
| 1 | 0 | N |
| 2 | 1 | A |
| 3 | 1 | B |
| 4 | 2 | C |
| 5 | 2 | D |
| 6 | 3 | E |
| 7 | 3 | F |
+----------+-------------+------------+
With PHP I want to increment all values inside class_level except 0.
So I made this PHP/MySQL function:
mysql_query("UPDATE classes SET class_level = (class_level + 1) WHERE class_level != 0") or die(mysql_error());
This (what is weird) does not add 1 to each class_level except theese equal to 0, but adds 2 or 3 or 4! I haven't found a rule, that this script would add either 2 or 3 or 4. This is RANDOMLY picked. And there is no error outputted too.
All it does it adds randomly 2 or 3 or 4 to each row.
So, to debug it, I have done this PHP code to add to each one by one:
$query = mysql_query("SELECT * FROM `classes` WHERE `class_level` != 0");
while ($row = mysql_fetch_assoc($query)) {
$class_id = $row['class_id'];
$class_level = $row['class_level'];
$class_level = $class_level + 1;
var_dump($class_level);
mysql_query("UPDATE `classes` SET `class_level` = '$class_level' WHERE `class_id` = '$class_id'") or die(mysql_error());
}
The output from var_dump is:
int(2) int(2) int(3) int(3) int(4) int(4)
But in database in table I get following result:
+----------+-------------+------------+
| class_id | class_level | class_name |
+----------+-------------+------------+
| 1 | 0 | N |
| 2 | 4 | A |
| 3 | 4 | B |
| 3 | 5 | C |
| 4 | 5 | D |
| 5 | 6 | E |
| 6 | 6 | F |
+----------+-------------+------------+
This is an empty file with just MySQL connection and the code above, so there is no loop above it.
Here is my version information: PHP version: 5.2.12, MySQL Client API version 5.1.44. Note that I cannot install mysqli nor PDO.
EDIT:
Just after executing the MySQL query I have outputted data from table, and the result was, as it should be. But in table itself (or on refresh with code just for output) there was 3 added, not 1!
EDIT 2:
I tried executing this MySQL query from command line (aka Webmin tool for SQL commands) and the result was, as it should be: 1 was added.
EDIT
Added SQL Fiddle demonstration: http://sqlfiddle.com/#!9/efa05b/1
create table classes
( class_id int(3) not null auto_increment primary key comment 'pk'
, class_level int(1)
, class_name char(1)
)
;
insert into classes (class_id,class_level,class_name) values
('1','0','N')
,('2','1','A')
,('3','1','B')
,('4','2','C')
,('5','2','D')
,('6','3','E')
,('7','3','F')
;
update classes set class_level = (class_level + 1) where class_level != 0
;
A query verifies that expected result is returned. Each row (other than row with class_level=0) has been updated, with class_level incremented by exactly 1.
select * from classes order by class_id
class_id class_level class_name
-------- ----------- ----------
1 0 N
2 2 A
3 2 B
4 3 C
5 3 D
6 4 E
7 4 F
original answer
Assuming that there isn't a BEFORE/AFTER UPDATE trigger on the table, given the SQL statement being executed:
UPDATE classes SET class_level = (class_level + 1) WHERE class_level != 0
The most logical explanation for the behavior is that the SQL statement is being executed multiple times within the function, or, the function is being called multiple times.
To verify this, you could temporarily turn on the MySQL general log, run the test, disable the general log, and review... and you're going to find multiple executions of the statement. If you don't have access to the MySQL server, then the next best would be to echo out a line immediately before the statement is executed; you're going to see that line echoed out multiple times.
Highly unlikely that this is a bug in the MySQL database. (Verify there isn't a TRIGGER defined on the table.)
Also, test that statement using a different client, like mysql command like client, or phpmyadmin. And verify the statement is working correctly.
FOLLOWUP
Given that your test of the SQL statement from a different client gives the expected results, I think this demonstrates this isn't a problem with the MySQL database or the SQL statement.
For some reason, that SQL statement is being executed multiple times. As a next step in debugging, I would add some more code. I'd temporarily create a "log" table, using MyISAM engine, containing an auto_increment id, a datetime column, and an informational string:
CREATE TABLE debug_log
( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
, dt DATETIME
, info VARCHAR(40)
) Engine=MyISAM
Then add another SQL statement in your function to insert a row to that table, immediately before and/or after the execution of the UPDATE statement
INSERT INTO debug_log (dt, info) VALUES (SYSDATE(), 'my function before update')
Then, run the test, and see how many rows get inserted into the debug_log table.
To get an error thrown if this statement is executed more than one time, supply a fixed value for the id column, e.g.
INSERT INTO debug_log (id, dt, info)
VALUES (123, SYSDATE(), 'my function before update')
With the fixed value for id, if that statement gets called a second time, then MySQL will throw a duplicate key exception.
As I mentioned previously, based on the information provided, I suspect that your function is being called multiple times. (I don't have sufficient information to actually make that determination; that's just a hunch.)
Here is the simple solution below
<?php
print("<h1>BEFORE</h1>");
$q =mysql_query("select *from classes ");
while($row=mysql_fetch_array($q)){
print("$row['class_id'] - $row['class_level'] - row[$class_name] <br/>");
}
mysql_query("UPDATE classes SET class_level = class_level+1 WHERE class_level>0") or die(mysql_error());
print("<h1>AFTER</h1>");
$q =mysql_query("select *from classes ");
while($row=mysql_fetch_array($q)){
print("$row['class_id'] - $row['class_level'] - row[$class_name] <br/>");
}
?>
You dnt need to write any single php line to do what you are actually want to do.
Ok i have updated the code try this way. First it will get data & show . Secondly ,it will update the data .finally,display the data. Try this way hope you can find your problem.
I solved this by simply doing something like this:
mysql_query("UPDATE classes SET class_level = 2 WHERE class_level = 1");
mysql_query("UPDATE classes SET class_level = 3 WHERE class_level = 2");
mysql_query("UPDATE classes SET class_level = 4 WHERE class_level = 3");
I have just those three classes so it gets the job done.
It isn't the way I wanted to go with, but it works. The bug was really odd and I'd rather not go back to it. I hope this helps someone though.
P.S. How could I possibly not think about that in the first place XD

Exploding in php

In my table 'users' there are 'friends' ,
Like this :
+----+------+---------+
| id | name | friends |
+----+------+---------+
| 1 | a | 0,1,2 |
| 2 | b | 0,1,3 |
| 3 | c | 0,1 |
+----+------+---------+
How do I use the explode function to get the friends id one by one (not 0,1,2) that are separated by a comma (,) ;
How do I select the id? (Example) :
$sql = Select id from users where id = (exploded)
if (mysql_num_rows($sql) > 0 ) {
$TPL->addbutton('Unfriend');
}else{
$TPL->addbutton('Add as Friend')
}
The solution here is actually a slight change in your database structure. I recommend you create a "many-to-many" relational table containing all of the users friends referenced by user.
+---------+-----------+
| user_id | firend_id |
+---------+-----------+
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
| 2 | 5 |
+---------+-----------+
If you are storing lists of values within one field then that is the first sign that your database design is not quite optimal. If you need to search for a numerical value, it'll always be better to place an index on that field to increase efficiency and make the database work for you and not the other way around :)
Then to find out if a user is a friend of someone, you'll query this table -
SELECT * FROM users_friends WHERE
`user_id` = CURRENT_USER AND `friend_id` = OTHER_USER
To get all the friends of a certain user you would do this -
SELECT * FROM users_friends WHERE `user_id` = CURRENT_USER
Just a simple example that will make you clear how to proceed:
// Obtain an array of single values from data like "1,2,3"...
$friends = explode(',', $row['friends']);
Then, back in your query:
// Obtain back data like "1,2,3" from an array of single values...
$frieldslist = implode(',', $friends);
$sql = "SELECT * FROM users WHERE id IN ('" . $frieldslist . "')";
to get an array of if ids from your string explode would be used like this
$my_array = explode("," , $friends);
but you'd probably be better using the mysql IN clause
$sql = "Select id from users where id in (".$row['friends'].")";
Just a quick idea. Change your database's table. It is certain that after a while many problems will arise.
You could have something like this.
id hasfriend
1 2
1 3
2 1 no need to be here (You have this already)
2 4
.....
You can do this by using indexes for uniqueness or programming. You may think of something better. Change your approach to the problem to something like this.

MySQL escaped strings problem

In some PHP code, I have an mysql_real_escape_string()'d term, like foo\'s. I search that in my database (where it is also stored as foo\'s) like so:
mysql_query("SELECT * FROM coupons WHERE retailerName LIKE '%" . $searchTerm . "%'");
The query should look like this without variables:
SELECT * FROM coupons WHERE retailerName LIKE '%foo\'s%'
If I search f, fo, or foo, then the search works. But if I search foo's then the search doesn't work (keep in mind that the actual query takes an escaped string, so everything should match up).
Perhaps the interface from you program to mysql (JDBC or similar) is adding extra escape characters to your string. If the same mechanism is not what put the data into the database, try doing an insert to see how the data gets stored.
Mysql can handle the query through it's own interface
mysql> describe test_table;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| col1 | varchar(20) | YES | | NULL | |
| col2 | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
mysql> insert into test_table (col1, col2) values ('col1value', 'foo\'s');
Query OK, 1 row affected (0.04 sec)
mysql> select * from test_table where col2 like '%foo\'s%';
+-----------+-------+
| col1 | col2 |
+-----------+-------+
| col1value | foo's |
+-----------+-------+
1 row in set (0.00 sec)
If it's stored as foo\'s in DB, then there are 2 options - either you are double-escaping (i.e., using mysql_real_escape_string() twice), or you are escaping values that "something" (e.g., magic quotes) has already slashed.
Check if you have magic_quotes_gpc enabled.
Here's PHP5.3 code for stripping "magic quotes" automatically (can be used in config file). For older PHP, callback function would look differently, but you should get the idea from this.
// remove slashes, if they are being automatically added
if ( get_magic_quotes_gpc () ) {
$stripslashes = function($value) use(&$stripslashes) {
if ( is_array($value) ) {
return array_map($stripslashes, $value);
}
return stripslashes($value);
};
$_GET = array_map($stripslashes, $_GET);
$_POST = array_map($stripslashes, $_POST);
$_COOKIE = array_map($stripslashes, $_COOKIE);
unset($stripslashes);
}

Categories