Join two table with pdo - php

I'd like to join two tables in my database. It works fine the 'classic' way but there are a bunch of select query in my script, so I'd like to shorten it...
Here is the joint sql:
SELECT
matches.id, matches.start_time, matches.category_id,
matches.highl, first_team.tid, first_team.t_name,
second_team.tid, second_team.t_name AS ft_name
FROM matches
INNER JOIN teams AS first_team ON matches.first_team_id = first_team.tid
INNER JOIN teams AS second_team ON matches.second_team_id = second_team.tid
ORDER BY matches.id DESC
LIMIT 10
What I want to achive is something like this, but I don't exactly know how to add all the values I copied above.
public function getMatches($table,$conditions = array()){
$sql = 'SELECT ';
$sql .= array_key_exists("select",$conditions)?$conditions['select']:'';
$sql .= ' FROM '.$table;
if(array_key_exists("where",$conditions)){
$sql .= ' WHERE ';
$i = 0;
foreach($conditions['where'] as $key => $value){
$pre = ($i > 0)?' AND ':'';
$sql .= $pre.$key." = '".$value."'";
$i++;
}
}
if(array_key_exists("inner_join",$conditions)){
$sql .= ' INNER JOIN '.$conditions['inner_join'];
}
if(array_key_exists("on",$conditions)){
$sql .= ' ON '.$conditions['on'];
}
if(array_key_exists("as",$conditions)){
$sql .= ' AS '.$conditions['as'];
}
if(array_key_exists("order_by",$conditions)){
$sql .= ' ORDER BY '.$conditions['order_by'];
}
if(array_key_exists("start",$conditions) && array_key_exists("limit",$conditions)){
$sql .= ' LIMIT '.$conditions['start'].','.$conditions['limit'];
}elseif(!array_key_exists("start",$conditions) && array_key_exists("limit",$conditions)){
$sql .= ' LIMIT '.$conditions['limit'];
}
$query = $this->db->prepare($sql);
$query->execute();
if(array_key_exists("return_type",$conditions) && $conditions['return_type'] != 'all'){
switch($conditions['return_type']){
case 'count':
$data = $query->rowCount();
break;
case 'single':
$data = $query->fetch(PDO::FETCH_ASSOC);
break;
default:
$data = '';
}
}else{
if($query->rowCount() > 0){
$data = $query->fetchAll();
}
}
return !empty($data)?$data:false;
}
}
Here is the output:
<div class="panel-heading">Matches</div>
<table class="table">
<tr>
<th>#</th>
<th>First Team</th>
<th>Second Team</th>
<th>Start Time</th>
</tr>
<?php
include 'inc/functions.php';
$db = new DB();
$matches = $db->getMatches('matches', array('inner_join'=>'teams'), array('as'=>'first_team'), array('on'=>'matches.first_team_id = first_team.tid'), array('inner_join'=>'teams'), array('as'=>'second_team'), array('on'=>'matches.second_team_id = second_team.tid'), array('order_by'=>'matches.id'));
if(!empty($matches)){ $count = 0; foreach($matches as $result){ $count++;?>
<tr>
<td><?php echo $count; ?></td>
<td><?php echo $result['ft_name']; ?></td>
<td><?php echo $result['t_name']; ?></td>
<td><?php echo $result['start_time']; ?></td>
</tr>
<?php } }else{ ?>
<tr><td colspan="4">No entry found!</td>
<?php } ?>
</table>
</div>

With all the honesty, for the life of me I will never ever ever understand, how such wall of PHP arrays
array('inner_join'=>'teams'), array('as'=>'first_team'),
array('on'=>'matches.first_team_id = first_team.tid'),
array('inner_join'=>'teams'),
array('as'=>'second_team'),
array('on'=>'matches.second_team_id = second_team.tid'),
array('order_by'=>'matches.id'));
can be even remotely considered "shorter" than elegant and compact SQL
SELECT
matches.id, matches.start_time, matches.category_id,
matches.highl, first_team.tid, first_team.t_name,
second_team.tid, second_team.t_name AS ft_name
FROM matches
INNER JOIN teams AS first_team ON matches.first_team_id = first_team.tid
INNER JOIN teams AS second_team ON matches.second_team_id = second_team.tid
ORDER BY matches.id DESC
LIMIT 10
Let alone the meaningfulness and readability.
Are you talking of saving yourself typing a few SQL keywords like SELECT or FROM? Seriously? Does it really worth making such a mess out of a meaningful and comprehensible SQL?

