explode does not work - php

This Code is for inserting Units for certain specifications.
for example, if specification is length, then units are centimeter, meter and millimeter.
When I try to read all units in single text field with commas and in PHP tried to explode the units with comma.
But when I submit the form only the first unit is saved to DB.
This is my database structure:
CREATE TABLE IF NOT EXISTS `tbl_unit` (
`unit_id` varchar(5) NOT NULL,
`unit_name` varchar(50) NOT NULL,
`specification_id` int(11) NOT NULL,
PRIMARY KEY (`unit_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
This is my code:
<?php
include("../config.php");
$uid=$_POST['unitid'];
$unit=$_POST['unitname'];
$spec=$_POST['specification'];
$arr1 = explode(',',$unit);
$size=count($arr1);
for($i=0;$i<$size;$i++)
{
mysql_query("insert into tbl_unit values('".$uid."','$arr1[$i]','".$specification."')");
}
header('Location:addunit.php');
?>
What is confusing me is that when I try to insert $arr1[0], $arr1[1] or $arr1[2] separately the values are being saved. I think the for loop is executing only once. what is the problem with for loop?

The problem is that unit_id is a primary key in your table, but you are trying to insert multiple records with the same value for this column. Each time through the loop, you insert using the same unit_id value, but a different unit_name value. You can't do that as long as unit_id is a primary (or unique) key.

You have a 'primary key' constraint on unit_id, hence the first insert succeeds, but all the subsequent ones fail.
There are many other things I could point out here, but without having the full picture, I am just listing some major ones:
1) In mysql, it is preferable for a int primary key, so it is best to have such a column explicitly even if you don't use it. The 'unit_id' column which is a varchar can still have 'unique key' constraints if you want to enforce it.
2) If you have a unique constraint on 'unit_id', you will have to re-think your table spec. on how you want to capture multiple units. Maybe it should just be indexed without a unique constraint?
3) You haven't escaped or sanitized the input from $_POST before inserting them in a table - makes it vulnerable to SQL injection attacks
4) Depending upon the size of the array, you could do a 'batch insert' rather than looping for each insert - i.e. a singly mysql inset call with multiple row values supplied.
5) Minor thing on 'explode()' - it has a very subtle behavior on empty strings, so it is best to check for that (maybe as part of data sanitization checks mentioned in point 3) - e.g.:
php -r '$a = explode(",", ""); var_dump($a);'
array(1) {
[0]=>
string(0) ""
}

Related

Prevent duplicate data in a table with more than 20000 records

everyday i add almost 5000 new records in mysql and i want to prevent insert duplicate row in table,i think i should check all of the bank befor any insert operation,is it suitable?
Or there is any better way to do that??
thanks in advance
It's a good choice to prevent the data model beeing corrupted by software by applying a unique index to the field attributes which must not be duplicatable.
It's even better to ask the database for duplicate candidates before inserting data.
The best is, to have both combined. The security on the database model and the question for duplicates in the software layer because a) error handling is much more expensive than querying and b) the constraint protects the data from human failure.
mysql supports unique indexes with the CREATE UNIQUE INDEX statement.
e.g: CREATE UNIQUE INDEX IDX_FOO ON BAR(X,Y,Z);
creates a unique index on table BAR. This index will also be used when running the query for duplicates - speeds up the processing very much.
See MySQL Documentation for more details.
When you have a data integrity issue, you want the database to enforce the rules (if possible). In your case, you do this with a unique index or unique constraint, which are two names for the same thing. Here is sample syntax:
create unique index idx_table_col1_col2 on table(col1, col2)
You want to do this in the database, for three reasons:
You want the database to know that that column is unique.
You do not want a multi-threaded application to "accidentally" insert duplicate values.
You do not want to put such important checks into the application, where they might "accidentally" be removed.
MySQL then has very useful constructs to deal with duplicates, in particular, insert . . . on duplicate key update, insert ignore, and replace.
When you run SQL queries from your application, you should be checking for errors anyway, so catching duplicate key errors should be no additional burden on the application.
Firstly, any column that needs to be unique you can use the UNIQUE constraint:
CREATE TABLE IF NOT EXISTS tableName
(id SERIAL, someUniqueColumnName VARCHAR(255) NOT NULL UNIQUE);
See the MySQL Documentation for adding uniqueness to existing columns.
You need to decide what constitutes a duplicate in your table, because uniqueness is not always restricted to a single column. For instance, in a table where you store users with a corresponding id for something else, then it may be both combined which have to be unique. For that you can have PRIMARY KEY which uses two columns:
CREATE TABLE IF NOT EXISTS tableName (
id BIGINT(20) UNSIGNED NOT NULL,
pictureId BIGINT(20) UNSIGNED NOT NULL,
someOtherColumn VARCHAR(12),
PRIMARY KEY(id, pictureId));

How to select a multiple column primary key of an inserted row?

Problem:
I have the following table in MySQL.
For this example lets say that there is (and always will be) only one person in the world called "Tom" "Bell". So (name, surname) is the PRIMARY KEY in my table. Every person has his salary, an unsigned integer.
CREATE TABLE IF NOT EXISTS `user` (
`name` varchar(64) NOT NULL DEFAULT 'Default_name',
`surname` varchar(64) NOT NULL DEFAULT 'Default_surname',
`salary` int(10) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY `id` (`name`,`surname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Whenever I insert a row using a PHP script I want my function to return the primary key of the inserted row (an array key=>value).
From PHP context I do not know what the primary key of table 'user' consists of and I do not always need to set all primary key values (example 2, very stupid, but possible).
I can add another argument to my insert function (for example I could pass the table name, in this case "user").
If this matters, I am using PDO (php data objects) to connect with my MySQL database.
Example 1:
$db->insert('INSERT INTO `user` (`name`,`surname`,`salary`) VALUES ('Tom','Bell','40');');
should return an array:
$arr = ['name' => 'Tom', 'surname' => 'Bell'];
Example 2:
$db->insert('INSERT INTO `user` (`name`,`salary`) VALUES ('Nelly','40');');
should return an array:
$arr = ['name' => 'Nelly', 'surname' => 'Default_surname'];
Disclaimer & other information:
I know this is not a well-designed table, I could use an auto_increment id column to make it much easier and probably more efficient as well. This is just an example to show the problem without having to explain my project structure.
Without loss of generality: Using functions like "getLastInsertId()" or "##identity" will return 0, I guess the reason is because the table does not have an auto_increment column.
What have I tried? Nothing (other than things stated in point 2 (which I was certain it wouldn't work) and searching for a solution).
There aren't "nice" ways around this problem. One of the reasons for having an auto_increment is to avoid having problems like you described.
Now, to avoid my answer to be one of those that take into account only half the picture - I do realize that sometimes you inherit a project or you simply screw up during initial stages and you have to fix things quickly.
To reflect on your example - your PK is a natural PK, not a surrogate one like auto_increment is. Due to that fact it's implied that you always know the PK.
In your example #1 - you inserted Tom Bell - that means you knew the PK was Tom Bell since you instructed MySQL to insert it. Therefore, since you knew what the PK was even before insert, you know how to return it.
In your example #2 you specified only a part of the PK. However, your table definition says thtat default values for both name and surname are Default_surname. That means, if you omit either part of the PK, you know it'll assume the default value. That also means you already know before insertion what the PK is.
Since you have to use a natural PK instead of a surrogate, the responsibility of "knowing" it shifts to you instead of RDBMS. There is no other way of performing this action. The problem becomes even more complex if you allow for a default value to become null. That would let you insert more than 1 Tom with null as surname, and the index constraint wouldn't apply (null is not equal to null, therefore (tom, null) is not equal to (tom, null) and insert can proceed).
Long story short is that you need a surrogate PK or the auto_increment. It does everything you require based on the description. If you can't use it then you have a huge problem at your hands that might not be solvable.

Does primary index in mysql table automatically have a value when new row is added?

So, assuming I have a table, with 20 columns, and I want to insert data to them, and the first column is just a primary index, which will automatically have a numerical value if I don't assign one to it. Primary index has auto increment on.
So my question is, do I always have to do it like this (which is pretty annoying and slow)
INSERT INTO table (col1,col2,col3,col4,col5,col6) VALUES (col1value,col2value,col3value,col4,value,col5value,col6value)
or, could I just specify the values (assuming that I'm filling every column except the primary index) like this
INSERT INTO table VALUES (col1values,col2values,col3values,col4values,col5values,col6values)
or will it break the table?
No, you can't use your second solution, unless you provide as many values as field count. You can still provide primary key value with NULL. MySQL will then replace it by an auto-incremented value (assuming your column is PRIMARY KEY + AUTO_INCREMENT).
Nevertheless, the first solution is perfectly fine.
tldr; You need to define the columns you are inserting into.
Mysql assumes that when you don't put in the column names like below
INSERT INTO table (column_name1, column_name2, column_name3)
that you are going to define all the columns in your value definition later. Without defining the column names, it wouldn't know which row to skip for the primary key.
An example of this would be if you had the primary key as column_name2 in the above example.
The first one is correct.
In the second one you can specify the primary key attribute as null or using INSERT INTO table VALUES('',col2values,col3values,col4values,col5values,col6values) assuming that the first field is primary key.

move a mysql database row up or down with php

I have a mysql database and some php that allows you to create an entry in the database, update an entry, and view the entries as a web page or xml. What I want to do is add a function to move an entry in the database up or down by one row, or, send to the top of the database or bottom.
I've seen some online comments about doing this type of thing that suggested doing a dynamic sort when displaying the page, but I'm looking for a persistent resort. I've seen one approach suggested that would be to have a separate "sort" field in the database that is agnostic of the actual database sort key, but I'm not sure why that would be better than actually re-ordering the database
Here is a dump of the table structure:
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
--
-- Database: `hlnManager`
--
-- --------------------------------------------------------
--
-- Table structure for table `hln_stations`
--
CREATE TABLE IF NOT EXISTS `hln_stations` (
`id` int(6) NOT NULL auto_increment,
`station_title` varchar(60) NOT NULL default '',
`station_display_name` varchar(60) NOT NULL default '',
`station_subtitle` varchar(60) NOT NULL default '',
`station_detailed_description` text NOT NULL,
`stream_url_or_playlist_url` text NOT NULL,
`link_type` varchar(25) NOT NULL default '',
`small_thumbnail_graphic_url` text NOT NULL,
`large_thumbnail_graphic_url` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;
Not sure what you mean by "Reordering" the database... SQL Databases typically do not make any guarantees on what order (if any) they will return records in short of an ORDER BY clause.
You need a "SortOrder" type column. I suggest you make it an int with a unique key.
You need a way to update this "SortOrder" column via the UI
Easy to program, easy to use: Implement a simple drag+drop interface in HTML using jQuery or whatever javascript library works for you. In the on-complete method (or in response to a save button), trigger an ajax call which will simply send an array of ids in the correct order. On the database side, loop over it and update the SortOrder accordingly, starting at 1, then 2, etc...
Harder to program, hard to use: Implement a classical move-up and move-down buttons. When clicked, send the id and action (eg, up, down) to the server. There are several strategies to handle this update, but I will outline a couple:
Assuming the user clicked "move up", you can swap IDs with the previous record.
Find the previous record: SELECT id FROM hln_stations WHERE SortOrder < (SELECT SortOrder FROM hln_stations WHERE id = ...) ORDER BY SortOrder DESC LIMIT 1
Run two update statements, swapping the SortOrder. Reverse for moving down. Add special code to detect top or bottom.
etc...
There are other ways, but for a web interface, I suggest you do Drag+Drop, as the users will love it.
Databases are not "stored" in any order. They are stored in whatever way is convenient for the storage subsystem. If you delete a record, a new record may use the space of the old record "inserting" itself into the database. While it may seem like the database always returns records in a particular order, you can't rely on it.
The ONLY way to assure a sort order is to have a field to sort on.
Dont know where you can find example to find example. but you can look the following code it is very basic:
Let id is your primary key and there is a column sort_order. You want to store primary keys in the following order: 5,4,3,6,8,7,9,10,2,1.
then you store them in an array:
$my_sorted = array(5,4,3,6,8,7,9,10,2,1);
then you update your table:
update `mytable` set `sort_order` = (index of $my_sorted) WHERE `id`=(array value of that index).
Instead of doing many queries you can do it in one query like:
$query = "UPDATE `mytable` SET sort_order= CASE id ";
foreach($my_sorted as $key=>$val){
$query .= " WHEN '$val' THEN $key ";
}
$query .="END";
Then you run $query in mysql.
After updating table you can select from mytable with order by sort_order asc or desc.
hope this helps.
"re-ordering" the database would require two records swapping primary keys, or most likely they would need to have all data except the primary keys be swapped. this would most likely be undesireable, since the primary key should be the one way you can consistently refer to a particular record.
The separate order field would be the way to go. Just make sure that you put an index on the order field so that things stay speedy.
There is no way to find out in which order databases stores data. When we query to database, we specify the field name that we want our data to be sorted by.
In your case, I would add a new column: sequence int(10). and write php function to change/update sequence number. when i will use select query, I will order by sequence number.

MySQL: UPDATEing a row with no guaranteed unique field

I am working with an old MySQL table, which serves as a log of sorts. It looks like
CREATE TABLE `queries` (
`Email` char(32) NOT NULL DEFAULT '',
`Query` blob,
`NumRecords` int(5) unsigned DEFAULT NULL,
`Date` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Now, I need to be able to UPDATE the records in this table (don't ask why, I don't know). Normally, I would just do
UPDATE table SET ... WHERE unique_column = value
But in this case, I don't have a unique column to work from.
Is there a workaround for this, or am I just going to have to push to put in a nice, standard INT NOT NULL AUTO_INCREMENT?
UPDATE queries
SET ...
WHERE Email = value1
AND Query = value2
AND NumRecords = value3
AND Date = value4
LIMIT 1;
A unique identifier is the only reliable way of doing this. Just add an auto_increment column and be done with it.
For exhaustive info including some workaround approaches (none of them perfect though!) check this question, where the OP had a table without a unique identifier and no way to change it.
Update: As Doug Currie points out, this is not entirely true: A unique ID is not necessary as such here. I still strongly recommend the practice of always using one. If two users decide to update two different rows that are exact duplicates of each other at the exact same time (e.g. by selecting a row in a GUI), there could be collisions because it's not possible to define which row is targeted by which operation. It's a microscopic possibility and in the case at hand probably totally negligeable, but it's not good design.
There are two different issues here. First, is de-duping the table. That is an entirely different question and solution which might involve adding a auto_increment column. However, if you are not going to de-dup the table, then by definition, two rows with the same data represent the same instance of information and both ought to be updated if they match the filtering criteria. So, either add a unique key, de-dup the table (in which case uniqueness is based on the combination of all columns) or update all matching rows.
In case you didn't know this, it will affect performance, but you don't need to use a primary key in your WHERE clause when updating a record. You can single out a row by specifying the existing values:
UPDATE queries
SET Query = 'whatever'
WHERE Email = 'whatever#whatever.com' AND
Query = 'whatever' AND
NumRecords = 42 AND
Date = '1969-01-01'
If there are duplicate rows, why not update them all, since you can't differentiate anyway?
You just can't do it with a GUI interface in MySQL Query Browser.
If you need to start differentiating the rows, then add an autoincrement integer field, and you'll be able to edit them in MySQL Query Browser too.
Delete the duplicates first. What's the point of having duplicate rows in the table (or any table for that matter)?
Once you've deleted the duplicates you can implement the key and they your problem is solved.

Categories