having trouble converting SELECT results correctly - php

Not sure if this should be in PHP or MySQL.
I have this query:
SELECT
product.*,
company.company-name
FROM
products
INNER JOIN
company ON products.company-id=company.id
ORDER BY
company.company-name,
product.model
which I am outputting using this:
$group = array();
while ($row = mysqli_fetch_assoc($result)) {
$group[ $row['company-name'] ][] = $row;
}
foreach ($group as $company-name => $models) {
foreach ($models as $model) {
echo "Product Name: $model[model-name]";
echo "Color: $model[color]";
echo "Core Company: $model[core-company-id]"; // this is the line I am trying to fix
}
Obviously in my output above if I output $model[core-company-id] it is only going to be the number. I want the corresponding company from the 'company' table (core-company-id = the correct company.company-name / company.id) to be in its place.
I cant figure out how to do it. Can I adjust my original SELECT query/result somehow, do I need an extra query, or can I modify the php output somehow to fix this?
EDIT: I should add, the Core Company name will be different from the $company-name I am retrieving in the initial SELECT. That company is the product company name, but the maker of the 'core' will be a different company most times
For example, if core-company-id is 20, I want whichever company.company-name has a company.id of 20 to be put there
Thanks for any help.
EDIT 2: Bear with me while I add table data etc. Sorry for not explaining this very well, I've found it difficult to put into words.
EDIT 3: More information.
I have two tables:
Table 'Product' contains: id, main-company-id, model-name, color, core-company-id
Table 'Company contains: id, company-name
My output currently looks like this:
COMPANY NAME (comes from company.company-id)
Product 1 Name: Item name
Color: Blue
Core Company: 27 (comes from product.core-company-id)
Product 2 Name: Item 2 name
Color: Blue
Core Company: 35 (comes from product.core-company-id)
COMPANY NAME
Product 1 Name Item 1 Name
Color: Green
Core company: 27 (comes from product.core-company-id)
Having a hard time posting the output example correctly. Ugh. Not doing so good am I?

That should work:
foreach ($group as $company-name => $models) {
foreach ($models as $model) {
echo "Product Name: $model[model-name]";
echo "Color: $model[color]";
echo "Core Company: " . $company-name; // this is the line
}
}

UPDATE: I just noticed in the SELECT and ORDER you are calling the table 'product' (singular) but in the FROM and JOIN you have 'products' (plural) - that would explain why you're not getting the result you expect!
It looks like you're not retrieving the value you want (core-company-id) with your select, or maybe it's in product but it's not clear to me where 'core-company-id' should come from.
Assuming it's a column in company table, this should work:
SELECT
product.*,
company.company-name
company.core-company-id
FROM
products
INNER JOIN
company ON products.company-id=company.id
ORDER BY
company.company-name,
product.model
you could always see what your array has with print_r and make sure the core-company-id is present;
print_r($group); ## new line for testing here
foreach ($group as $company-name => $models) {
Edit: From reading your edits it sounds as if you may want to join the same table twice, which you can do, but it's still not clear to me where is core-company-id coming from.

Maybe You need something like:
SELECT
field1,
field2,
company.company-id AS com_company-id
company.company-name AS another_field
FROM table
...
product.company-id AS pro_company-id
...
Then You can use another_field in Your PHP code the same way as You use the field1.
As stated at 13.2.8. SELECT Syntax "A select_expr can be given an alias using AS alias_name." You can set an expression and rename the field to some name that would be easy to access using PHP later. Such as $model[another_field], $model[com_company-id], $model[pro_company-id].
If You have the same field names in different tables You can make aliases with AS and use them in Your SQL query as well (on JOINs etc.).
If You need to get some company_names instead of company_ids You can use brackets () to create SQL subqueries. For example, to get a company name instead of "27", "35", etc.
Then there should be something like:
SELECT ... FROM ...
(
SELECT Company.company-name FROM Company
INNER JOIN Product
WHERE Company.id = Product.core-company-id
) AS company_name;
Using a Subquery to get the company name and access that as $model[company_name] in Your PHP code.
Update
Just noted, that You are messing up with "product" and "productS".
Maybe Your query should be like that:
SELECT
products.*, -- You have product.* here
company.company-name
FROM
products
INNER JOIN
company ON products.company-id=company.id
ORDER BY
company.company-name,
products.model -- You have product.model here
In that case, maybe, You will be able to select$model[core-company-id] as You did it earlier in PHP code.

Related

Many to many relationships - Moving data from many tables to a single table

I have a table with users and one with labels
A label can have many users and a user can have many labels, so a Many to Many relationship
A joining table is needed, that's why I have label_user
Below you can see pictures of what they contain with example data:
Users:
https://i.stack.imgur.com/E5E6O.png
Labels:
https://i.stack.imgur.com/1NFjq.png
label_user:
https://i.stack.imgur.com/tW2Uo.png
Let's say I have 5000 users and I can sort them by gender. Let's say 2800 of them are males, how can I assign them all to a label?
Here's some things I tried:
public function add_users_to_label($label_id, $condition, $value)
{
$db = new Database();
$conn = $db->db_connect();
$label_id = escape_string($conn, $label_id);
$query = $conn->query("INSERT INTO `label_user`(`label_id`, `user_id`) SELECT :label_id, psid FROM `iris_messenger_users` WHERE $condition = $value");
$query->bind_param("iss", $label_id, $condition, $value);
if ($query->execute()) {
return true;
}
else {
return "Error inserting data: " . $conn->error . "\n";
}
}
On the user side I have a simple form with select that let's you select a label and then this code:
if(isset($_POST['label-select'])) {
if ($_GET['show_only_gender'] == 'male') {
$condition = 'gender';
$user->add_users_to_label($_POST['label-select'], $condition, $_GET['show_only_gender']);
}
}
Basically, I want to get all users that are male and assign them to a label and put that into label_user with respectively the label_id and the user_id(psid)
Even if this worked I'd still have to do it 2699 times more. What can I do here to optimize and make it to run with 1 query if possible?
I don't think using foreach and running it as much times as there are users is the best option, is it?
Is there any better approach I can take to make this possible?
Although what you are describing does not make sense to have a "label" associated with a person for this specific component, the gender is already on the user table you should be able to get all male based on
select * from user where gender = 'male'
no need to JOIN to a label table on this field. Similarly if you were trying to find people based on a name starting with something... you would not create a label for the name either. Query directly from the table that has that specific component association.
Now, to answer your question, how to insert into the label table for each instance in bulk, you could do something like... I am doing this based on some label ID = 123 as just an example in your labels table that represents gender.
I am doing a LEFT-JOIN in the select so we dont try to add for any user IDs that are already on file do not try to get re-added.
insert into label_user
( label_id,
user_id )
select
123 as label_id,
U.id as user_id
from
users U
left join label_user LU
on U.id = LU.user_id
AND LU.label_id = 123
where
U.gender = 'male'
AND LU.user_id IS NULL
You obviously need to adjust for php.

Join on get_where - is this possible?

I have a table called Listings and a table called wines and one more called wineinfo
I originally was using the following to get the info from the listings table only, how ever since I restructured my DB, it requires the use of two other tables.
$listing = $this->db->get_where( "listings", [ "listingID" => $id ]
)->row();
if( !$listing )
throw new Exception("Error: Listing you're trying to bid on does not exist.", 1);
// check not to bid on own listings
if( $listing->list_uID == $userid )
throw new Exception("Error: Dont't bid on your own listings.", 1);
I then tried changing the code so the JOIN statements could work
$this->db->select("FROM listings.*, Vintage, Vineyard, Wine_Name, Region, Advice, Grape,Producer,Type id,wine_id,Wine_Name,");
$this->db->from("wineinfo");
$this->db->where(["listingsID" => $id]);
$this->db->where(["wineinfo.wine_id" => "listings.wine_id"]);
$this->db->where(["wineinfo.Vintage" => "listings.wine_id"]);
$this->db->join("wines", "wineinfo.wine_id = wines.wine_id");
$listing = $this->db->get()->row();
I am being given this error.
Unknown table 'listings'
But there is 100% a table called listings.
I know I've missed something, or definitely messed up the code, I am only just learning about this and the code above worked for something else, but now I've amended it to this, it hasn't.
I then tried changing the code so the JOIN statements could work
you are trying to combine 3 tables with 2 FROM and one JOIN clauses, which is incorrect the way you do it.
you need to keep SELECT clean, just select the columns you need, like:
$this->db->select("listings.*, wineinfo.*, wine.*");
then the FROM clause:
$this->db->from("wineinfo");
then make the joins:
$this->db->join("listings", "wineinfo.wine_id = listings.listingsID");
$this->db->join("wines", "wineinfo.wine_id = wines.wine_id");
followed by your where clauses.
please note, I don't know your table structure, so I can only guess your JOIN relationships. Also this is a simplified example, where I suppose that the 3 tables don't have matching column names.
response to "ambiguous" comment: you can limit your select clause to just necessary columns, e.g.
$this->db->select("listings.*, wineinfo.vintage, wine.*");
or use an alias:
$this->db->select("listings.*, wineinfo.wine_id as my_wineID, wine.*");
The FROM in $this->db->select("FROM listings.*, Vintage, Vineyard, Wine_Name, Region, Advice, Grape,Producer,Type id,wine_id,Wine_Name,"); is not supposed to be there.
The generated out query now looks like:
SELECT FROM *... FROM sometable

MySQL Inner join output to html table in php

I have a table that is being displayed in a form, which looks like this: http://puu.sh/5VBBv.png
The end of the table, City, is displaying an ID of a city, which is supposed to be linked to another table (http://puu.sh/5VBIG.png).
What I've done for my INNER JOIN query is:
mysql_query("SELECT * FROM cities INNER JOIN people ON people.cityid = cities.id") or die(mysql_error());`
and I'm trying to output it into a table:
echo "<td>" . $row['cityid'] . "</td>";
My issue is that I'm not quite sure how to actually display the cityid that corresponds to the city name. I've tried using ['name'] and other values as the value to output in the table, and I can't find any solution for this anywhere so far. I'm just learning joins, so I don't exactly have any knowledge on what I could be doing wrong. Is there anything immensely obvious?
First your use of * in the join query could be ambiguous. If cities had a name column and people had a name column, you won't know which one you're getting. Second you can do this a couple ways. I think you're trying to get a city id from a city name. If that's correct you can either make and ajax call and query it directly or define an array as follow:
$res = mysql_query("...");
$city_ids = Array();
while ($ary = mysql_fetch_assoc($res)) {
city_ids[$ary['name']] = Ary['id'];
}
Then when you get the name, you just loop up $ary['name'].
Selecting from people and joining cities makes more sense. Then select the fields you need.
SELECT people.*, cities.name as city_name FROM people JOIN cities ON people.cityid = cities.id
Then, echo $row['city_name']
Select ID from cities city, people person where person.ID = city.ID
You are selecting the ID from both Cities and People, and joining on the ID

I want to get output result from second table based on first table rows output in json-php

I have knowledge of PHP but I am still learning Json. First of all I want to clear what I am looking for. I have two tables in mysql database, table1(users) and table2(business). Table "users" contains these rows(id, uid, business_name) and table "business" contains these rows(id, uid, category).
I have following code in PHP page:
if(isset($_GET['catName'])) {
$cat = $_GET['catName'];
$stmt = $pdo->prepare("SELECT id, uid, category FROM business WHERE category = ? ");
$stmt->execute(array($_GET['catName']));
$arr = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
I am able to get json output on my html page e.g.
101, 102, 103 and so on.
But I want to get business_name rows like ABC Business, XYZ Business, 123 Business and so on from second table "business" based on the output uid from first table. In brief, I want business_name output instead of uid output from second table.
Please help me. Thank you so much in advance.
You have an associative array, with the results from the query. It sounds like you want the business names, but you are not querying for them.
So the first step would be fix your broken query!
It's difficult to tell what you want from the query, but you're mixing the users table with the business table, so I'm guessing you really want business names based on users.
SELECT b.business_name FROM users u JOIN business b ON u.uid = b.uid WHERE category = ?
Then, you have to access your $arr variable correctly to get the business names
foreach ($arr as $bus_sql_result) {
echo $bus_sql_result['business_name']."\n";
}
This is not in JSON format, I'm not sure what JSON has to do with what you want, but if you really want it that way, you could try something like
$business_names = array();
foreach ($arr as $bus_sql_result) {
$business_names[] = $bus_sql_result['business_name'];
}
echo json_encode($business_names);
Thank you so much Chris and Jormundir. Joining the both tables really solved my problem. This is what I have done:
$stmt = $pdo->prepare("SELECT business.uid, users.business_name FROM business,users WHERE business.uid = users.uid AND business.category= ? ");
In html page I have put "business_name" array instead of "uid" and I have got result whatever I was looking for.
Thanks you so much all of you.

mySQL Search Statement with Multiple filters

I've been trying to figure this out for a few days now, but haven't been able to find a solution. Most likely due to the fact that I don't think I'm asking the right question.
Here is goes...
I am trying to create a search on my website of a list of attorneys.
Table 1
ID (primary)
Name
Category1 (fkey)
Category2 (fkey)
Category3 (fkey)
Category4 (fkey)
Category5 (fkey)
Location1 (fkey)
Location2 (fkey)
Location3 (fkey)
Location4 (fkey)
Location5 (fkey)
Table 2 - Locations
ID (primary)
Name
Table 3 - Categories
ID (primary)
Name
So Attorneys have multiple categories and multiple locations -> one to Many Relationship with both Table 2 and Table 3
First Question: Do I have Table 1 set up correctly? Do I need to have multiple location and category columns (ie location1, location2, location3, etc...) Or am I complicating this?
Next...
I want a checkbox style search on my site. A user can search by Location and/or by Category. And with checkbox they can choose multiple locations and/or categories. The checkbox values are the IDs of the locations and categories (not the names)
So three ways this can happen.
Search by locations ONLY
Search by categories ONLY
Search by categories within locations
I have two problems.
I can get scenarios 1 & 2 to work, but only if ONE checkbox is selected.
I have no idea how to even begin to get scenario 3 to work.
Here is what I have for scenario 1 & 2
$AttorneyLocation = $_POST['AttorneyLocation'];
for ($i="0"; $i<count($AttorneyLocation); $i++) {
if (!is_numeric($AttorneyLocation[$i])) {
$AttorneyLocation[$i]="";
}
if (empty($AttorneyLocation[$i])) {
unset($AttorneyLocation[$i]);
}
}
$AttorneyLocation = implode (" OR ", $AttorneyLocation);
$sqlCommand = "SELECT att_id, att_name, att_logo, att_addy, att_town, att_profile_url FROM attorneys WHERE att_location1='$AttorneyLocation' OR att_location2='$AttorneyLocation' OR att_location3='$AttorneyLocation' OR att_location4='$AttorneyLocation' OR att_location5='$AttorneyLocation'";
Again, this works but only when ONE checkbox is selected, it fails when two or more are selected. Basically it seems to only search the LAST checkbox that has been selected, ignoring the ones before it.
For scenario 3 - Again I'm just not sure where to start, how do I join together the category search within the location search?
If someone can point me in the right direction that would be great, thanks so much! This is my first try creating something like this!
Here is my form code if necessary - all created dynamically
<input type='checkbox' name='AttorneyCategory[]' value='$cat_id'> $category<br />
<input type='checkbox' name='AttorneyLocation[]' value='$loc_id'> $location<br />
As pointed out by #JonathanLeffler your structure for Table 1 is a perfect example of what not to do. Your Category* and Location* fields should be removed from Table 1 and replaced with two many-to-many tables - attorney_locations(attorney_id, location_id) and attorney_categories(attorney_id, category_id).
Start by amending your db structure and then we can address the other issues.
Next round -
<?php
foreach ($_POST['AttorneyLocation'] AS $key => $val) {
if (is_numeric($val)) {
$_POST['AttorneyLocation'][$key] = intval($val);
} else {
unset($_POST['AttorneyLocation'][$key]);
}
}
$AttorneyLocations = implode (',', $_POST['AttorneyLocation']);
foreach ($_POST['AttorneyCategory'] AS $key => $val) {
if (is_numeric($val)) {
$_POST['AttorneyCategory'][$key] = intval($val);
} else {
unset($_POST['AttorneyCategory'][$key]);
}
}
$AttorneyCategories = implode (',', $_POST['AttorneyCategory']);
$sqlCommand = 'SELECT DISTINCT att_id, att_name, att_logo, att_addy, att_town, att_profile_url FROM attorneys ';
if ($AttorneyLocations) {
$sqlCommand .= 'INNER JOIN attorney_locations ON attorneys.att_id = attorney_locations.attorney_id ';
}
if ($AttorneyCategories) {
$sqlCommand .= 'INNER JOIN attorney_categories ON attorneys.att_id = attorney_categories.attorney_id ';
}
$sqlCommand .= 'WHERE 1=1 ';
if ($AttorneyLocations) {
$sqlCommand .= "AND attorney_locations.location_id IN ($AttorneyLocations) ";
}
if ($AttorneyCategories) {
$sqlCommand .= "AND attorney_categories.category_id IN ($AttorneyCategories)";
}
You should print out what you get from your implode():
$AttorneyLocation = implode (" OR ", $AttorneyLocation);
It won't be valid SQL syntax, because you need it to read something like:
location = 'location1' OR location = 'location2' OR ...
So, you are not generating valid SQL, as you would surely see if you printed the SQL.
Your Table1 is a relational disaster. CategoryN or LocationN columns are SQL 'code smells'. It isn't clear what that table means; is it documenting 'AND' or 'OR' connections between the categories and locations, and is Category5 associated only with Location5 or is it also relevant to Location1? Without knowing what the data is supposed to mean, we can't reliably provide the correct design.
Given that each attorney may practice up to 5 categories of law, and may practice in up to 5 locations, then a better design for the tables is probably:
Attorney
ID (pkey)
Name
...other details...
AttorneyCategory
AttorneyID (fkey - references Attorney)
Category (fkey - references Category)
(AttorneyID, Category) (pkey)
AttorneyLocation
AttorneyID (fkey - references Attorney)
Location (fkey - references Location)
(AttorneyID, Category) (pkey)
This will actually be significantly easier to query, too, because you won't have to look up the same location name in each of five different columns, nor look up the same category in each of five different columns.
Well, since you are using PHP i just recommend you do an IF statement for each of the filters you want, maybe a few to make 2 or 3 filters work together. your database is set correctly, just create PHP if's with different queries and it should work.

Categories