Upload multiple files from multiple inputs with PHP and insert the filename into a database.

I want to upload multiple files to my server with PHP and insert the filename, given description and some other things to my database.

This is the form I am using. I am using the LI and UL elements because I am using jQuery to add more inputs dynamically.

            <form class="add-post-form" action="add-files-to-post.php?id=<?php echo $lastId; ?>" method="post">
              <ul id="fieldList">
                <li>
                  <input type='file' name='postFile'>
                </li>
                <li>
                  <input type='text' name='postName[]' placeholder='Titel van bestand'>
                </li>
                <li>
                  <input type='text' name='postDesc[]' placeholder='Beschrijving / instructie'>
                </li>
              </ul>
              <button type="button" id="addMore" name="button">Nog een bestand</button>
              <br>
              <input type="submit" name="" value="Bestanden uploaden en toevoegen">
            </form>

Open in new window


This is the jQuery code

$(function() {
  $("#addMore").click(function(e) {
    e.preventDefault();
    $("#fieldList").append("<li>&nbsp;</li>");
    $("#fieldList").append("<li><input type='file' name='postFile'></li>");
    $("#fieldList").append("<li><input type='text' name='postName[]' placeholder='Titel van bestand'></li>");
    $("#fieldList").append("<li><input type='text' name='postDesc[]' placeholder='Beschrijving / instructie'></li>");
  });
});

Open in new window


This is how my table looks



Along with this, I am of course using some CSS to remove the bullet points and do some additional styling.

My question

How can I upload the files, while ALSO inserting the filepath, file title and file description into my database?

Using a loop seems the most logical option? However I am unsure on how to implement it.

I have tried a script that would upload multiple files from one <input> tag with the attribute multiple but this is not what I am looking for since I need to be able to add a title and description for each individual file.

Any help and tips are greatly appreciated. I know it's a broad question, but I just need someone to give me a point to start at.
Joey DrenthAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

nociSoftware EngineerCommented:
With a file field, the content of the file is sent across as the field.
a Name needs to be provided in another text field.
 (And those need to be numbered) also all files need to be to fit in an upload. (size limit)
0
Joey DrenthAuthor Commented:

Here to start :
https://www.experts-exchange.com/questions/29076657/Multiple-upload-files-with-PHP-and-MySQL-save-data-and-showing-them.html
https://www.experts-exchange.com/questions/26874395/Submit-PHP-form-values-and-upload-multiple-image-files.html
You've lot of example here too :
https://www.experts-exchange.com/searchResults.jsp?searchTerms=upload+multiple+files+php&searchSubmit=&asSubmit=true&asIgnored=true

Thank you for your time and help.

I took a look at those links and in both of them, the amount of images is predetermined. But I need the amount of images to be variable, there could be only one file, eight or maybe even fifteen.

That's why running it in a loop for each individual file seems like the most logical option to me.

            <form class="add-post-form" action="add-files-to-post.php?id=<?php echo $lastId; ?>" method="post">
              <ul id="fieldList">
                <li>
                  <input type='file' name='postFile[]'>
                </li>
                <li>
                  <input type='text' name='postName[]' placeholder='Titel van bestand'>
                </li>
                <li>
                  <input type='text' name='postDesc[]' placeholder='Beschrijving / instructie'>
                </li>
              </ul>
              <button type="button" id="addMore" name="button">Nog een bestand</button>
              <br>
              <input type="submit" name="" value="Bestanden uploaden en toevoegen">
            </form>

Open in new window


In my form I am using the brackets so the files and data gets submitted as an array. But I am unsure how to then use this data and insert it into my database with a loop.

I am able to do the database connection, write all the queries and secure it.

Just the part of using the loop per file and the file upload is where I lose it.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

Dave BaldwinFixer of ProblemsCommented:
All PHP installations have limits on the size of files that are uploaded and the number of uploads in a given POST.  Before you're done, you need to check your installation to see what the limits and try to keep it below those limits so it doesn't error out.
0
Joey DrenthAuthor Commented:

All PHP installations have limits on the size of files that are uploaded and the number of uploads in a given POST.  Before you're done, you need to check your installation to see what the limits and try to keep it below those limits so it doesn't error out.

