1

I have two forms that share some same columns: NAME, EMAIL, NOMINEE, DEPT, RANK and TIMESTAMP and I want to store those same columns in a new table called: TEACHING_AWARD_ALL_NOMINATIONS.

I have came up with the code to store each data into different table and then there should be some code to store the shared columns into TEACHING_AWARD_ALL_NOMINATIONS table.

I haven't came up with the code yet, please help!!!!

$srr = array_map('mysql_escape_string', $_REQUEST);

if ($srr['NOMINATIONTYPE'] == 'STUDENT')
    $fields = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'COURSE', 'YEARTERM', 'REQUIRED_FOR_MAJOR', 'MAJOR_LEARNING_OBJECTIVES', 'WHAT_EXTENT_INSTRUCTOR_HELP', 'RANK', 'RANK_COMMENT', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3', 'TEXTBOX_4', 'TEXTBOX_5');
else if ($srr['NOMINATIONTYPE'] == 'FACULTY')
    $fields = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'RANK', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3');
else die('error: no nomination type');

foreach ($fields as $f)
    $$f = $srr[$f];

$qry = "INSERT INTO TEACHING_AWARD_".$srr['NOMINATIONTYPE']."_NOMINATIONS (";
    foreach ($fields as $f) $qry .= $f . ", ";
    $qry = substr($qry, 0, -2);
    $qry .= ") VALUES (";
    foreach ($fields as $f) $qry .= "'" . $$f . "', ";
    $qry = substr($qry, 0, -2);
    $qry .= ")";

$result = mysql_query($qry) or die('An error ocurred: '.mysql_error());

echo 'Success! Thank you for submitting your nomination.';
Kumar V
  • 8,810
  • 9
  • 39
  • 58
