How to Output the results of a MySQL query that used aliases? - php

I have two primary MySQL tables (profiles and contacts) with many supplementary tables (prefixed by prm_). They are accessed and manipulated via PHP.
In this instance I am querying the profiles table where I will retrieve an Owner ID and a Breeder ID. This will then be referenced against the contacts table where the information on the Owners and Breeders is kept.
I received great help here on another question regarding joins and aliases, where I was also furnished with the following query. Unfortunately, I am having huge difficulty in actually echoing out the results. Every single site that deals with Self Joins and Aliases provide lovely examples of the queries - but then skip to "and this Outputs etc etc etc". How does it output????
SELECT *
FROM (
SELECT *
FROM profiles
INNER JOIN prm_breedgender
ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN contacts ownerContact
ON profiles.ProfileOwnerID = ownerContact.ContactID
LEFT JOIN prm_breedcolour
ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON profiles.ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
) ilv LEFT JOIN contacts breederContact
ON ilv.ProfileBreederID = breederContact.ContactID
WHERE ProfileName != 'Unknown'
ORDER BY ilv.ProfileGenderID, ilv.ProfileName ASC $limit
Coupled with this is the following PHP:
$owner = ($row['ownerContact.ContactFirstName'] . ' ' . $row['ownerContact.ContactLastName']);
$breeder = ($row['breederContact.ContactFirstName'] . ' ' . $row['breederContact.ContactLastName']);
All details EXCEPT the contacts (gender, colour, etc.) return fine. The $owner and $breeder variables are empty.
Any help in settling this for me would be massively appreciated.
EDIT: My final WORKING query:
SELECT ProfileOwnerID, ProfileBreederID,
ProfileGenderID, ProfileAdultColourID, ProfileColourModifierID, ProfileYearOfBirth,
ProfileYearOfDeath, ProfileLocalRegNumber, ProfileName,
owner.ContactFirstName AS owner_fname, owner.ContactLastName AS owner_lname,
breeder.ContactFirstName AS breeder_fname, breeder.ContactLastName AS breeder_lname,
BreedGender, BreedColour, BreedColourModifier
FROM profiles
LEFT JOIN contacts AS owner
ON ProfileOwnerID = owner.ContactID
LEFT JOIN contacts AS breeder
ON ProfileBreederID = breeder.ContactID
LEFT JOIN prm_breedgender
ON ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN prm_breedcolour
ON ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
WHERE ProfileName != 'Unknown'
ORDER BY ProfileGenderID, ProfileName ASC $limit
Which I could then output by:
$owner = ($row['owner_lname'] . ' - ' . $row['owner_fname']);
Many Thanks to All!

I guess you're using the mysql_fetch_array or the mysql_fetch_assoc-functions to get the array from the result-set?
In this case, you can't use
$row['ownerContact.ContactFirstName']
as the PHP-Docs read:
If two or more columns of the result have the same field names, the
last column will take precedence. To access the other column(s) of the
same name, you must use the numeric index of the column or make an
alias for the column. For aliased columns, you cannot access the
contents with the original column name.
So, you can either use an AS in your SQL-query to set other names for the doubled rows or use the numbered indexes to access them.
This could then look like this:
Using AS in your Query
In your standard SQL-query, the columns in the result-set are named like the columns which their values come from. Sometimes, this can be a problem due to a naming-conflict. Using the AS-command in your query, you can rename a column in the result-set:
SELECT something AS "something_else"
FROM your_table
This will rename the something-column to something_else (you can leave the ""-quotes out, but I think it makes it more readable).
Using the column-indexes for the array
The other way to go is using the column-index instead of their names. Look at this query:
SELECT first_name, last_name
FROM some_table
The result-set will contain two columns, 0 ==> first_name and 1 ==> last_name. You can use this numbers to access the column in your result-set:
$row[0] // would be the "first_name"-column
$row[1] // would be the "last_name"-column
To be able to use the column-index, you'll need to use mysql_fetch_row or the mysql_fetch_assoc-function, which offers an associative array, a numeric array, or both ("both" is standard).

you need to replace the * with the data you need , and the similar ones you have to make aliases too :
ownerContact.ContactFirstName as owner_ContactFirstName
and
breederContact.ContactFirstName as breeder_ContactFirstName .
like this :
select ownerContact.ContactFirstName as owner_ContactFirstName , breederContact.ContactFirstName as breeder_ContactFirstName from profiles join ownerContact ... etc
in this way you will write :
$owner = ($row['owner_ContactFirstName'] . ' ' . $row['owner_ContactLastName']);
$breeder = ($row['breeder_ContactFirstName'] . ' ' . $row['breeder_ContactLastName']);

You cannot specify table alias when you access row using php. Accessing it by $row['ContactFirstName'] would work if you didn't have 2 fields with the same name. In this case whatever ContactFirstName appears second overwrites the first.
Change your query to use fields aliases, so you can do $owner = $row['Owner_ContactFirstName'].
Another option I'm not 100% sure is to access field by index, not by name(e.g. $owner=$row[11]). Even if it works I don't recommend to do so, you will have a lot of troubles if change your query a bit.

