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.
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.
For my iPhone web app I have created a database in php MyAdmin, it contains two tables (bookings, waiters and allocations) the I wish to view the bookings within a table in HTML where i can allocate a waiter to that booking. Any tips on how this would be done, any help will be appreciated as this is my first contact with web app development and MyAdmin. Thanks!
Mysql work with autoincrement id. You will have an id after of an insertion. You can to create a table only to id's and after to use it in the insertion of the waiter.
First you will need to get the data from the table via MySQL
$sql = "SELECT * FROM table_name";
$result = mysql_query($sql);
Then you would loop through the result
while($row = mysql_fetch_assoc($result)){
extract($row);
}
Then you can do as you wish with the returned data...
You really need to give us a little more... What have you got so far?
I'm currently trying to write a simple ORM with PHP and mysql. I want the orm class to be able to work with joined tables.
So here's my problem, the following code shows how I map the data the query yields into an array.
public function execute_query($db_connection)
{
$query = '';
foreach($this->sql_query as $query_part)
$query .= $query_part;
$result = $db_connection->query($query);
while($row = $result->fetch_assoc())
{
array_push($this->m_Data, $row);
}
}
db_connection is a mysqli object.
sql_query contains all the different query parts (e.g. sql_query['join'] etc.).
m_Data is the array that contains the data read from the db.
My specific problem now is when I'm using a join statement in my query this function will just override fields with the same name in my m_Data array. Also if I dont save the name's of the table the specific field data is coming from, I later can't update the tables with the same join statement.
tl,dr. I need to be able to not only save the table data like this: m_Data{ 'field_name' => 'value' } but I also need to save the table name the field is selected from. I could then save the data like this m_Data{ 'table_name.field_name' => 'value' } which enables me later to generate a query to update the joined tables successfully.
I cant seem to find any information on how to get the origin table name for each field I pull out of the result.
If it isnt possible with mysqli I'd much appreciate it if you point me in the right direction.
extra short problem statement:
I need to get a result set and read each row seperatly. For each row I need the following information for every field selected: field_name, table_name, value.
There must be a simple answer to this but I seem to be searching for the wrong keywords to find a solution.
I hope I've written this understandable enough.
Seems to me that you should store table column values in an object, so if you have a related table, the column values would be stored in a separate object - and so would not interfere with the values in your primary table.
In general you might work with the ORM this way:
// Make joined query
$rows = ...
foreach($rows as $row)
{
// $row just refers to the primary table
echo $row->id;
// You get a many:1 related table this way
echo $row->getRelatedRow()->value;
// You get a 1:many rows this way
$rows = $row->getOtherRelatedRows();
}
Depending on how you set up your query options, getting related data may or may not initiate further SELECTs to get the required data.
mysqli_result::fetch_fields has useful things:
http://www.php.net/manual/en/mysqli-result.fetch-fields.php
table
orgtable
field type
etc
I built a document upload admin screen, where my client can browse and upload pdf documents to a mysql dbase.
I have two separate tables for the Agendas, and one for Minutes. both have separate table names "upload" and "upload_mins".
on the index.php page, I have the page fetch each row of the database, and display all of the valid documents on a "download" page.
I have come a across a problem.
Each dbase is set to increment ID. now that there is two databases, they are coming to utilize the same ID.
so I am pulling from the Agenda table:
http://www.example.com/clerk.php?ID=77
and I am pulling from the Minutes table also:
http://www.example.com/clerk.php?ID=77
and they happen to have the same increment ID.
Is there some way to avoid this? Can I add a field parameter to the minutes to make sure that they don't have the same URL when pulling documents?
Create a integer field, or txt field?
i.e. http://www.example.com/clerk.php?ID=77&min=yes
If these are just documents, you could store them in a single table but have a column called type that differentiates between minutes and agendas. That way, IDs will be unique.
You could also extend the types column be a foreign key to a types table, so you can extend it to include additional document types such as spreadsheets in the future easily.
This would also aid the front-end display, as you would only need one query to fetch the documents within a batch or timeframe, but add them to differing arrays. For example:
// get the last 20 uploaded documents
$sql = "SELECT * FROM documents ORDER BY created DESC LIMIT 0,20";
$res = mysql_query($sql);
while ($doc = mysql_fetch_object($res)) {
$type = $doc->type;
if (!isset($docs[$type]) || !is_array($docs[$type])) {
$docs[$type] = array();
}
$docs[$type][] = $doc;
}
// loop over agendas
foreach ($docs['agendas'] as $agenda) {
echo '' . $agenda->title . '';
}
// loop over minutes
foreach ($docs['minutes'] as $minutes) {
echo '' . $minutes->title . '';
}
...
You say that the problem you are having is with URLs being duplicated. You have 2 different options to solve that.
The first is to create an identifier that tells you which table you want. You could have agenda.php and minutes.php, or you could have clerk.php?ID=77&type=1 and clerk.php?ID=77&type=2.
This will allow you to know which table you are referencing. This is also the approach I would recommend. There is no reason to avoid duplicate keys in different tables as long as you have a way of knowing which table you need.
The second option is to put all your records into a single table. You can then add a type column that specifies what type of document it is. You can then leave your clerk.php file alone, but need to change the upload page to populate the type column.
If you are just storing PDFs in the database, you shouldn't need anything in this table except id, type, and the document itself.