But I could just increase this limit in my php.ini file?
0
Julian HansenCommented:
First up you are going to have to add the following attribute to your form
enctype="multipart/form-data"

Open in new window

Then you are going to need to change your postFiles variable to an array otherwise when you add more fields only the last file will actually be uploaded.
<script>
$(function() {
  $("#addMore").click(function(e) {
    e.preventDefault();
    $("#fieldList").append('<li>&nbsp;</li>');
    // CHANGE TO ARRAY
    $("#fieldList").append('<li><input type="file" name="postFile[]"></li>');
    $("#fieldList").append('<li><input type="text" name="postName[]" placeholder="Titel van bestand"></li>');
    $("#fieldList").append('<li><input type="text" name="postDesc[]" placeholder="Beschrijving / instructie"></li>');
  });
});
</script>

Open in new window


Then, your insert is going to work on a loop. Your submitted data will look something like this
POST
Array
(
    [postName] => Array
        (
            [0] => d
            [1] => f
            [2] => a
        )

    [postDesc] => Array
        (
            [0] => e
            [1] => g
            [2] => g
        )

)

Open in new window

FILES
Array
(
    [postFile] => Array
        (
            [name] => Array
                (
                    [0] => file1.txt
                    [1] => file2.txt
                    [2] => file3.txt
                )

            [type] => Array
                (
                    [0] => application/octet-stream
                    [1] => application/octet-stream
                    [2] => application/x-zip-compressed
                )

            [tmp_name] => Array
                (
                    [0] => C:\Windows\Temp\phpBDAE.tmp
                    [1] => C:\Windows\Temp\phpBDAF.tmp
                    [2] => C:\Windows\Temp\phpBDB0.tmp
                )

            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                    [2] => 0
                )

            [size] => Array
                (
                    [0] => 282
                    [1] => 12860
                    [2] => 15009
                )

        )

)

Open in new window


The trick here is to pick one of the variables to iterate over - I would chose the files.
You then use the index from the file you are on to find the associated data
<?php
// BASEPATH WHERE UPLOADED FILES WILL BE SAVED TO
define('BASEPATH','/path/to/destination/');

// DB CONNECTION PARAMETERS
$host     = 'localhost';
$user     = 'username';
$password = 'password';
$db       = 'database';

// SAFELY EXTRACT THE $_FILES DATA
$files = isset($_FILES['postFile']) ? $_FILES['postFile'] : array();

// START YOUR DB TRANSACTION HERE SO THAT IF ANY PART OF THIS 
// FAILS YOU DON'T END UP WITH PARTIAL RECORDS
$db = new mysqli($host, $user, $password, $db);

// CHECK THAT YOUR DB CONNECT WAS SUCCESSFUL HERE (NOT INCLUDED)

$db->begin_transaction();
// A PLACE TO SAVE THE PATHS TO UPLOADED FILES IN CASE WE NEED TO REGRESS
$paths = array();

// START OUR try / catch BLOCK
try {
  // WE WILL USE PREPARED STATEMENTS SO SET UP THE BASE QUERY
  // NOTE: WE ARE USING HEREDOC NOTATION
  $query = <<< QUERY
    INSERT INTO `yourtable` (`dia_title`, `dia_desc`, `dia_path`) VALUES (?,?,?)
QUERY;

  // CREATE THE STATEMENT
  $stmt = $db->prepare($query);

  // BUG OUT IF NOT SUCCESSFUL
  if (!$stmt) throw new Exception('Failed to prepare query: ' . $db->error);

  // BIND OUR LOOP VARIABLES
  $stmt->bind_param("sss", $title, $desc, $path);

  // ITERATE OVER THE UPLOADED FILES
  foreach($files['name'] as  $k => $f) {

    // SAFELY EXTRACT POST VARIABLES INTO BOUND STATEMENT VARIABLES
    $title = isset($_POST['postName'][$k]) ? $_POST['postName'][$k] : false;
    $desc  = isset($_POST['postDesc'][$k]) ? $_POST['postDesc'][$k] : false;

    // YOU MAY WANT TO BUG OUT AT THIS POINT IF title OR desc NOT SUPPLIED
    // YOU COULD DO THIS AS FOLLOWS
    // if (!$title || !$desc) throw new Exception('Invalid or missing data');

    // CREATE THE TARGET PATH
    $path = BASEPATH . $f;

    // ATTEMPT TO SAVE THE FILE - BUG OUT IF NOT SUCCESSFUL
    if (!move_uploaded_file($files['tmp_name'][$k], $path)) throw new Exception('Failed to move file ' . $f);

    // SAVE THE PATH IN CASE WE NEED TO REGRESS
    $paths[] = $path;

    // EXECUTE THE STATEMENT AND BUG OUT IF AN ERROR
    if (!$stmt->execute()) throw new Exception('Query failed with error ' . $db->error);
  }

  // GOT HERE SO ALL IS GOOD - COMMIT THE TRANSACTION
  $db->commit();
}
catch(Exception $e) {
   // ROLLBACK THE DB CHANGES
   $db->rollback();

   // YOU MAY WANT TO REMOVE YOUR UPLOADED FILES IF THERE WAS A FAILURE
   foreach($paths as $p) unlink($p);
}