On outer select You have only two tables:
(inner select) as ilv
contacts as breederContact
there is no ownerContact at all

Related

How to correctly use WHERE with JOIN in SQL and PHP

So I'm trying to implement a JOIN in my PHP but I don't know how to include the WHERE clause with JOIN in my query.
I'm trying to do:
SELECT SpecialFacts.ConservationStatus, SpecialFacts.Reproduction, SpecialFacts.Length, Habitat.Type, Habitat.located
FROM SpecialFacts
INNER JOIN Habitat ON SpecialFacts.SpeciesID=Habitat.SpeciesID
WHERE SpeciesID="G. cuvier"
Basically I'm trying to make sure the join happens on the tables where the SpeciesID is G. cuvier but everything I have tried so far doesn't work and the error it is giving me now is "Column SpeciesID in where clause is ambiguous".
Here is my relevant PHP code:
<?php
include 'connect.php';
$result = mysqli_query($connect,"SELECT SpecialFacts.ConservationStatus, SpecialFacts.Reproduction, SpecialFacts.Length, Habitat.Type, Habitat.located FROM SpecialFacts INNER JOIN Habitat ON SpecialFacts.SpeciesID=Habitat.SpeciesID WHERE SpeciesID='G. cuvier'") or die("fail" . mysqli_error($connect));
$i = 0;
while($row = mysqli_fetch_array($result))
{
echo $row[$i];
$i = $i + 1;
}
Column SpeciesID exists in both tables, so it doesn't know which need to be compared to value given as G. cuvier. As you are writing every column name as table name with dot(.), the same should be in where condition column SpecialFacts.SpeciesID = "G. cuvier".
So query should be like:
SELECT SpecialFacts.ConservationStatus, SpecialFacts.Reproduction, SpecialFacts.Length, Habitat.Type, Habitat.located
FROM SpecialFacts
INNER JOIN Habitat ON SpecialFacts.SpeciesID=Habitat.SpeciesID
WHERE SpecialFacts.SpeciesID="G. cuvier"
It's not giving you that error because you're using WHERE incorrectly. It's giving you that error because there are multiple tables in your query that have a column with that name, hence the "ambiguous". You just need to disambiguate it by adding the table name to the identifier.
WHERE SpecialFacts.SpeciesID="G. cuvier"
or
WHERE Habitat.SpeciesID="G. cuvier"
Since you're inner joining the tables on that column, either table should work for the WHERE clause. I would suggest using the smaller table for performance reasons, but honestly I'm not 100% certain if it will matter or not. You can do EXPLAIN on each one to see how they compare.
Use below query instead
SELECT SpecialFacts.ConservationStatus, SpecialFacts.Reproduction, SpecialFacts.Length, Habitat.Type, Habitat.located
FROM SpecialFacts INNER JOIN Habitat
ON SpecialFacts.SpeciesID=Habitat.SpeciesID
WHERE SpecialFacts.SpeciesID='G. cuvier'
I have used single quote and used column name with table name.

echoing data From mySQL when table column joined twice

I am trying to echo both the employee name and manager name
SQL QUERY:
SELECT *
FROM `form`
INNER JOIN `emp` AS employee
ON `form`.emp_ID = employee.emp_ID
INNER JOIN `emp` AS manager
ON `form`.manager_ID = manager.emp_ID
ECHO:
while($row = $result->fetch_assoc()){
echo $row['emp_name'];
}
Always outputs the managers name.
have tried the following:
$row['employee.emp_name']
$row['employee']['emp_name']
which all don't work.
any help is appreciated
When the columns have the same name, their values will overlap when retrieving by fetch_assoc(). You can either use fetch_array() and reference the columns by numeric index (not recommended with SELECT *, since you can't easily guarantee the order of columns), or you will have to list the column names explicitly and alias them. For example:
SELECT emp.emp_name emp_emp_name, manager.emp_name manager_emp_name, ...
This would give you separate distinctly named fields in the result, that you could then access from what fetch_assoc() returns.

PHP PDO Multiple Table join

I have multiple tables and I want to access the fields in a specific table. Here are the table schemas:
Each tbl_acct has one tbl_unit. A tbl_unit has many tbl_groups and a tbl_groupcontact consist of the contacts and the related group. Every time I log in, I set a session where $_SESSION['unitid'] = $row['unitid'];.
What I wanted to do is to access the fields in the tbl_contacts. For now my code is here:
$data = $conn->prepare("SELECT * FROM tbl_groups LEFT JOIN tbl_groupcontact ON tbl_groups.id=tbl_groupcontact.group_id WHERE tbl_groups.unitid = ?");
$data->execute(array($_SESSION['unitid']));
foreach ($data as $row) {
echo $row['fname'] . " " . $row['lname']. "<br />";
}
As you can see, I can related the tbl_groups and tbl_groupcontact in my code however, I can't get the fields in the tbl_contacts. Am I missing something here? Any help would be much appreciated.
You need to join another table.
SELECT tbl_contacts.*
FROM tbl_groups
INNER JOIN tbl_groupcontact ON tbl_groupcontact.group_id = tbl_groups.id
INNER JOIN tbl_contacts ON tbl_contacts.id = tbl_groupcontact.contact_id
WHERE tbl_groups.unitid = ?
No need for (slower) LEFT JOIN btw - use it when you want to retrieve records from (left-side) table even when there's no match found in joined (right-side) table (it's columns will be filled with nulls in this case).