Sio
  • 27
  • 1
  • 1
  • 9
  • As every user which is still using mysql_* commands in PHP I have to inform you about the [MySQLi extension](http://www.php.net/manual/de/book.mysqli.php) . Prepared statements would improve readability and security of your code alot (for example: String escaping) – th3falc0n Jan 10 '14 at 18:03
  • 1
    You are going through a lot of code building those SQL statements by hand. Further, **by building SQL statements with outside variables, you are leaving yourself wide open to SQL injection attacks.** Also, any input data with single quotes in it, like a name of "O'Malley", will blow up your SQL query. Please learn about using parametrized queries, preferably with the PDO module, to protect your web app. http://bobby-tables.com/php has examples to get you started, and [this question](http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php) has many examples in detail. – Andy Lester Jan 10 '14 at 18:10
  • Use `INSERT INTO ... SELECT`. This will be much faster since you're not sending the data over the network. – Marcus Adams Jan 10 '14 at 18:32

2 Answers2

2

WARNING! As noted in comments your original code is using deprecated functions and suffers from potential security issues. Check out the refactored solution that is using PDO, and yes you should use PDO too (instead of your current approach).

Check out the code below, untested but should do your job. As written above it uses PDO - check the docs here

    // obviously, first set your connection parameters $DbHost, $DbName etc.

    //connect to mysql
    $dbh = new PDO("mysql:host=".$DbHost.";dbname=".$DbName, $DbUser, $DbPass, array(PDO::ATTR_PERSISTENT => true));
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->query('SET NAMES UTF8'); //assuming you use utf-8 encoding

    //provide values array
    $values = $YourValuesArray;

    //set field types
    $fields = array();
    $fieldsStudent = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'COURSE', 'YEARTERM', 'REQUIRED_FOR_MAJOR', 'MAJOR_LEARNING_OBJECTIVES', 'WHAT_EXTENT_INSTRUCTOR_HELP', 'RANK', 'RANK_COMMENT', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3', 'TEXTBOX_4', 'TEXTBOX_5');
    $fieldsFaculty = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'RANK', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3');
    $fieldsAll = array_intersect($fieldsStudent, $fieldsFaculty);

    //pick the proper field set or die
    $fields = ($srr['NOMINATIONTYPE'] == 'STUDENT') ? $fieldsStudent : $fieldsFaculty;
    if(empty($fields)) die('error: no nomination type');

    //set tables
    $table = 'TEACHING_AWARD_'.$srr['NOMINATIONTYPE'].'_NOMINATIONS';
    $tableAll = 'TEACHING_AWARD_ALL_NOMINATIONS';

    //construct fields string
    $strFields = implode(",", $fields);
    $strFieldsAll = implode(",", $fieldsAll);

    //construct the placeholders string
    $strIns = implode(",", array_map(function($item){ return ":".$item; }, $fields)); 
    $strInsAll = implode(",", array_map(function($item){ return ":".$item; }, $fieldsAll)); 

    //insert specific data 
    $sql = "INSERT INTO $table ($strFields) VALUES ($strIns)";
    $sth = $dbh->prepare($sql);

    //bind values to placeholders
    foreach ($fields as $f)
    {
        $sth->bindValue(':' . $f, $values[$f]);
    }

    $sth->execute();

    //insert all data
    $sql = "INSERT INTO $tableAll ($strFieldsAll) VALUES ($strInsAll)";
    $sth = $dbh->prepare($sql);

    //bind values to placeholders
    foreach ($fieldsAll as $f)
    {
        $sth->bindValue(':' . $f, $values[$f]);
    }

    $sth->execute();

EDIT:

As per your comment, to select a UNIONed set of results using PDO you can use the below (untested) code:

    //connect to mysql
    $dbh = new PDO("mysql:host=".$DbHost.";dbname=".$DbName, $DbUser, $DbPass, array(PDO::ATTR_PERSISTENT => true));
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->query('SET NAMES UTF8'); //assuming you use utf-8 encoding

    $sql = "SELECT NAME, EMAIL, NOMINEE, DEPT, RANK, TIMESTAMP, 'STUDENT' AS TYPE FROM TEACHING_AWARD_STUDENT_NOMINATIONS 
    UNION 
    SELECT NAME, EMAIL, NOMINEE, DEPT, RANK, TIMESTAMP, 'FACULTY' AS TYPE FROM TEACHING_AWARD_FACULTY_NOMINATIONS";

    $sth = $dbh->prepare($sql);
    $sth->execute();

    //init result array
    $results = array();

    //fetch the results into an array
    while($row = $sth->fetch(PDO::FETCH_ASSOC))
        $results[] = $row;

    //show results or do whatever else you need
    print_r($results);
Gadoma
  • 6,475
  • 1
  • 31
  • 34
  • If OP is going to switch to PDO, then all that SQL building gets to go away. – Andy Lester Jan 10 '14 at 18:10
  • @AndyLester I edited my answer to include a more appropriate solution, that uses PDO. – Gadoma Jan 10 '14 at 18:37
  • do you think create view instead of creating table is a good idea? I want to show the view in phpmyadmin instead of print out the view on the submitted page. But the question is, whenever the user submitted the form, can mysql update the view? I don't want to give the view a new name whenever the user submit the form. – Sio Jan 10 '14 at 19:26
1

You could try making two arrays, one for the "shared" columns (NAME, EMAIL, etc.) and another for the "type-specific" columns (COURSE, YEARTERM, etc.). Then, when you are building up your SQL statement, do a foreach on the "shared" columns followed immediately by the "type-specific" columns to simulate the entire table. It might look something like this:

$qry = "INSERT INTO TEACHING_AWARD_".$srr['NOMINATIONTYPE']."_NOMINATIONS (";
    foreach ($fields_shared as $f) $qry .= $f . ", ";
    foreach ($fields_typespecific as $f) $qry .= $f . ", ";
    $qry = substr($qry, 0, -2);
    $qry .= ") VALUES (";
    foreach ($fields_shared as $f) $qry .= "'" . $$f . "', ";
    foreach ($fields_typespecific as $f) $qry .= "'" . $$f . "', ";
    $qry = substr($qry, 0, -2);
    $qry .= ")";

I would also agree with th3falc0n's comment about looking into preparing your SQL statements with more robust tools.

Another consideration: rather than enter redundant data into a TEACHING_AWARD_ALL_NOMINATIONS table, why not simply make that a view that pulls all shared columns from each type-specific table (likely using a UNION statement)? This prevents redundant data and would make data maintenance easier (e.g. when a nomination is deleted from one of the type-specific table, it automatically vanishes from the ALL_NOMINATIONS view, etc.).

Gerf
  • 311
  • 1
  • 4
  • if I create a view, where I can see the view? and how to add below statement into my original code? "$sql = "( SELECT NAME, EMAIL, NOMINEE, DEPT, RANK, TIMESTAMP, 'STUDENT' AS TYPE FROM TEACHING_AWARD_STUDENT_NOMINATIONS ) UNION ( SELECT NAME, EMAIL, NOMINEE, DEPT, RANK, TIMESTAMP, 'FACULTY' AS TYPE FROM TEACHING_AWARD_FACULTY_NOMINATIONS )";" – Sio Jan 10 '14 at 18:49
  • @user3170649 check out my edited answer for code you can use to select UNIONed results – Gadoma Jan 10 '14 at 19:15
  • @user3170649 If you are unfamiliar with views, I'd recommend taking a look at them as they can be quite powerful tools. A generic description is [here](http://en.wikipedia.org/wiki/View_%28SQL%29), while specific MySQL implementation details can be found [here](http://dev.mysql.com/doc/refman/5.7/en/create-view.html). – Gerf Jan 10 '14 at 19:32