Comparing queries with PHP while loop - php

Here is my table setup:
employee: Employee information, name, address, etc...
group: List of distribution groups.
employee2group: table that links employees to multiple groups.
I have it setup this way so I can add groups in the future, without having to add columns to my employee table. This may seem like common sense to you all, but I just started with PHP a couple months ago, so everything is still new and confusing to me.
So, I'm working on my update form, which will display a list of check boxes that is populated with a simple SELECT * FROM group query. The idea is to show the ones that an employee is part of as "checked" when I view the employee in the update form.
Currently, my while loop to show the list of check boxes is this:
<?php
$group_list_query = "SELECT * FROM group"
$group_list_result = mysql_query($group_list_query, $cmsWrite)
while ($row = mysql_fetch_assoc($group_list_result)) {
echo "<input type=\"checkbox\" name=\"distro_{$row['group_name']}\"> {$row['group_name']}";
}
?>
Pretty simple. I might have some syntax errors in there, but in my code they don't exist, because it works fine.
So what I need to do, is run another query that returns ONLY the names of the groups that the employee belongs to:
SELECT group.group_name
FROM group JOIN employee2group ON group.group_id = employee2group.group_id
WHERE employee2group.employee_id ='{$_GET['employee_id']}'
Then, I need to compare the two queries, and output a normal check box when there isn't a match, and output a checked check box when there is a match.
I tried doing a while statement that set $row = query1 and $row2 = query2, and compare the $row and $row2 values, but then it only returned instances where both queries had results, instead of all of them.
I hope this makes sense, I've been trolling the internet for a while, and haven't found anything that pertains to my problem.
Thanks for reading!

Two solutions :
1 : Get a array of the groupIds that user is a member of, then when looping through the group list. Check if the id is in that array with in_array, if it is dont display the check box
2 : Do a left join on the employee2group table and check if the value = null or not, if its null display the check box.
--
Off question topic but you should also look at using bound paramaters rather than just including them inthe sql statement like that, leaves it open to sql injection otherwise.

Related

PHP mysqli query returning result "1" on joins

I have been trying to pull out some values from php-mysql, and it's returning a strange result "1". It comprises of an inner join with a where clause, everything works fine, but the result is strangely "1" when I try to echo out the ID, but I am assured that the ID is not 1. When I run the same query on the MySQL CLI, it returns exactly what I need but in the php, it doesn't even say there's an error.
Interestingly, only the ID is returning "1", everything else is returning the correct values. The ID on the CLI is- "V8FBaMJT6bqPbpRutJgkRdc44S3Gz3H8VjW5iu5E4yhBlLA1/D8o+EcGMUY62LZLrxb2SSkaxBoUwaiQXQv+3OsoDTuheYTy4ibPsy91X8JhNGFjOWM2MWQyMWMxMTBmMTU5YjU5NzU2NGM3OTc1YQ==", so there's no chance that it is equal to "1".
$showPosts = "SELECT * FROM box
INNER JOIN interactions
ON box.u_id=interactions.actorid
WHERE interactions.actorid=?
AND interactions.type IN ('1','5')
ORDER BY box.time_created";
if ($stmt = $conn->prepare($showPosts)) {
/* bind parameters for markers */
$b = "V8FBaMJT6bqPbpRutJgkRdc44S3Gz3H8VjW5iu5E4yhBlLA1/D8o+EcGMUY62LZLrxb2SSkaxBoUwaiQXQv+3OsoDTuheYTy4ibPsy91X8JhNGFjOWM2MWQyMWMxMTBmMTU5YjU5NzU2NGM3OTc1YQ==";
$stmt->bind_param("s", $b);
/* execute query */
$stmt->execute();
/* bind result variables */
$metaResults = $stmt->result_metadata();
$fields = $metaResults->fetch_fields();
$statementParams = '';
//build the bind_results statement dynamically so I can get the results in an array
foreach($fields as $field){
if(empty($statementParams)){
$statementParams .= "\$post['".$field->name."']";
} else {
$statementParams .= ", \$post['".$field->name."']";
}
}
$statment = "\$stmt->bind_result($statementParams);";
eval($statment);
while($stmt->fetch()){
echo $post['id'];
echo $post['time_created'];
}
}
Now, in the result- the first is the strange "1" and the second is the timestamp.
Also, if I remove the INNER join part, and do a simple SELECT * FROM box, it returns the ID perfectly. And I have also tried doing a stmt->num_rows, and it returns '0'. Maybe I am missing something obvious.
I am new to using joins in php mysql and it has been a big headache for me for the last 2 hours, any help is appreciated.
Thank you.
The problem is that you use SELECT * FROM ... which returns every column from any table you are using. This is not what you want. Always write the columns you want to read from the query.
In this case you have more than one Id column in your result set, one from the table box, the other one from the table interactions. The value of $post['id'] will contain the value of the interactions table. So, change the SELECT query by writing:
SELECT box.id, box.time_created FROM ...
Also, do not use the eval() function, ever. You might want to switch to PDO which has a more clear API (the PDOStatement::fetch function returns the next row as an array)
After hours of research, I have come to an working example and it works just fine.
Someone else might face the same problems in the future and make mistakes, so I am posting an answer to the problem here:
Problems:
Having same column names in two joined tables
The first problem was the the table interactions had the same column name id as that of the table box. Since I used SELECT * FROM box along an inner join with interactions, it resulted in the return of the results based on the second id which was of interactions rather than box.
Not storing the results before showing record count
Secondly, the problem was the results were not being stored as in http://php.net/manual/en/mysqli-stmt.num-rows.php, which was a silly mistake.
Solutions:
Addressing the column repition
So, firstly I decided to change the column name of the table interactions for id, and I changed it to inter_id to avoid further conflicts. Though not a very smart step, it will avoid such silly mistakes in the future. Then as pointed out by the previous answer, I had to specify the column names of the results I wanted to output rather than using a SELECT *, so I changed it to
SELECT box.id, box.time_created FROM box
INNER JOIN interactions
ON box.u_id=interactions.actorid
WHERE interactions.actorid=?
AND interactions.type IN ('1','5')
ORDER BY box.time_created";
That pretty much solved the first problem.
Counting the number of results
The second one was just about adding the $stmt->store_result(); to the code and it worked flawlessly just before I did a echo $stmt->num_rows; and it showed the results perfectly.
Thank you, again.

