Inventory system multiple tables and recipes - php

I'm a novice in PHP and extremely new to databases, so forgive me if this is a stupid question:
I've built an inventory system in PHP/MySQL that allows someone to (among other things) add raw materials to a table, that has "Price_Per_Pound_In_Dollars" and "Pounds_In_Stock" columns. As it stands, updating the "Pounds-In-Stock" column for a raw material must be done manually, one-at-a-time via a form.
I'm now wanting to add another database for recipes that contains the steps needed for making a product, so that the "Pounds_In_Stock" column can be updated for multiple raws at once. Please see the image below.
Basically someone would go to a form, pick a product from a drop down menu (populated with recipe names by doing a mysqli_query), enter the number of gallons they want to make and press submit.
The rows in the recipe table have the figures needed for making a gallon of that product, so all of the numbers in the table would be multiplied by the number that was entered into the form.
So, if someone were to choose "Recipe Name 1" and entered "2" into the gallons input box. It would multiply the "Pounds_Needed_Per_Gallon" by 2 and put that info into a mysqli_query to remove it from the correct raw "Pounds_In_Stock" column in the "Raws" table. (If that makes sense).
Now my question:
Is it possible to do this dynamically? Am I approaching this the wrong way? I know I can get the result I want by hard coding the values for each recipe in a PHP document and linking to it via the "action =" on the form page, but this seems like an exceedingly inelegant way of doing things. I just can't seem to wrap my head around how to do this with MySQL.
Form Issue:
I created a bare-bones form that should include the table names in a drop-down menu (so that a recipe table can be selected). But I can't seem to get the table names to echo out in the drop down. I know the while loop is working correctly, since there are three options in the drop-down menu, which corresponds to the number of tables in the database, the only problem is that they're blank. Please see the image and code below. I looked over my code a few times, but can't see where I made a mistake. Any ideas?
<?php
//Prepare MySQL Query.
$Product_Menu_Query ="SHOW TABLES";
$Run_Product_Menu_Query = mysqli_query($Connect, $Product_Menu_Query);
?>
<form action="submit.php" method="POST">
<span>Recipe Name:</span><br>
<select name="recipe">
<?php //Populates dropdown with Product_Name from database.
while ($row = mysqli_fetch_array($Run_Product_Menu_Query)) {
echo '<option value="' . $row[0] . '">' . '</option>';
}
?>
</select><br><br>
<span>Gallons:</span><br>
<input type="number" name="gallons"><br><br>
<input type="submit" value="Submit">
</form>
Screenshot of form:

looks like you would have something like this (change your table names and fields accordingly to your database actual field and table names):
$recipeName = $_POST['recipe'];
$gallons = $_POST['gallons'];
$stmt = $mysqli->prepare("SELECT raws.id as rawId, (recipe.pounds_needed_per_gallon * ?) as gallons
FROM RecipeName recipe
JOIN Raws raws on recipe.raw_id=raws.raw_id
WHERE raws.raw_name = ?");
$stmt->bind_param("ds", $gallons, $recipeName);
$stmt->execute();
$stmt->bind_result($rawId, $gallonsNeeded);
$stmt->close();
mysqli_query("UPDATE Raws set pounds_in_stock = (pounds_in_stock - $gallonsNeeded) where id = $rawId");
EDIT: I see you need more help with debugging. You should check the values obtained through the queries (i.e. rawId and gallonsNeeded) and echo out errors, but as i don't have your entire code base I cannot tell exactly what is going wrong with your code.

Related

three table inner join with empty table for searching

my database is structured as below
at present the character, groups and vault tables all have data. The games tables is empty however.
Is it possible to write an inner join on the games table that will allow for a php search box to get data from the other three tables even though the games table has no data in it?
Is there another way of doing this that I might not know about?
For example I want to write a php search script for a webpage that searches on the games tables. If a user enters 'Allistair Tenpenny', it will pull the data from the characters table and display it in the search page with the characters name and their history, same with if some one searches a vault it will display the data from the vaults table.
From what I have read of inner joins the data on each joined table must match for it to display. Is there another way to approach this?
No inner join is necessary to get the data you want. You can simply use php to use SQL to search the appropriate table based on the user input.
If there are multiple search fields on your page, just name the submit buttons differently, then have PHP check for the existence of each submit button's POST data from the form, then perform the appropriate search. An example form might be:
<form action="" method="post">
Search Character Name:<input type="text" name="charactername">
<input type="submit" name="charsubmit" value="Search">
</form>
<form action="" method="post">
Search Vault Name:<input type="text" name="vaultname">
<input type="submit" name="vaultsubmit" value="Search">
</form>
Your PHP code can then be structured as:
if (isset($_POST['charsubmit']))
{
$stmt = $db->prepare("SELECT * FROM character_table WHERE character_name = ':mydata'");
$stmt->bindParam(':mydata',$_POST['charactername']);
}
elseif (isset($_POST['vaultsubmit']))
{
$stmt = $db->prepare("SELECT * FROM vault_table WHERE vault_name = ':mydata'");
$stmt->bindParam(':mydata',$_POST['vaultname']);
}
$stmt->execute();
Using prepared statements like this is a good way to prevent SQL injection attacks, thus ensuring user entered data is NEVER put directly into a SQL statement.
Think about it yourself. There should be no redundant information in normalized relative database. All the data tables have a column history. It should not have redundant data, which you could use to identify rows in other tables, but a description of the record set in the own table. We don't know, what vault_number is for. All other tables might be connected to the vault table directly depending on your data structure. Only you know, what your intention building this structure has been.
Further more you have connected games to groups by a redundant column with the group_name. You should avoid any redundancy and give the groups an id. Then connect it to games by a foreign group_id key. Imagine what will happen, when there are 100 games in a group and you decide to rename a group or just want to correct a typo.
Instead of joining the tables why not try to add them to an array?
create an array with the elements you need to display (don't forget to add the same number of elements from all tables (not 3 from 1 table and 4 from the other)
query the first table and use add it to the array
query the the second table and add it to the array
continue adding the tables you need
display the array
Edit:
The array could consist of 4 elements:
vault_number
name
history
type (table it's comming from)
example query would be:
select vault_number, charactor_name as name, history, 'charactor' as type from charactor
select vault_number, group_name as name, history, 'group' as type from groups
You just continue adding this to your array and you can then display all results
Take into consideration what Quasimodo's clone explained about your db normalization and the approach given by Sgt AJ could go a long way.

Explain this SQL code in PHP script

I found this piece of code from an answer on Several drop down list input to one field table. It really seems like something I can use in my current project. The current project is about populating a table with two dropdown boxes (which are populated themselves with tables). However, I don't understand what personal changes I need to do in order to make it work. attributes? :attributes? Can someone make sense of it?
$levels = $_POST['level1'][0].",".$_POST['level1'][1];
//Now you have a string called $levels
// Which contains a comma seperated list, to insert into db / one field
//Insert into your table...change your table and field names to real values...
$sql = "INSERT INTO yourTable (attributes) VALUES (:attributes)";
$q = $db->prepare($sql);
$q->execute(array(':attributes'=>$levels));
?>
:attributes is a bound parameter in a PHP prepared statement which inserts a row into a table with an attributes field, setting just that field.

Click a link to run MySQL query for that specific value in the link (php)

I had a hard time to find a solution for this, most of the questions asked were to click a button to run a query.
What I have is a list of db table names in a HTML table. I need them to be in hyperlink format, once I click a table name it should send the name of the table to a php file and run mysql query to get all the attributes of the table.
What's the best way to do this? thanks for all suggestions in advance.
huh? how about phpmyadmin if you want to use querying
but if you like to build your own SQL query tool then learn this things:
List database:
http://php.net/manual/en/function.mysql-list-dbs.php
List Tables:
http://www.php.net/manual/en/function.mysql-list-tables.php
and lastly List Fields
http://www.php.net/manual/en/function.mysql-list-fields.php
ADDING THE AMBIGUOUS REQUEST OF Q-Starter.
#example:index.php
<form method="get" action="query.php">
<label>Statement: </label><input type="text" name="sqlState"/>
</form>
#example:query.php
<?php
$sqlState = $_GET['sqlState'];
$result = mysql_query($sqlState);
echo $result;
?>
This is bad programming codes but if you really want to explore then go and try this codes, just use this on your own, this might damaged your DATABASE if other users tries to use the so called "SQL INJECTION".

Creating a site to query a database of tables

I have a small problem. I am working with some manual testers who are untrained in programming/database design. Our current process means that these manual testers need to insert data into our database at certain times whilst we build a GUI to facilitate this in the future.
In the interim, I would like to create a simple site. What I would like to do with the site is, simply, connect to our database, allow the manual tester to enter some keywords, and return any columns within tables that are close/related to the keywords provided. This would save a lot of time for our testers searching for colums in our (rather large) database.
How could I create a site like this? I think it could be useful for a lot of people, so I have decided to post the question up here to gather the thoughts of StackOverflow.
At the moment, I am thinking a simple PHP page with a textbox, which allows the user to enter some data, separated by commas. Explode the data based on commas, hold it in an array. Connect to my database, then use the Information Schema View to retrieve column information.
My main problem is - what is the most effective way to use the Information Schema View to retrieve columns related to the keywords entered by the users ? How can I ensure the columns returned are the most suitable?
Any input here would be greatly appreciated. Thanks a lot.
Tl;dr is the bolded part, for busy people :)
I think you could achieve this with a simple form and some ajax calls using on key up.
Here is a simple example in which the list will update each time the user enters a letter in the column name they are searching for.
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript">
$(document).ready(function() {
$("#faq_search_input").keyup(function()
{
var faq_search_input = $(this).val();
var dataString = 'keyword='+ faq_search_input;
if(faq_search_input.length>1)
{
$.ajax({
type: "GET",
url: "ajax-search.php",
data: dataString,
success: function(server_response)
{
document.getElementById("searchresultdata").style.display = "block";
$('#searchresultdata').html(server_response).show();
}
});
}return false;
});
});
</script>
</head>
<body>
<div class="searchholder">
<input name="query" class="quicksearch" type="text" id="faq_search_input" />
<div id="searchresultdata" class="searchresults" style="display:none;"> </div>
</div>
</body>
</html>
next we need a script to carry out our search
ajax-search.php
//you must define your database settings
define("DB_HOST", "FOO");
define("DB_USERNAME", "BAR");
define("DB_PASSWORD", "YOUR PASSWORD");
define("DB_NAME", "DATABASE NAME");
if(isset($_GET['keyword']))
{
$search = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
if ($search->connect_errno)
{
echo "Failed to connect to MySQL: (" . $search->connect_errno . ") " . $search->connect_error;
$search->close();
}
$keyword = trim($_GET['keyword']) ;
$query ="SELECT COLUMN_NAME FROM ".DB_NAME.".INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME LIKE '%".$keyword."%'";
$values = $search->query($query);
if($values->num_rows != 0)
{
while($row = $values->fetch_assoc())
{
echo $row['COLUMN_NAME']."<br>";
}
}
else
{
echo 'No Results for :"'.$_GET['keyword'].'"';
}
}
As the user types out a column name all of the column name like this will be returned and updated on the fly, without page reload. Hope this helps
You should do something like this:
Form:
<form action="search.php" method="post">
<textarea name="words"></textarea>
<input type="submit">
</form>
search.php
<?php
// You will need a DB user with enough permissions
$link = mysqli_connect($server,$user,$pass);
mysqli_select_db($link,$database_name);
print "<table>";
// Comma separated
$words = explode(",",$_POST['words']);
foreach ($words as $word)
{
$sql = "SELECT COLUMN_NAME FROM ".$database_name.".INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%".$word."%'";
$res = mysqli_query($link,$sql);
while ($row = mysqli_fetch_assoc($res))
{
print "<tr><td>".$row['COLUMN_NAME']."</td></tr>";
}
}
print "</table>";
?>
I can see why you are asking this interesting question. If the tester enters a list of keywords, and you use the information schema view to obtain a list of matching columns, then there is a danger that there will be a lot of false matches that could waste time or cause the tester to enter incorrect information into your system. You want to know how to determine which columns are the best matches to the tester's query. But you want to keep it simple because this is just a temporary workaround, it's not your main application.
The answer is to supplement search results using a reputation-based system. Here is a very simple one that should work well for your application.
First, create two simple tables to store rating information for the tables and columns in your database. Here is the starting structure.
TEST_SEARCH_TABLES:
TABLE_ID
TABLE_NAME
RATING
TEST_SEARCH_COLUMNS:
COLUMN_ID
TABLE_ID
COLUMN_NAME
RATING
Populate TEST_SEARCH_TABLES with the name of every table in your database. Populate TEST_SEARCH_COLUMNS with the name of every column, and link it to the corresponding table. Initialize all the RATING columns to 1000.0 - you will be using the Elo Rating System to supplement your rankings because it is simple, easy to implement and it works great.
When the user enters a list of keywords, don't use Information Schema View. Instead, search the TEST_SEARCH_COLUMNS table for any columns that have any of those keywords. Assign each column a WEIGHT based on the number of hits. (For example, if the search is "customer,amount,income" then a column CUSTOMER_ID would have a weight of 1. A column CUSTOMER_INCOME would have a weight of 2, and CUSTOMER_INCOME_AMOUNT would have a weight of 3.) Calculate the WEIGHT of each table as the sum of the weights of its columns.
Now for each table and column returned by your search, multiply the WEIGHT times the RATING to determine the SEARCH VALUE. Give the tester a list of matching tables in descending order of search value. Within each table, also list the columns in descending order of their search value.
Every time a table or column appears in a search, use the Elo Rating System to give it a WIN against an opponent rated 1000.0. Every time a user selects a column to work with, give both that column and its table a win against an opponent rated 1500.0. In this way, the most useful and successful tables and columns will organically float to the top of your search lists over time.
A side benefit to this approach (using tables instead of information schema view) is that this approach is more extensible. As an enhancement, you could put DESCRIPTION and COMMENTS columns on the TEST_SEARCH_TABLES and TEST_SEARCH_COLUMNS tables, and also search those columns for keyword matches as well.
Here is another optional enhancement - you could put a (+) and (-) button next to each table and column and give it a win against a 2000-rated opponent if the user clicks (+) and a loss against a zero-rated opponent if the user clicks (-). That will allow your testers to vote for columns they find important and to vote against columns that are always getting in the way.
I'm not sure if I fully understood your issue
Take a look at this:
http://php.net/manual/en/function.mysql-list-tables.php
you can get all the tables on a database , store them in an array then filter them using your keywords
I think this could be done in the following steps without any PHP programming and even without need in any web-server.
Write SQL-script which makes everything to retrieve data you need.
Modify script to add columns to result set with simple html-formatting to make you result record like the following:
'<tr><td>', 'resultcolumn1', '</td><td>', 'resultcolumn2','</td></tr>'
Run this script using sqlcmd with output option to file. Give resulting file .html extension.
Place sqlcmd call inside cmd file. After calling sqlcmd call web browser with resulting html file name as parameter. This will display your results to tester.
So, your testers only run cmd file with some parameters and get html page with results. Of course you need to form correct html head and body tags, but this is not a problem.
Now about your main question about how you can be sure the columns returned are the most suitable. I think the most reliable from the most simple ways is to create thesaurus table which contains synonyms for your column names. (This could be done by testers themselves). So you can search your column names from Information Schema View using LIKE in INFORMATION_SCHEMA.COLUMNS as well as in thesaurus table.
Not sure if you want spend time on writing and supporting your solution. For php/mysql I would use http://www.phpmyadmin.net/home_page/index.php or if users can access db directly
http://dev.mysql.com/downloads/gui-tools/5.0.html
Might take some time to tech them how to use it, but will save a lot of problems in a long run.
Another thing, you can create *.sql files that would populate db automatically.
query.sql
CREATE TABLE "example" (
"id" INT NOT NULL AUTO_INCREMENT,
"name" VARCHAR(30),
"age" INT
);
INSERT INTO "example" VALUES
('1', 'a', 1),
('2', 'b', 2);
than you can run it from command line:
mysql -u USER -pPASSWORD database_name < filename.sql
Use mysql_connect method if you use mysql and enter data like:
INSERT INTO tablename
and stuff just read about it.

Add data from one table to another when specific data form one table is selected

I have a drop down menu on add_media.php that is populated from the "bulletin_date" field within the "bulletins" table in a MySQL database. When a "bulletin_date" is selected, I would like the "filename" that is a part of that same record in the "bulletins" table to be placed into the "publications" table along with the rest of the data that is being submitted via the add_media.php form.
I'm uncertain how to add to the "publications" table the "filename" from the "bulletins" table that is a part of the same record as the "bulletin_date" that was selected.
I hope this makes sense...I does in my head, but hard to put in words... :-)
Kind of need a bit more information before answering this, like, can you pre-populate the data from the bulletins table into the add_media.php form? This can be accomplished by retrieving the value on page load, and sticking it in a fashion like this:
<input type="hidden" value="<?php echo $bulletinsDateVal ?>" />
This will make it part of the posted data from add_media.php. It will probably need parsing/changing after the post to format it correctly, and there is the possibility of a loss of precision depending on how this is implemented.
If you can't, or if you would rather not, do it that way the other way is supplying the id of the row in bulletins table in the form, much like above. You can then simply add the bulletin_date column value as part of the INSERT that you do after the page is posted like so:
// Code which handles the POST from the form on add_media.php
$bulletinDataSelectVal = $_POST['bulletinDataSelect'];
$sqlInsert = "INSERT INTO publications(filename, other, form, data)
VALUES( (SELECT filename FROM bulletins WHERE id = '$bulletinDataSelectVal'),
'blah',
'dee',
'blah')";
Does that all make sense?
I see now after reading your comment, so you will probably want the latter then. Assuming your table has an unique id column, or some other way to identify it, definitely populate the dropdown with select's whose text is bulletin_date, but also set each select element's value to the ID of that row in the table like so:
<select name="bulletinDataSelect">
<option value="<?php echo bulletinData["id"]; ?>"><?php echo $bulletinData["bulletin_date"]; ?>
You can then use that idOfBulletinData value to do the above insert which I have edited.

Categories