What is the best practice to execute multiple SQL queries using PHP PDO?
I have 4 tables and each of them is running on MyISAM. As such they do not have Foreign Key support. It's a one-to-many design whereby there is 1 main table and the other table contains reference to the main table in the form of IDs.
For now, what I do is that I run the first query to get the ID from the main table. Once that is executed, I then perform another query to query other tables using the ID from the first query. Results from both the queries are then merged together (array_merge) and then displayed to the user.
Here's my code so far. I think you will get the gist and you can most probably tell that I'm a super beginner in PHP. :)
$sql1 = "SELECT * FROM student_records WHERE name=? LIMIT 1";
$stmt1 = $db->prepare($sql1);
$stmt1->execute(array($name));
$e11 = $stmt1->fetch();
$id = $e1['id'];
$sql2 = "SELECT file_name FROM images WHERE id=? LIMIT 1";
$stmt2 = $db->prepare($sql2);
$stmt2->execute(array($id));
$e2 = $stmt2->fetch();
$e = array_merge($e1, $e2);
I think that the code above is somewhat repetitive and redundant. Is there any suggestion and tips on how I can improve this?
Use joins, and don't use SELECT * (select only the columns you need):
SELECT file_name
FROM student_records AS sr
JOIN images AS i ON sr.id = i.id
WHERE sr.name=?
Related
I'm making 4 individual queries to a MySQL DB, all of which are identical except the WHERE parameters. 2 of which are:
$totalInvites = mysqli_num_rows(mysqli_query($con, "SELECT code FROM invites"));
$usedInvites = mysqli_num_rows(mysqli_query($con, "SELECT code FROM invites WHERE used IS NOT NULL"));
Is there a way of doing the $totalInvites query and from the returned table, do the WHERE call without doing another query?
If that's confusing, this is an example of what I mean:
$query = mysqli_query($con, "SELECT code FROM invites");
$totalInvites = mysqli_num_rows($query);
$usedInvites = mysqli_num_rows($query /*WHERE used IS NOT NULL*/);
I know that's not proper syntax but that's what I was trying say.
If you just want counts then retrieving the entire database and throwing out the results is not really a good idea. Instead jus task for a count:
SELECT COUNT(*) AS count, used
GROUP BY used
This will give you up to two rows, one count for those that are used and one that isn't presuming used has only NULL or a single non-null value.
Use as little SQL as possible:
SELECT if(used is null, 0, 1) AS used, code
FROM invites
And parse result in PHP according to what you need
SELECT
(SELECT code FROM invites) total
(SELECT code FROM invites WHERE used IS NOT NULL) used
So i'm trying to fetch all of the user_id's from the users-events table where the event_id is equal to the passed in variable (let's say it's 2 for now.)
In the database there are currently 2 ID's registered to that event_id which are 1 and 2.
This code however only returns the first of these values. I feel like i need to incorporate the first query into the while loop but i dont know how to go about it.
Any help would be greatly appriciated!
function showregisteredplayers($id){
$eventq = mysql_fetch_assoc(mysql_query("SELECT user_id FROM `users-events` WHERE event_id = '".$id."'"));
$rosterq = mysql_query("SELECT username FROM `users` WHERE `user_id` = '".$eventq['user_id']."'");
while($player = mysql_fetch_assoc($rosterq)){
echo("
<tr>
<td>".$player['username']."</td>
</tr>
");
}
}
Use a sub query then kill your first one.
SELECT username FROM `users` WHERE `user_id` IN
(
SELECT user_id FROM `users-events` WHERE event_id = 5
)
Rest is fine, you already are looping over the second result set so this should do. Unless you have a large number of records, there should not be any considerable performance degradation with the use of IN otherwise you can optimize the query.
5 is obviously just an example, use $id there correctly.
Why not use a JOIN?
SELECT username
FROM `users` AS u
INNER JOIN `users-events` AS ue ON u.user_id = ue.user_id
WHERE event_id = ?
Several advices:
Don't use mysql_ functions because are deprecated
Use prepared queries, then you only need to loop through execute method, take a look to Example 3 in this link (example from php.net using mysqli)
Can I do this?
$query = "SELECT * FROM my_table";
$results = mysqli_query($db, $query)
$query = "SELECT name FROM $results";
$results = mysqli_query($db, $query)
Any help much appreciated!
No. For really complex queries you can use temporary tables:
CREATE TEMPORARY TABLE tmp SELECT * FROM my_table;
SELECT name FROM tmp;
But it causes big overhead for mysql server.
In your query, you are taking the results from this:
$query = "SELECT * FROM my_table";
And then trying to do this:
$query = "SELECT name FROM $results";
I can think of two things that you really want to do. The first is trivial:
$query = "SELECT name FROM my_table";
The second is that you want to get the table name from the first query and use it in the second. You can do that, assuming that the first query is returning one row and one columns. Or that the second is inside a loop and you have just oversimplified the code.
You can do this because you are constructing the strings that form the queries through the application. You cannot do this in basic SQL, because table names and column names cannot be dynamically created. They can be using a prepare statement, which is equivalent to constructing the strings in php.
I have a bunch of tables that are like Client# and the # changes. Is there a way to create a query to query that table based on the client number you get from logging in as their use?
Example to give idea:
$q2 = "SELECT * FROM users WHERE username = '".$_SESSION['username']."'";
$result2 = mysql_query($q2,$conn);
$row = mysql_fetch_assoc($result2);
$_CLIENT_ID = $row['CLIENTID'];
$q2 = "SELECT * FROM client+".$_CLIENT_ID."";
Is there a better way to do this?
I'm trying to keep clients in their own tables so they do not get to massive.
I'm trying to keep clients in their own tables so they do not get to massive.
This is almost always the wrong strategy. The table size isn't as important as how you have indexed it for access, and it can be partitioned later, should that become necessary. The proper way to handle this is simply a column in one table which identifies the client id.
With a proper client-identifying column you can query as:
SELECT othertable.*
FROM
users
JOIN othertable ON users.CLIENTID = othertable.CLIENTID
WHERE users.username = '$_SESSION['username']'
Dealing with dynamic table names becomes troublesome not only because it is more difficult to query against. You cannot, for example, use a placeholder in place of a table name with many parameterized query APIs like PDO & MySQLi:
// Won't work with a PDO prepared statement. :clienttable place holder isn't allowed
SELECT * FROM :clienttable WHERE value=:someval
I try to avoid doing Count() because of performance issue. (i.e. SELECT COUNT() FROM Users)
If I run the followings in phpMyAdmin, it is ok:
SELECT SQL_CALC_FOUND_ROWS * FROM Users;
SELECT FOUND_ROWS();
It will return # of rows. i.e. # of Users.
However, if I run in in PHP, I cannot do this:
$query = 'SELECT SQL_CALC_FOUND_ROWS * FROM Users;
SELECT FOUND_ROWS(); ';
mysql_query($query);
It seems like PHP doesn't like to have two queries passing in. So, how can I do that?
SQL_CALC_FOUND_ROWS is only useful if you're using a LIMIT clause, but still want to know how many rows would've been found without the LIMIT.
Think of how this works:
SELECT SQL_CALC_FOUND_ROWS * FROM Users;
You're forcing the database to retrieve/parse ALL the data in the table, and then you throw it away. Even if you aren't going to retrieve any of the rows, the DB server will still start pulling actual data from the disk on the assumption that you will want that data.
In human terms, you bought the entire contents of the super grocery store, but threw away everything except the pack of gum from the stand by the cashier.
Whereas, doing:
SELECT count(*) FROM users;
lets the DB engine know that while you want to know how many rows there are, you couldn't care less about the actual data. On most any intelligent DBMS, the engine can retrieve this count from the table's metadata, or a simple run through the table's primary key index, without ever touching the on-disk row data.
Its two queries:
$query = 'SELECT SQL_CALC_FOUND_ROWS * FROM Users';
mysql_query($query);
$query = 'SELECT FOUND_ROWS()';
mysql_query($query);
PHP can only issue a single query per mysql_query call
It's a common misconception, that SQL_CALC_FOUND_ROWS performs better than COUNT(). See this comparison from Percona guys: http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
To answer you question: Only one query is allowed per one mysql_query call, as described in manual: mysql_query() sends a unique query (multiple queries are not supported)
Multiple queries are supported when using ext/mysqli as your MySQL extension:
http://www.php.net/manual/en/mysqli.multi-query.php
Only this code works for me so i want to share it for you.
$Result=mysqli_query($i_link,"SELECT SQL_CALC_FOUND_ROWS id From users LIMIT 10");
$NORResult=mysqli_query($i_link,"Select FOUND_ROWS()");
$NORRow=mysqli_fetch_array($NORResult);
$NOR=$NORRow["FOUND_ROWS()"];
echo $NOR;
Use 'union' and empty columns:
$sql="(select sql_calc_found_rows tb.*, tb1.title
from orders tb
left join goods tb1 on tb.goods_id=tb1.id
where {$where}
order by created desc
limit {$offset}, {$page_size})
union
(select found_rows(), '', '', '', '', '', '', '', '', '')
";
$rs=$db->query($sql)->result_array();
$total=array_pop($rs);
$total=$total['id'];
This is an easy way & works for me :
$query = "
SELECT SQL_CALC_FOUND_ROWS *
FROM tb1
LIMIT 5";
$result = mysqli_query($link, $query);
$query = "SELECT FOUND_ROWS() AS count";
$result2 = mysqli_query($link, $query);
$row = mysqli_fetch_array($result2);
echo $row['count'];
Do you really think that selecting ALL rows from tables is faster than counting them?
Myisam stores a number of records in table's metadata, so SELECT COUNT(*) FROM table don't have to access data.