Related

Select query executing twice

I'm writing a simple page to retrieve "PO Numbers" that belong to the logged-in user. That portion is working fine with the exception of the query returning 2 complete sets of records. I have checked for page refresh issues, as mentioned in other posts I've read, but none have been found.
poTable.php
<table class="table" style="width: 100%">
<thead class="thead-dark">
<tr>
<th scope="col">PO#</th>
<th scope="col">Job#</th>
<th scope="col">Job Name</th>
<th scope="col">Salesperson</th>
<th scope="col">Vendor</th>
<th scope="col">Date</th>
</tr>
</thead>
<tbody>
<?php include 'usersPOs.php'?>
</tbody>
</table>
usersPOs.php
$db = mysqli_connect('localhost', 'root', '', 'acs-jobs-pos');
$userID = $_SESSION['userID'];
$userPrivs = $_SESSION['admin'];
if ($userPrivs == 0) { // User IS NOT an admin
// Get ALL main table records that belong to the logged-in user
$sqlmain = "SELECT * FROM main INNER JOIN users ON main.userID = '" . $userID . "'";
//debug_print_backtrace();
$resultmain = mysqli_query($db,$sqlmain);
while($rowmain = mysqli_fetch_assoc($resultmain))
{
?>
<tr>
<?php
$PONumb = $rowmain["PONumb"];
$jobNumber = $rowmain["jobNumber"];
$jobName = $rowmain["jobName"];
$salespersonID = $rowmain["salespersonID"];
$vendorID = $rowmain["vendorID"];
$timestamp = $rowmain["timestamp"];
?>
<td><?php echo $PONumb ?></td>
<td><?php echo $jobNumber ?></td>
<td><?php echo $jobName ?></td>
<?php
$sqlsp = "SELECT * FROM users WHERE userID = '" . $salespersonID . "'";
$resultsp = mysqli_query($db,$sqlsp);
$rowsp = mysqli_fetch_assoc($resultsp);
if ($rowsp["lastname"] == '' && $rowsp["firstname"] == '') {
?>
<td></td>
<?php
} else {
?>
<td><?php echo $rowsp["lastname"] . ', ' . $rowsp["firstname"] ?></td>
<?php
}
$sqlvendor = "SELECT * FROM vendor
WHERE vendorID = '" . $vendorID . "'";
$resultvendor = mysqli_query($db,$sqlvendor);
$rowvendor = mysqli_fetch_assoc($resultvendor);
?>
<td><?php echo $rowvendor["vendorname"] ?></td>
<td><?php echo $timestamp ?></td>
</tr>
<?php
}
mysqli_close($db);
}
This code could be hugely simplified by use of joins. I'd also recommend using PDO for your database access; it's less verbose and makes prepared statements easier (and those are not optional in any environment.) Only relevant columns are selected from the database. A heredoc block is also used to simplify output.
<?php
$db = new PDO('mysql:host=localhost;dbname=acs-jobs-pos', 'root', '');
$userID = $_SESSION['userID'];
$userPrivs = $_SESSION['admin'];
if ($userPrivs == 0) {
$sql = "SELECT m.PONumb, m.jobNumber, m.jobName, m.salespersonID, m.vendorID, m.timestamp,
u.lastname, u.firstname, v.vendorname
FROM main m
LEFT JOIN users u ON (m.salespersonID = u.userID)
LEFT JOIN vendors v ON (m.vendorID = v.vendorID)
WHERE m.userID = ?";
$stmt = $db->prepare($sql);
$stmt->execute([$userID]);
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach ($results as $row) {
echo <<< HTML
<tr>
<td>$row[PONumb]</td>
<td>$row[jobNumber]</td>
<td>$row[jobName]</td>
<td>$row[lastname], $row[firstname]</td>
<td>$row[vendorname]</td>
<td>$row[timestamp]</td>
</tr>
HTML;
}
}
follow sql error
"SELECT * FROM main INNER JOIN users ON main.userID = '" . $userID . "'";
you can not use join as this, something like
"SELECT * FROM main INNER JOIN users ON main.userID = users.ID where users.ID='" . $userID . "'";