Open in new window


DISCLAIMER: This code has not been tested - the pattern should be correct but I have not tested that the code is typo / bug free.

EDIT
Updated to reflect fixes
- $stmt->bind() => $stmt->bind_param()
- Added $k index to extraction of postName and postDesc variables
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Joey DrenthAuthor Commented:
Julian, first of all thank you a lot for your efforts.

I have edited the code. See below.

However, I am now getting this error.

Call to undefined method mysqli_stmt::bind() ... on line 39

I changed it to bind_param instead of just bind, the error is gone, but it just shows a blank page now.

Any idea what might cause this?

<?php
// BASEPATH WHERE UPLOADED FILES WILL BE SAVED TO
define('BASEPATH','/user-uploads/');

// DB CONNECTION PARAMETERS
$host     = 'localhost';
$user     = 'root';
$password = '';
$db       = 'nnnext';

// SAFELY EXTRACT THE $_FILES DATA
$files = isset($_FILES['postFile']) ? $_FILES['postFile'] : array();

// START YOUR DB TRANSACTION HERE SO THAT IF ANY PART OF THIS
// FAILS YOU DON'T END UP WITH PARTIAL RECORDS
$db = new mysqli($host, $user, $password, $db);

// CHECK THAT YOUR DB CONNECT WAS SUCCESSFUL HERE (NOT INCLUDED)

$db->begin_transaction();
// A PLACE TO SAVE THE PATHS TO UPLOADED FILES IN CASE WE NEED TO REGRESS
$paths = array();

// START OUR try / catch BLOCK
try {
  // WE WILL USE PREPARED STATEMENTS SO SET UP THE BASE QUERY
  // NOTE: WE ARE USING HEREDOC NOTATION
  $query = <<< QUERY
    INSERT INTO `dias` (`dia_title`, `dia_desc`, `dia_path`) VALUES (?,?,?)
QUERY;

  // CREATE THE STATEMENT
  $stmt = $db->prepare($query);

  // BUG OUT IF NOT SUCCESSFUL
  if (!$stmt) throw new Exception('Failed to prepare query: ' . $db->error);

  // BIND OUR LOOP VARIABLES
  $stmt->bind("sss", $title, $desc, $path);

  // ITERATE OVER THE UPLOADED FILES
  foreach($files['name'] as  $k => $f) {

    // SAFELY EXTRACT POST VARIABLES INTO BOUND STATEMENT VARIABLES
    $title = isset($_POST['postName']) ? $_POST['postName'] : false;
    $desc = isset($_POST['postDesc']) ? $_POST['postDesc'] : false;

    // YOU MAY WANT TO BUG OUT AT THIS POINT IF title OR desc NOT SUPPLIED
    // YOU COULD DO THIS AS FOLLOWS
    // if (!$title || !$desc) throw new Exception('Invalid or missing data');

    // CREATE THE TARGET PATH
    $path = BASEPATH . $f;

    // ATTEMPT TO SAVE THE FILE - BUG OUT IF NOT SUCCESSFUL
    if (!move_uploaded_file($files['tmp_name'][$k], $path)) throw new Exception('Failed to move file ' . $f);

    // SAVE THE PATH IN CASE WE NEED TO REGRESS
    $paths[] = $path;

    // EXECUTE THE STATEMENT AND BUG OUT IF AN ERROR
    if (!$stmt->execute()) throw new Exception('Query failed with error ' . $db->error);
  }

  // GOT HERE SO ALL IS GOOD - COMMIT THE TRANSACTION
  $db->commit();
}
catch(Exception $e) {
   // ROLLBACK THE DB CHANGES
   $db->rollback();

   // YOU MAY WANT TO REMOVE YOUR UPLOADED FILES IF THERE WAS A FAILURE
   foreach($paths as $p) unlink($p);
}