php sql check value print one line for each positive record

I have been working on my "administrative" webpage for a while now, almost finished. Just need a little help with one last thing;
I want to get a value (ID) from a table posted as Yes if the ID is found, but no if it isn't.
Have managed to get it printet, but it prints all the records in the table on every person that displays on the website (http://gyazo.com/13f271bbb8c4e83ff9ecd9908545c854 where it says "Betalt" it should just be ONE correct for each one).
The code for that part is here:
if ($row[9] == $row[1]) {
$betalt = "Ja";
}
$row[9] is the value from table SI_PAYMENTS. And $row[1] is the value from table BUSS1.
These two values should be the same if the record exists in SI_PAYMENTS, and if it exists, I want the webpage to display "Yes". But if it don't find it, I want the webpage to display "No".
EDIT
Here's my SQL Query:
SELECT buss1.navn, buss1.plassnummer, buss1.telefon, buss1.epost, buss1.fodselsdato, buss1.pastigningssted, buss1.bilettype, buss1.ankommet, buss1.merknader, si_payment.ac_inv_id FROM buss1, si_payment ORDER BY buss1.plassnummer ASC
I think you need to JOIN the two tables. At the moment, you will get every row from table buss1 next to every row from si_payment. So if there are 6 rows in buss1 and 4 in si_payment, you'll end up with 24 rows. I suspect there is a column in the two tables that links them, so you need a JOIN: something like this
SELECT buss1.navn, buss1.plassnummer, buss1.telefon, buss1.epost, buss1.fodselsdato, buss1.pastigningssted, buss1.bilettype, buss1.ankommet, buss1.merknader, si_payment.ac_inv_id
FROM buss1 INNER JOIN si_payment WHERE buss1.some_column = si_payment.another_column
ORDER BY buss1.plassnummer ASC
I can't tell what some_column and another_column should be, I'm afraid. But if you change those, that will give you only the matching rows from the two tables. If that's not quite right, you may need a LEFT JOIN, which will give you all rows from the first table and the matching rows from the same table.
If I've misunderstood, I apologise.

PHP print from two tables where attribute from table A matches id in table B

I am building a simple adress book website where you can enter information about a person and then enter information about adresses. You can then select where people lives using a drop down menu to update the building id attribute in the person to match the automaticly generated id in the building. What I can't figure out how to do print all info about all persons(this I can do) and then print the info about the building that matches each persons building id(this I have no idea how to do. Right now I am using a while loop to print each person. But I can't get the matching building to print.
Edit: also, thanks for all info I have gotten from this site in my learning of webbprograming
You could use joins in SQL to combine several tables in one query. Also you could use GROUP BY.
Just search for that and I think you will get a good tutorial in your language.
Here are some good links:
SQL JOIN, SQL GROUP BY
Could use some code and table names to help define this example a little better, but regardless, you need to change your mysql query. In your database you need at least 1 matching row between your persons table and your buildings table. This way you can JOIN them together using the common row.
I will be using id as a placeholder for the common row in this example. Somethings like this should work:
SELECT * FROM persons LEFT JOIN buildings ON(persons.id=buildings.id) WHERE persons.building_id = buildings.building_id
To get all the results from persons and buildings you will need a separate query. But, the query above should give you the results of the person's info where the building_id matches the building_id from buildings.

Understanding COUNT() as `count`

I'm currently learning how to build a site in PHP MySQL. However, I seem to fail to understand COUNT() as count and wouldn't mind some further explanation.
I get the principles of COUNT, 0 || 1, and how it returns all the values that pertain to that query.
But, don't see how COUNT as count works. Anyhow, this is how the code I'm writing goes - so we have a working example - and where I first became perplexed.
"SELECT COUNT(id) as count, id
FROM user
WHERE email='$email' AND password='".md5$password."'"
That is what is called alias which is sometimes used to show a more appealing column header to users or the calling code
SELECT COUNT(`id`) as `count`....
will print
count
--------
5
The alias standing as the column header instead of any arbitrary string: See the SQLFiddle to see the difference
From the fiddle you can see that the header column looks somehow e.g.
count(*)
--------
5
With Count() you can count the returning rows of a result set. The also the official MySQL documentation about count:
Databases are often used to answer the question, “How often does a certain type of data occur in a table?” For example, you might want to know how many pets you have, or how many pets each owner has, or you might want to perform various kinds of census operations on your animals.
Counting the total number of animals you have is the same question as “How many rows are in the pet table?” because there is one record per pet. COUNT(*) counts the number of rows, so the query to count your animals looks like this:
SELECT COUNT(*) FROM pet;
The part with AS count means that this colum will get a name which you can use e.g. in PHP. See also this explenation on w3schools:
You can give a table or a column another name by using an alias. This can be a good thing to do if you have very long or complex table names or column names.
An alias name could be anything, but usually it is short.
as count is just an alias. You can use as for any field or method selected. it means you change the name of the column being returned in your dataset.
SELECT `field` as another_name
So:
SELECT COUNT(*) as `count`
Just renames the column from COUNT(*) to count making it easier to work with whereever you are maniuplating your result set.
It also makes for easier access within your current query. Many would do the following with large table names:
SELECT * FROM `table_with_ridiculous_name` as twrn WHERE twrn.id = 1
If you ran this sql:
SELECT COUNT(id), id ....
You would get (after doing a *_fetch_assoc) $row['numberofrecordshere'] which would be very hard to echo (or use in a comparison) unless you knew how many records there would be (which would defeat the purpose of this result, anyway)
Returning it as count allows you to get to it in the resulting array by using $row['count']

Can I run a single SELECT rather than two nested to link two tables, omitting dupes, and return value if they match? MySQL / PHP

total n00b here, first post, so please be constructive! I've bought a book to teach myself PHP / MySQL - and not one which is universally praised, unfortunately - so my progress is a bit erratic.
I have two tables which I want to link. I want to display all of the information held in table 1 (let's call it Records), but ONLY once. I then want to check whether each item in Records has a match to a specific field in table 2 (UserTable) and if it does, display a ticked checkbox, or an empty checkbox if there's no match.
The issues I've had to date are only displaying the items from Records where there's a match, or displaying multiple instances of each item in Records where there are multiple matches. I've solved these with the code below - but I keep thinking there must be a better way to do this, perhaps with a single link?
Anyway, here are some excerpts from the code:
$sql = "SELECT * FROM Records";
$res = mysqli_query($mysqli,$sql);
while ($iteminfo = mysqli_fetch_array($res, MYSQLI_ASSOC)) {
$recordid2 = $iteminfo['record_id'];
I've omitted a section which pulls out the relevant data from Records and starts to build a table, then:
$sql2 = "SELECT COUNT(*) AS matches FROM UserTable
where usertable.item = '$recordid2' and User_ID = '$current_user_id'";
$res2 = mysqli_query($mysqli, $sql2);
$matches = mysqli_fetch_array($res2, MYSQLI_ASSOC);
$matches2 = $matches['matches'];
if ($matches2) {
$output = "<input type='checkbox' name='test' checked>"; } else {
$output = "<input type='checkbox' name='test'>";
As I say, this works, but it feels a bit clumsy - I'm running a separate nested query for every item in Records, which over time could become really slow. Is there a way to run a single query for the whole which brings through all of the row info (once) and a 0 or 1 depending on whether there is a match in UserTable? I've tried using DISTINCT but couldn't get it to work.
How about this:
SELECT * FROM Records
LEFT JOIN (
SELECT usertable.item, COUNT(User_ID) AS matches FROM UserTable
WHERE User_ID = '$current_user_id'
GROUP BY usertable.item
) as UserTable ON record_id = usertable.item
This fetches ALL records, and also only the matching rows for the given User ID in UserTable (change the User ID to fetch details for a different user).
If a row in Record exists, but no matching row exists in UserTable, then "matches" will be NULL. Otherwise it should be a numeric value greater than zero.
Just run this in PHP to handle the checkbox stuff. (it checks for matches greater than zero, and only if found, will print out the "checked" attribute)
<input type="checkbox" name="test" <?=((int)$record['matches'] > 0) ? 'checked="checked"' : ''; ?> />
Well done for noticing that the approach is clumsy. Take some time to look at the SQL language and better understand it. In particular you want to learn how to JOIN. Probably an INNER JOIN. Other types are FULL OUTER JOIN, LEFT OUTER JOIN and RIGHT OUTER JOIN.
I suggest that rather than doing the joining in the procedural code you do it in the SQL. Then make a single call to the DB, e.g.
select records.field1, records.field2, matches.field1, matches.field2
from records
, matches
where records.field = matches.field;
Play with this query until you get the results you want then call this from PHP
$sql = <query from above>
$res = mysqli_query($mysqli,$sql);
One good thing about this is that the SQL language is fairly transferable. Everything form Access to Oracle uses a similar syntax. And you can use this knowledge regardless of the procedural language you're working with (PHP, .NET, etc)
Good luck.

Categories