Displaying query in browser with table

Hi there i am using a sqlite database and i have written a query in php that is running. However i cant seem to build a solution that will display the results of this query in the browser (tabular or other). Here is my code. This is the last element of this system so help is appreciated.
Code:
$db = new PDO('sqlite:daypilot.sqlite');
$start = '2018-02-20';
$end = '2018-02-25';
$sql = 'SELECT * FROM events WHERE end > ? AND start < ?';
$stmt = $db->prepare($sql); $stmt->execute([$start, $end]);
$events = $stmt->fetchAll();
[Update] From comment, OP has tried
<table>
<tr>
<th>id</th> <th>name</th> <th>contact</th>
</tr>
<?php foreach ($events as $event): ?>
<tr>
<td><?php echo $event['id'] ?></td>
<td><?php echo $event['name'] ?></td>
<td><?php echo $event['contact'] ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php
$db = new PDO('sqlite:daypilot.sqlite');
$start = '2018-02-20';
$end = '2018-02-25';
$sql = 'SELECT * FROM events WHERE end > ? AND start < ?';
$stmt = $db->prepare($sql); $stmt->execute([$start, $end]);
$events = $stmt->fetchAll(PDO::FETCH_ASSOC);
$table = '<table>';
foreach($events as $event) {
$table .= ' <tr>';
$table .= ' <td>' . $event['column_name'] . '</td>';
// repeat for every column you want to add
$table .= ' </tr>';
}
$table .= '</table>';
echo $table;
?>
Well, this is the simplest (and not the best) way to build the HTML table. You should insert that snippet code in the place where you want the table appears.
I passed PDO::FETCH_ASSOC to fetchAll method to ensure that the data are returned as associative array, then you have to iterate over it and extract the desired columns

inline td with th using loop in PHP