Open in new window

0
Dave BaldwinFixer of ProblemsCommented:
But I could just increase this limit in my php.ini file?
Yes, I always do on my own machines.  If you are on shared hosting, you often can't.
0
Joey DrenthAuthor Commented:
Okay, so I feel silly now. I totally forgot to add the brackets to my jQuery code. I did that now and the code is running further.

It's now throwing this error:

Invalid argument supplied for foreach() ... on line 42

As you might have noticed, I am a complete noob at loops, so unlike the last error I have no clue how to solve this one.
0
Julian HansenCommented:
As I stated in my post this is just out of my head so there may be a few typos
mysqli_stmt::bind() => mysqli_stmt::bind_param()

Open in new window

In your case
$stmt->bind() => $stmt->bind_param()

Open in new window

I have corrected in the original post

The loop error is saying that the value supplied for the loop was invalid - that is referring to the $files['name'] - which is indicating that your $_FILES value is not coming through correctly.

Place this at the top of the file
echo "<pre>" . print_r($_FILE, true) . "</pre>";

Open in new window

And report the results here.
0
Julian HansenCommented:
Did you make the change to your form to include the enctype attribute
enctype="multipart/form-data"

Open in new window

0
Joey DrenthAuthor Commented:
This is my form at the moment
            <form class="add-post-form" enctype="multipart/form-data" action="file-handler.php?id=<?php echo $lastId; ?>" method="post">
              <ul id="fieldList">
                <li>
                  <input type='file' name='postFile[]'>
                </li>
                <li>
                  <input type='text' name='postName[]' placeholder='Titel van bestand'>
                </li>
                <li>
                  <input type='text' name='postDesc[]' placeholder='Beschrijving / instructie'>
                </li>
              </ul>
              <button type="button" id="addMore" name="button">Nog een bestand</button>
              <br>
              <input type="submit" name="" value="Bestanden uploaden en toevoegen">
            </form>

Open in new window


The line of code at the top results in this:

Array
(
    [postFile] => Array
        (
            [name] => TEST-IMAGE-2.jpg
            [type] => image/jpeg
            [tmp_name] => C:\server\temp\php435.tmp
            [error] => 0
            [size] => 146805
        )

)

Open in new window


It seems to be only uploading the last file.
0
Julian HansenCommented:
Did you make the change in your jQuery to put the '[]' on the end of the postFile in the dynamic fields you are adding.

Here is a sample page with source that mimics your code and points to a reflect script. It demonstrates how the code should work

http://www.marcorpsa.com/ee/t3146.html

In the sample you will see that the results show the FILES coming through correctly.

I suspect it is your jQuery code that has not been updated.
0
Joey DrenthAuthor Commented:
I have found a typo (that I made myself), I forgot to place the dot in front of the basepath.

I did change some other things and the file upload is now working, files are being uploaded to my server in the folder ./user-uploads/ and there's a record being created.

There's one final error, the file title and description are not being inserted correctly.

It says "array" in both fields, instead of what I specified.


 Notice: Array to string conversion ... on line 64

print_r is now echoing this, which seems  to be working properly.