How to use the OR statement in MySQL while using the LIKE search statement

I am trying to create a good little search statement that searches muitple fields using the with different search terms depending on what is returned. I am basiclly setting an order in which I want to search if one search term is not found try the next one. However I am using a WHERE clause to seperate search only one type of data. Currently I am getting some strange results returned because I don't think my order is correct, it seems that my WHERE clause is being ignored.
here is my statement (I am usig PHP):
mysql_query("SELECT * FROM item AS i LEFT JOIN country AS c ON i.country_id = c.country_id WHERE i.item_status = 'active' AND (i.item_name LIKE '%".$_SESSION['item']."%') OR i.item_description LIKE '%".$_SESSION['description']."%' OR i.item_name LIKE '%".$_SESSION['description']."%' ");
Thank you in advance.
Why don't you use full-text search feature?
Need to alter table structure for create fulltext search index.
ALTER TABLE item ADD FULLTEXT (item_name, item_description);
Then your queries turns to:
mysql_query("
SELECT * FROM item AS i LEFT JOIN country AS c ON i.country_id = c.country_id
WHERE i.item_status = 'active' AND
MATCH (i.item_name, i.item_description)
AGAINST (" . $_SESSION['item'] . " " . $_SESSION['description'] . ");
");
Simple, accurate, and faster.
Move the right parenthesis to the end of the statement:
SELECT *
FROM item AS i LEFT JOIN country AS c
ON i.country_id = c.country_id
WHERE i.item_status = 'active'
AND (i.item_name LIKE '%".$_SESSION['item']."%'
OR i.item_description LIKE '%".$_SESSION['description']."%'
OR i.item_name LIKE '%".$_SESSION['description']."%')
It is your parentheses in the wrong place. Here is the correct code:
mysql_query("SELECT * FROM item AS i LEFT JOIN country AS c ON i.country_id = c.country_id WHERE i.item_status = 'active' AND (i.item_name LIKE '%".$_SESSION['item']."%' OR i.item_description LIKE '%".$_SESSION['description']."%' OR i.item_name LIKE '%".$_SESSION['description']."%')");
The OR operator has lower precedence than the AND operator. http://dev.mysql.com/doc/refman/4.1/en/operator-precedence.html
Put all the ORs inside parentheses (one that contains all of them, not one for each of them ;) ).

Enumerating tables used in mysql query?

Is there any way to enumerate tables used in mysql query?
Lets say I have query :
SELECT * FROM db_people.people_facts pf
INNER JOIN db_system.connections sm ON sm.source_id = pf.object_id
INNER JOIN db_people.people p ON sm.target_id = p.object_id
ORDER BY pf.object_id DESC
And I want in return array:
$tables = array(
[0] => 'db_people.people_facts',
[1] => 'db_system.connections',
[2] => 'db_people.people',
);
Yes, you can get information about tables and columns that are part of a query result. This is called result set metadata.
The only PHP solution for MySQL result set metadata is to use the MySQLi extension and the mysqli_stmt::result_metadata() function.
$stmt = $mysqli->prepare("SELECT * FROM db_people.people_facts pf
INNER JOIN db_system.connections sm ON sm.source_id = pf.object_id
INNER JOIN db_people.people p ON sm.target_id = p.object_id
ORDER BY pf.object_id DESC");
$meta = $stmt->result_metadata();
$field1 = $meta->fetch_field();
echo "Table for field " . $field1->name . " is " . $field1->table . "\n";
You'll have to build the array of distinct tables used in the query yourself, by looping over the fields.
Depending on what you're using it for, MySQL's EXPLAIN could do the trick for you:
http://dev.mysql.com/doc/refman/5.0/en/explain.html
The solution marked as good will return only the result tables. But if you do the next query it will fail:
SELECT users.* FROM users, cats, dogs WHERE users.id = cats.user_id
Will return only users and not cats and dogs tables.
The best solution is find a good parser, another solution is using REGEX and EXPLAIN query (more info in the next link):
Get mysql tables in a query
But I think that another good solution is list all tables and search them inside the query, you can cache the list of tables.
EDIT: When searching for tables, better use a preg like:
// (`|'|"| )table_name(\1|$)
if(preg_match('/(`|\'|"| )table_name(\1|$)/i', $query))
// found
If not, it can return false positives with for example "table_name2", "table_name3"... table_name will return FOUND two times.

Categories