So I have this tables on my database that I have to display as table in html. The problem is I do not know how I am going to inline my td with my th and add zero to the person who doesn't have allowance.
This is the image of my allowance table
.
So far this is what i have:
<?php
error_reporting(0);
include "./includes/connectdb.php";
$emp = "select * from employee";
$q = $dbhandle->query($emp);
if($q->num_rows>0){
$all = "select distinct allowance from emp_allowances order by allowance asc";
$a = $dbhandle->query($all);
if($a->num_rows>0) {
while($b = $a->fetch_assoc()){
$thallowance .= '<th>'.$b['allowance'].'</th>';
$empallowance = $b['allowance'];
}
}
while($r = $q->fetch_assoc()){
$id= $r['id'];
$name= $r['name'];
$all2 = "select * from emp_allowances order by allowance asc";
$c = $dbhandle->query($all2);
if($c->num_rows>0){
$tdallow='';
while($d = $c->fetch_assoc()){
$empid = $d['emp_id'];
$empallowance = $d['allowance'];
$amount = $d['amount'];
if($empid==$id){
$tdallow.='<td>'.$amount.'</td>';
}
}
}
$tbody .= '<tr>
<td>'.$name.'</td>
'.$tdallow.'
</tr>';
}
}
$thead = '
<thead>
<tr>
<th>Name</th>
'.$thallowance.'
</tr>
</thead>
';
?>
<table border=1>
<?php echo $thead; ?>
<tbody>
<?php echo $tbody; ?>
</tbody>
And from this code i got this result.
I changed your while loop, try to copy it and see if works.
The $tdarray sets all allowances to zero, if some of them has a greater value it is set in the employee allowances loop. This way if there is no allowance for an employee there will be zero and properly inline, because the default values (zeros) are preset.
Let me know if works.
<?php
error_reporting(0);
include "./includes/connectdb.php";
$emp = "select * from employee";
$q = $dbhandle->query($emp);
if($q->num_rows>0){
// array that will hold key value pairs for allowances
$tdarray = array();
$all = "select distinct allowance from emp_allowances order by allowance asc";
$a = $dbhandle->query($all);
if($a->num_rows>0) {
while($b = $a->fetch_assoc()){
$thallowance .= '<th>'.$b['allowance'].'</th>';
$empallowance = $b['allowance'];
// fill the array with keys (allowances) and default, zero values
$tdarray[$b['allowance']] = 0;
}
}
// Looping through employees
while($r = $q->fetch_assoc()){
$id= $r['id'];
$name= $r['name'];
$all2 = "select * from emp_allowances order by allowance asc";
$c = $dbhandle->query($all2);
if($c->num_rows>0){
$tdallow='';
// Looping through employee allowances
while($d = $c->fetch_assoc()){
$empid = $d['emp_id'];
$amount = $d['amount'];
$empallowance = $d['allowance'];
if($empid==$id){
$tdarray[$empallowance] = $amount;
}
}
}
$tbody .= '<tr>';
$tbody .= '<td>'.$name.'</td>';
foreach ($tdarray as $allowance => $amount) {
$tbody .= '<td>'.$amount.'</td>';
// reset to zero
$tdarray[$allowance] = 0;
}
$tbody .= '</tr>';
}
try adding else with your code:
if($empid==$id){
$tdallow.='<td>'.$amount.'</td>';
}else{ // add else block for print zero
$tdallow.='<td>0</td>';
}

Invalid argument supplied for foreach()

i'm coding a project and have some troubles when the system inform error:
Invalid argument supplied for foreach() in:
foreach($dbh->query($q1) as $row)
and can't get data from the database. How can i fix it, im a newbie, so if i don't understand, please teach me! thanks!
thank for your helps but i still can't fix it
<?php include("top.html"); ?>
<body>
<div id="main">
<h1>Results for <?php echo $_GET['firstname'] . " " . $_GET['lastname'] ?></h1> <br/><br/>
<div id="text">All Films</div><br/>
<table border="1">
<tr>
<td class="index">#</td>
<td class="title">Title</td>
<td class="year">Year</td>
</tr>
<?php
$dbh = new PDO('mysql:host=localhost;dbname=imdb_small', 'root', '');
$q1 = "SELECT id
FROM actors
WHERE first_name = '".$_GET['firstname']."' AND last_name = '".$_GET['lastname']."'
AND film_count >= all(SELECT film_count
FROM actors
WHERE (first_name LIKE'".$_GET['firstname']." %' OR first_name = '".$_GET['firstname']."')
AND last_name = '".$_GET['lastname']."')";
$id = null;
foreach($dbh->query($q1) as $row){
$id = $row['id'] ;
}
if($id == null){
echo "Actor ".$_GET['firstname']." ".$_GET['lastname']."not found.";
}
`
$sql2 = "SELECT m.name, m.year
FROM movies m
JOIN roles r ON r.movie_id = m.id
JOIN actors a ON r.actor_id = a.id
WHERE (r.actor_id='".$id."')
ORDER BY m.year DESC, m.name ASC";
$i = 0;
foreach($dbh->query($sql2) as $row){
echo "<tr><td class=\"index\">";
echo $i+1;
echo "</td><td class=\"title\">";
echo $row['name'];
echo "</td><td class=\"year\">";
echo $row['year'];
echo "</td></tr>";
$i++;
}
$dbh = null;
?>
</table>
</div>
</div>
<?php include("bottom.html"); ?>
</body>
</html>
Check that your query succeeded before iterating on the result:
if (false !== ($result = $dbh->query($d1))) {
foreach($result as $row){
$id = $row['id'] ;
}
}
By the way, I don't understand what you are trying to do with this pointless loop.
You could do this
$st = $dbh->query($q1);
if ( $st ) {
while ( $row = $st->fetch() ) {}
}
Try to make your code more readable
$result = $dbh->query($q1);
foreach($result as $row){$id = $row['id'];}

Date function not working with bind_result

I have this date format in place in my files. It works great if I do a normal SELECT query, but when I do a prepared statement query that does not have a bind_param and assign it a bind_result variable, I cannot get this to work.
Here is the function. Which it displays in US Central time. How can I get that to Eastern time?
function fixDate($strDateTime) {
$strFormat = 'M, j, Y';
$strFormatTime = '\a\t g:ia';
$intTimeStamp = strtotime($strDateTime);
$strDate = date($strFormat, $intTimeStamp);
$strTime = date($strFormatTime, $intTimeStamp);
if($strDate == date($strFormat)) {
return "Today " . $strTime;
}
elseif($strDate == date($strFormat, strtotime('yesterday'))) {
return "Yesterday " . $strTime;
}
else {
return " on " . $strDate . " " . $strTime;
}
}
The function will work if I do this with a normal SELECT query.
$date = $row2['topic_date'];
$date = fixDate($date);
BUT if I have a bind_result of $date and try to do this
$date = fixDate($date);
It won't work.
How can I get this function to work with a prepared statement's bind_result variable?
UPDATE:
This works..
$query2 = mysqli_query($con,"SELECT * FROM forum_topics
INNER JOIN forum_categories ON
forum_topics.category_id = forum_categories.id
INNER JOIN users
ON forum_topics.topic_creator = users.id
ORDER BY forum_topics.topic_reply_date DESC
LIMIT 3")
or die ("Query2 failed: %s\n".($query2->error));
$numrows2 = mysqli_num_rows($query2);
if($numrows2 > 0){
$topics .= "<table class='top_posts_table'>";
$topics .= "<tr><th class='top_posts_th'>Topic Title</th><th class='top_posts_th'>Replies</th><th class='top_posts_th'>Views</th></tr>";
$topics .= "<tr><td colspan='3'><hr /></td></tr>";
while($row2 = mysqli_fetch_assoc($query2)){
$cid = $row2['cid'];
$tid = $row2['id'];
$title = $row2['topic_title'];
$views = $row2['topic_views'];
$replies = $row['tid2'];
$date = $row2['topic_date'];
$date = fixDate($date);
$creator = $row2['username'];
$topics .= "<tr><td class='top_posts_td'><a href='forum_view_topic.php?cid=".$cid."&tid=".$tid."'>".$title."</a><br /><span class='post_info'>Posted
by: ".$creator."<br>".$date."</span></td><td class='top_posts_td'>0</td><td class='top_posts_td'>".$views."</td></tr>";
$topics .= "<tr><td colspan='3'><hr /></td></tr>";
This doesn't work...
if ($announcements_stmt = $con->prepare("SELECT announcements.id, announcements.user_id, announcements.message, announcements.date, users.username FROM announcements
INNER JOIN users
ON announcements.user_id = users.id")) {
$announcements_stmt->execute();
$announcements_stmt->bind_result($announcements_id, $announcements_user_id, $announcements_messages, $announcements_date, $announcements_username);
if (!$announcements_stmt) {
throw new Exception($con->error);
}
}
$announcements_stmt->store_result();
$announcements_result = array();
$announcements_date = $announcements_date;
$announcements_date = fixDate($announcements_date);
?>
<div class="index_announcements_out">
<div id="announcements_title">League Announcements:</div>
<div class="index_announcements_wrap">
<table class="index_announcements_table">
<?php
while ($row = $announcements_stmt->fetch()) {
?>
<tr class="index_announcements_border">
<td class="index_announcement_pic"></td>
<td class="index_announcement_username_td">FROM: <?php echo $announcements_username; ?><br>on <?php echo $announcements_date; ?></td>
<td class="index_announcement_message_td"><?php echo $announcements_messages; ?></td>
</tr>
Basically, when using bind_result(), you need to do a fetch() before the variables get populated. In this case, you're trying to access them before that happens.
In the given code, it's not necessary to get the fixed $announcements_date outside the while loop, so just replacing <?php echo $announcements_date; ?> with <?php echo fixDate($announcements_date); ?> in the loop should do the trick.

Categories