Array
(
    [postFile] => Array
        (
            [name] => Array
                (
                    [0] => latest001+pix.jpg
                    [1] => gun-city-offline.jpg
                )

            [type] => Array
                (
                    [0] => image/jpeg
                    [1] => image/jpeg
                )

            [tmp_name] => Array
                (
                    [0] => C:\server\temp\php98D3.tmp
                    [1] => C:\server\temp\php98D4.tmp
                )

            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                )

            [size] => Array
                (
                    [0] => 43280
                    [1] => 190032
                )

        )

)

Open in new window

0
Julian HansenCommented:
What is on line 64 - your code has changed since your last code post - which has a blank line for 64.
0
Joey DrenthAuthor Commented:
I added a ID to insert (I need it to be able to link images to created posts) this works.

The error is on line 65 according to the error message,


Notice: Array to string conversion in ... on line 65

The title and description that I give to the images do not seem to process properly, instead of the given string, the word "Array" gets inserted into the database record.

<?php
echo "<pre>" . print_r($_FILES, true) . "</pre>";

// BASEPATH WHERE UPLOADED FILES WILL BE SAVED TO
define('BASEPATH','./user-uploads/');

// DB CONNECTION PARAMETERS
$host     = 'localhost';
$user     = 'root';
$password = '';
$db       = 'nnnext';

// SAFELY EXTRACT THE $_FILES DATA
$files = isset($_FILES['postFile']) ? $_FILES['postFile'] : array();

// START YOUR DB TRANSACTION HERE SO THAT IF ANY PART OF THIS
// FAILS YOU DON'T END UP WITH PARTIAL RECORDS
$db = new mysqli($host, $user, $password, $db);

// CHECK THAT YOUR DB CONNECT WAS SUCCESSFUL HERE (NOT INCLUDED)

$db->begin_transaction();
// A PLACE TO SAVE THE PATHS TO UPLOADED FILES IN CASE WE NEED TO REGRESS
$paths = array();

// START OUR try / catch BLOCK
try {
  // WE WILL USE PREPARED STATEMENTS SO SET UP THE BASE QUERY
  // NOTE: WE ARE USING HEREDOC NOTATION
  $query = <<< QUERY
    INSERT INTO `dias` (`dia_title`, `diaserie_id`, `dia_desc`, `dia_path`) VALUES (?,?,?,?)
QUERY;

  // CREATE THE STATEMENT
  $stmt = $db->prepare($query);

  // BUG OUT IF NOT SUCCESSFUL
  if (!$stmt) throw new Exception('Failed to prepare query: ' . $db->error);

  // BIND OUR LOOP VARIABLES
  $stmt->bind_param("siss", $title, $id, $desc, $path);

  // ITERATE OVER THE UPLOADED FILES
  foreach($files['name'] as  $k => $f) {

    // SAFELY EXTRACT POST VARIABLES INTO BOUND STATEMENT VARIABLES
    $title = isset($_POST['postName']) ? $_POST['postName'] : false;
    $desc = isset($_POST['postDesc']) ? $_POST['postDesc'] : false;
    $id = $_GET['id'];

    // YOU MAY WANT TO BUG OUT AT THIS POINT IF title OR desc NOT SUPPLIED
    // YOU COULD DO THIS AS FOLLOWS
    // if (!$title || !$desc) throw new Exception('Invalid or missing data');

    // CREATE THE TARGET PATH
    $path = BASEPATH . $f;

    // ATTEMPT TO SAVE THE FILE - BUG OUT IF NOT SUCCESSFUL
    if (!move_uploaded_file($files['tmp_name'][$k], $path)) throw new Exception('Failed to move file ' . $f);

    // SAVE THE PATH IN CASE WE NEED TO REGRESS
    $paths[] = $path;

    // EXECUTE THE STATEMENT AND BUG OUT IF AN ERROR
    if (!$stmt->execute()) throw new Exception('Query failed with error ' . $db->error);
  }

  // GOT HERE SO ALL IS GOOD - COMMIT THE TRANSACTION
  $db->commit();
}
catch(Exception $e) {
   // ROLLBACK THE DB CHANGES
   $db->rollback();

   // YOU MAY WANT TO REMOVE YOUR UPLOADED FILES IF THERE WAS A FAILURE
   foreach($paths as $p) unlink($p);
}

Open in new window

0
Julian HansenCommented:
A couple of typos on my part.
postName and postDesc are arrays so we need to do this

$title = isset($_POST['postName'][$k]) ? $_POST['postName'][$k] : false;
$desc = isset($_POST['postDesc'][$k]) ? $_POST['postDesc'][$k] : false;

Open in new window

The $k is the key of the $files array we are iterating over in the for loop - it tells us what item in each array to map to the file we are processing
0
Joey DrenthAuthor Commented:
So I just tested this and it works!

Thank you a ton for helping me out here, I really learned a lot today.
0
Joey DrenthAuthor Commented:
Together with the help of Julian I was able to resolve my problem.

Thank you a lot for helping me out with my problem and learning me a lot today.
0
Julian HansenCommented:
You are welcome.
0
Joey DrenthAuthor Commented:
Hello Julian, sorry to come back to this question.

If I wanted to add a check to the script to see whether a file is an image or not.

I was thinking about something like getimagesize(); or pathinfo(); ?

What would I use in this case and how would I add it to the existing script, considering security and the script that I currently have?
0
Julian HansenCommented:
Check out the function exif_imagetype()
0
Joey DrenthAuthor Commented:
First of all, sorry for my very late response, had two busy weeks.

I looked at the function that you suggested and this is what I'm thinking.

Instead of doing this: (Psuedo) IF filetype === GIF OR PNG OR JPG

Do this:
$allowed = array("IMAGETYPE_PNG", "IMAGETYPE_JPG", "IMAGETYPE_GIF");

$fileType = exif_imagetype($_FILES['']) //Not entirely sure what to put there

if(!in_array($fileType, $allowed)) {
   // Don't allow file and stop script
}

Open in new window


Is this correct? And how would I implement this in the loop ?
0
Julian HansenCommented:
Run it against the uploaded file the path to which is stored in $_FILES['tmp_name'].
$fileType = exif_imagetype($_FILES['tmp_name'])

Open in new window

0
Joey DrenthAuthor Commented:
foreach($files['name'] as  $k => $f) {

    // SAFELY EXTRACT POST VARIABLES INTO BOUND STATEMENT VARIABLES
    $title = isset($_POST['postName']) ? $_POST['postName'] : false;
    $desc = isset($_POST['postDesc']) ? $_POST['postDesc'] : false;
    $id = $_GET['id'];

    // YOU MAY WANT TO BUG OUT AT THIS POINT IF title OR desc NOT SUPPLIED
    // YOU COULD DO THIS AS FOLLOWS
    // if (!$title || !$desc) throw new Exception('Invalid or missing data');

    // CREATE THE TARGET PATH
    $path = BASEPATH . $f;

    // ATTEMPT TO SAVE THE FILE - BUG OUT IF NOT SUCCESSFUL
    if (!move_uploaded_file($files['tmp_name'][$k], $path)) throw new Exception('Failed to move file ' . $f);

    // CHECK WHETHER FILE IS AN IMAGE OR NOT
    $allowed = array("IMAGETYPE_PNG", "IMAGETYPE_JPG", "IMAGETYPE_GIF");

    $fileType = exif_imagetype($_FILES['tmp_name'][$k]);

    if(!in_array($fileType, $allowed)) throw new Exception('File is not an image');

    // SAVE THE PATH IN CASE WE NEED TO REGRESS
    $paths[] = $path;

    // EXECUTE THE STATEMENT AND BUG OUT IF AN ERROR
    if (!$stmt->execute()) throw new Exception('Query failed with error ' . $db->error);
  }

  // GOT HERE SO ALL IS GOOD - COMMIT THE TRANSACTION
  $db->commit();
}

Open in new window

0
Joey DrenthAuthor Commented:
I added these lines:

    $allowed = array("IMAGETYPE_PNG", "IMAGETYPE_JPG", "IMAGETYPE_GIF");

    $fileType = exif_imagetype($_FILES['tmp_name'][$k]);

    if(!in_array($fileType, $allowed)) throw new Exception('File is not an image');

Open in new window


But it doesn't seem to work.

Is there something I'm missing here?

Please note that I did enable these settings in the php.ini file.
extension=php_mbstring.dll
extension=php_exif.dll

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Databases

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.