I am using this code to send out emails to my relevent partners, the problem I have is that sometimes the partner ID comes up twice and send the partner 2 x emails (duplicate), how can I prevent this?
$get_partner_id = "SELECT partner_id FROM partners_locations WHERE location_id ='$location_id'";
if ($partner_ids = $connect->query($get_partner_id)) {
foreach ($partner_ids as $partner_id) {
$partner_id = $partner_id['partner_id'];
//CONVERT PARTNER IDS TO RELATED PARTNER NAME AND SEND
$get_partner_names = "SELECT partner_name FROM partners WHERE partner_id ='$partner_id' AND active ='yes'";
if ($partner_names = $connect->query($get_partner_names)) {
foreach ($partner_names as $partner_name) {
$partner_name = $partner_name['partner_name'];
// GET ADMIN EMAIL TEMPLATE
ob_start();
include (TEMPLATEPATH . '/quote/admin-email-template.php');
$admin_message = ob_get_clean();
#mail("alerts#myremovalsquote.com", "Referral for " . $partner_name . "", $admin_message, $admin_headers);
}
}
else {
}
}
}
else {
}
First, simplify your code to just use a single query. In general, when working with SQL, you don't need loops in the application code. Use a JOIN:
SELECT p.partner_name
FROM partners_locations pl JOIN
partners p
ON p..partner_id = p.partner_id AND p.active ='yes'"
WHERE pl.location_id = '$location_id';
Next, you probably have a data problem, where partners are listed multiple times in the data, somehow. You might want to investigate that, if these values should be unique. In the meantime, you can use SELECT DISTINCT:
SELECT DISTINCT p.partner_name
FROM partners_locations pl JOIN
partners p
ON p..partner_id = p.partner_id AND p.active ='yes'"
WHERE pl.location_id = '$location_id';
Related
I have two different tables, one named users, and another named transactions. Transactions contains wallet1, wallet2, amount. Users contains user details such as firstname, lastname, and wallet. I am trying to display the corresponding first name and last name, depending on whether or not the SESSION_wallet is equal to wallet1 or wallet2 within transactions. I tried searching for a while, and came up with a solution for showing the correct display name for the first and last name making the transfer, however, I am trying to make it display the correct value for "Transfer to:"
Here is some of my code to get a better understanding of what I mean:
MySQLi Query:
$result2 = mysqli_query($link, "SELECT * FROM transactions INNER JOIN users ON transactions.wallet1 = users.wallet WHERE transactions.wallet1 = '" . $_SESSION["wallet"] . "' OR transactions.wallet2 = '" . $_SESSION["wallet"] . "' Order by transactions.id DESC LIMIT 5 ");
PHP Code:
<?php
if(mysqli_num_rows($result2) > 0)
{
while($row = mysqli_fetch_array($result2))
{
?>
The table that needs to display the transfer from, and transfer to:
<?php
if ($_SESSION["wallet"] == $row["wallet1"]) {
echo "<td>Transfer to ".$row["firstname"]." ".$row["lastname"]."</td>";
}
else if ($_SESSION["wallet"] == $row["wallet2"]) {
echo "<td>Transfer from ".$row["firstname"]." ".$row["lastname"]."</td>";
}
?>
Right now my tables are only showing the first and last name of the user that made the Transfer, however, I need it to display the first and last name of the user that the transaction is made to as well. The else if code is working correct, but the first part is not showing the corresponding value.
You will need to JOIN your transactions table to your users table twice, once to get each users name. Then to avoid duplicate column names overwriting the results in the output array, you will need to use column aliases. Something like this should work:
$result2 = mysqli_query($link, "SELECT t.*,
u1.firstname AS w1_firstname,
u1.lastname AS w1_lastname,
u2.firstname AS w2_firstname,
u2.lastname AS w2_lastname
FROM transactions t
INNER JOIN users u1 ON t.wallet1 = u1.wallet
INNER JOIN users u2 ON t.wallet2 = u2.wallet
WHERE t.wallet1 = '{$_SESSION["wallet"]}'
OR t.wallet2 = '{$_SESSION["wallet"]}'
ORDER BY t.id DESC
LIMIT 5 ");
Then you can access each user's names as $row['w1_firstname'] etc.:
if ($_SESSION["wallet"] == $row["wallet1"]) {
echo "<td>Transfer to ".$row["w2_firstname"]." ".$row["w2_lastname"]."</td>";
}
else if ($_SESSION["wallet"] == $row["wallet2"]) {
echo "<td>Transfer from ".$row["w1_firstname"]." ".$row["w1_lastname"]."</td>";
}
Note that ideally you should use a prepared query for this, for example:
$stmt = $link->prepare("SELECT t.*,
u1.firstname AS w1_firstname,
u1.lastname AS w1_lastname,
u2.firstname AS w2_firstname,
u2.lastname AS w2_lastname
FROM transactions t
INNER JOIN users u1 ON t.wallet1 = u1.wallet
INNER JOIN users u2 ON t.wallet2 = u2.wallet
WHERE t.wallet1 = ?
OR t.wallet2 = ?
ORDER BY t.id DESC
LIMIT 5");
$stmt->bind_param('ss', $_SESSION["wallet"], $_SESSION["wallet"]);
$stmt->execute();
$result2 = $stmt->get_result();
For this problem I need to make a PHP page where the user can search an invoice table by inputting a "quantity" value. The form then takes that quantity and spits out a table with the name, invoice number, quantity, and item description for all invoices where the quantity exceeds the quantity the user submitted.
For the most part I have my page set up and working fine. Where I'm getting stuck is on the query side -- specifically, the code below is providing me a list of invoices where the quantity is identical to the input quantity.
I've tried changing "WHERE ii.quantity LIKE ?" to "WHERE ii.quantity > ?" but all that does is provide me a list of all invoices without filtering by the user submitted quantity.
$query =
"SELECT c.first_name, c.last_name, ii.invoice_id, ii.quantity, it.description
FROM `c2092`.`customer` c
JOIN `c2092`.`invoice` i ON c.customer_id = i.customer_id
JOIN `c2092`.`invoice_item` ii ON ii.invoice_id = i.invoice_id
JOIN `c2092`.`item` it ON it.item_id = ii.item_id
WHERE ii.quantity LIKE ?
ORDER BY ii.invoice_id";
This is too complex query. Try to make explain on it. I am sure it will use filesort, and even temp table.
The better approach is to make several queries:
$invoiceItems = $db->query(
"SELECT ii.invoice_id, ii.id, ii.quantity, it.description
FROM `c2092`.`invoice_item` ii
JOIN `c2092`.`item` it ON it.item_id = ii.item_id
WHERE ii.quantity > ?
ORDER BY ii.invoice_id");
$invoiceItemMap = [];
$invoiceIds = [];
foreach ($invoiceItems as $invoiceItem) {
$invoiceItemMap[$invoiceItem['invoice_id']][] = $invoiceItem;
$invoiceIds[$invoiceItem['invoice_id']] = $invoiceItem['invoice_id'];
}
$invoiceIds = array_values($invoiceIds);
$userInvoices = $db->query(
"SELECT c.first_name, c.last_name, i.invoice_id
FROM `c2092`.`invoice` i
JOIN `c2092`.`customer` c ON c.customer_id = i.customer_id
WHERE i.id IN (".implode(',', $invoiceIds).")");
$result = [];
foreach ($userInvoices as $row) {
$result[] = array_merge($row, $invoiceIds[$row['invoice_id']]);
}
Hello,
What is the value of your variable?
Prefer the use of named parameter instead of ? syntax.
This is a hypothetical question. If I have 3 arrays from 3 separate sql db queries that all relate to another. For example...
//db
schools
id | school_name
classes
id | class_name | school_id
students
id | student_name | class_id
And I want to display everything in a huge list like this...
//php
foreach(schools as school){
echo '<h1>' . $school->school_name . '<h1>';
foreach(classes as class){
if($class->school_id == $school->id){
echo '<h2>' . $class->class_name . '<h2>';
foreach(students as student){
if($student->class_id == $class->id){
echo '<h3>' . $student->student_name . '<h3>';
}
}
}
}
}
I have to make 3 database calls. Is there a way to grab all this information in a single db query? Like maybe an array in an array in an array and then somehow loop through? Or is this the best way to do this?
You can do a join which will allow you to have 1 for each. Are you wanting everything or any sort of filter ?
You can join those table, to get one big array with flattened data. When looping through this data, you can check if the id of the previous record still matches the id of the current record. If not, you can output a new header. It is important, though, that the resultset is properly sorted for this.
SELECT
s.id AS school_id,
s.school_name,
c.id AS class_id,
c.class_name,
st.id AS student_id,
st.student_name
FROM
schools s
INNER JOIN classes c ON c.school_id = s.id
INNER JOIN students st ON st.class_id = c.id
ORDER BY
s.id,
c.id,
st.id
If you have it all in a flattened structure, you can even make it into a nested array structure again something like this:
foreach ($resultset as $row)
{
$schools[$row->school_id]->school_name =
$row->school_name;
$schools[$row->school_id]->classes[$row->class_id]->class_name =
$row->class_name;
$schools[$row->school_id]->classes[$row->class_id]->students[$row->student_id]->student_name =
$row->student_name;
}
var_dump($schools);
After that, you can still use the nested for loops to process the array, but it will be in a more efficient way, since the data is already sorted out: classes are already added to the school they belong to, and student are already added to the right class.
<?php
try {
$pdo = new PDO("mysql:host=127.0.0.1;dbname=school", "username");
} catch (PDOException $e) {
echo "PDO Connection failed: " . $e->getMessage();
exit(1);
}
$sql = <<<SQL
SELECT schools.school_name, classes.class_name, students.student_name
FROM
schools INNER JOIN classes ON (schools.id = classes.school_id)
INNER JOIN students ON (classes.id = students.class_id)
ORDER BY 1, 2;
SQL;
$result = $pdo->query($sql);
if ($result == false) {
die("query failed?!");
}
$school = "";
$class = "";
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
if ($school != $row['school_name']) {
$school = $row['school_name'];
echo "\nSchool: $school\n\n";
}
if ($class != $row['class_name']) {
$class = $row['class_name'];
echo " Class: $class\n\n";
echo " Student list:\n";
}
echo " {$row['student_name']}\n";
}
$res = mysql_query('SELECT school_name, class_name, student_name, sc.id AS scid, c.id AS cid, st.id AS stid FROM schools sc LEFT JOIN classes c ON (sc.id = c.school_id) LEFT JOIN students st ON (c.id = st.class_id) ');
$arr = array();
while ($v = mysql_fetch_assoc($res)) {
$arr[$v['school_name']][$v['class_name']][$v['stid']] = $v['student_name'];
}
print_r($arr);
You could do it all in one SQL query that might look something like:
SELECT schools.schoolname, classes.class_name, students.student_name
FROM
schools INNER JOIN classes ON (schools.id = classes.school_id)
INNER JOIN students ON (classes.id = students.class_id)
ORDER BY 1, 2;
Then you could walk the result set in one loop, but you'd probably want to add some logic to only display the school name and class name once for each time it changes.
I need your help with a small thing. I have two tables I need to get a list of the names and IDs of the people from the first table. Then use this list to get the services associated to these people.
Please keep in mind that I need both the name and ID to identify the service.
The query is similar to the following:
$query = "SELECT id, name from person where customerType='specificType';
$result = mysql_query($query,$this->connection);
After that I loop through the result of this query to get the services list:
While ($list=mysql_fetch_array($result))
{
$query = "SELECT serviceID, serviceName from services
where assignedToName='".$list['name']."' and assignedToID=".$list['id'];
$result2 = mysql_query($query,$this->connection);
if(!$result2 || mysql_num_rows($result2) <= 0)
{//I do nothing}
else{
if(isset($servicesList))
{
//Here is the part that is not working, How to combine the results??
$servicesList .= $result;
}
else $servicesList=$result;
}
}
//End While
if(isset($servicesList))
{ return $servicesList;}else {
return 'error';
}
Thanks in advance...
Please consider using a join and just one query.
Something like this:
SELECT
p.id,
p.name,
s.serviceID,
s.serviceName
FROM
person p
LEFT JOIN
services s
ON
(p.id = s.assignedToID
AND
p.name = s.assignedToName)
WHERE
p.customerType='specificType'
I'm building a simple web app at the moment that I'll one day open source. As it stands at the moment, the nav is generated on every page load (which will change to be cached one day) but for the moment, it's being made with the code below. Using PHP 5.2.6 and MySQLi 5.0.7.7, how more efficient can the code below be? I think joins might help, but I'm after advice. Any tips would be greatly appreciated.
<?php
$navQuery = $mysqli->query("SELECT id,slug,name FROM categories WHERE live=1 ORDER BY name ASC") or die(mysqli_error($mysqli));
while($nav = $navQuery->fetch_object()) {
echo '<li>';
echo ''. $nav->name .'';
echo '<ul>';
$subNavQuery = $mysqli->query("SELECT id,name FROM snippets WHERE category='$nav->id' ORDER BY name ASC") or die(mysqli_error($mysqli));
while($subNav = $subNavQuery->fetch_object()) {
echo '<li>';
echo ''. $subNav->name .'';
echo '</li>';
}
echo '</ul>';
echo '</li>';
}
?>
You can run this query:
SELECT c.id AS cid, c.slug AS cslug, c.name AS cname,
s.id AS sid, s.name AS sname
FROM categories AS c
LEFT JOIN snippets AS s ON s.category = c.id
WHERE c.live=1
ORDER BY c.name, s.name
Then iterate thru the results to create the proper heading like:
// last category ID
$lastcid = 0;
while ($r = $navQuery->fetch_object ()) {
if ($r->cid != $lastcid) {
// new category
// let's close the last open category (if any)
if ($lastcid)
printf ('</li></ul>');
// save current category
$lastcid = $r->cid;
// display category
printf ('<li>%s', $r->cslug, $r->cname);
// display first snippet
printf ('<li>%s</li>', $r->cslug, $r->sname, $r->sname);
} else {
// category already processed, just display snippet
// display snippet
printf ('<li>%s</a>', $r->cslug, $r->sname, $r->sname);
}
}
// let's close the last open category (if any)
if ($lastcid)
printf ('</li></ul>');
Note that I used printf but you should use your own function instead which wraps around printf, but runs htmlspecialchars thru the parameters (except the first of course).
Disclaimer: I do not necessarily encourage such use of <ul>s.
This code is just here to show the basic idea of processing hierarchical data got with one query.
First off, you shouldn't query your database in your view. That would be mixing your business logic and your presentation logic. Just assign the query results to a variable in your controller and iterate through it.
As for the query, yup a join can do that in 1 query.
SELECT * -- Make sure you only select the fields you want. Might need to use aliases to avoid conflict
FROM snippets S LEFT JOIN categiries C ON S.category = C.id
WHERE live = 1
ORDER BY S.category, C.name
This will get you an initial result set. But this won't give you the data nicely ordered like you expect. You'll need to use a bit of PHP to group it into some arrays that you can use in your loops.
Something along the lines of
$categories = array();
foreach ($results as $result) {
$snippet = array();
//assign all the snippet related data into this var
if (isset($categories[$result['snippets.category']])) {
$categories[$result['snippets.category']]['snippet'][] = $snippet;
} else {
$category = array();
//assign all the category related data into this var;
$categories[$result['snippets.category']]['snippet'] = array($snippet);
$categories[$result['snippets.category']]['category'] = $category;
}
}
This should give you an array of categories which have all the related snippets in an array. You can simply loop through this array to reproduce your list.
I'd try this one:
SELECT
c.slug,c.name,s.name
FROM
categories c
LEFT JOIN snippets s
ON s.category = c.id
WHERE live=1 ORDER BY c.name, s.name
I didnt test it, though. Also check the indexes using the EXPLAIN statement so MySQL doesnt do a full scan of the table.
With these results, you can loop the results in PHP and check when the category name changes, and build your output as you wish.
Besides a single combined query you can use two separate ones.
You have a basic tree-structure here with branch elements (categories table) and leaf elements (snippets table). The shortcoming of the single-query solution is that you get owner brach-element repeatedly for every single leaf element. This is redundant information and depending on the number of leafs and the amount of information you query from each branch element can produce large amount of additional traffic.
The two-query solution looks like:
$navQuery = $mysqli->query ("SELECT id, slug, name FROM categories WHERE live=1 ORDER BY name")
or die (mysqli_error ($mysqli));
$subNavQuery = $mysqli->query ("SELECT c.id AS cid, s.id, s.name FROM categories AS c LEFT JOIN snippets AS s ON s.category=c.id WHERE c.live=1 ORDER BY c.name, s.name")
or die (mysqli_error ($mysqli));
$sub = $subNavQuery->fetch_object (); // pre-reading one record
while ($nav = $navQuery->fetch_object ()) {
echo '<li>';
echo ''. $nav->name .'';
echo '<ul>';
while ($sub->cid == $nav->id) {
echo '<li>';
echo ''. $sub->name .'';
echo '</li>';
$sub = $subNavQuery->fetch_object ();
}
echo '</ul>';
}
It should print completely the same code as your example
$navQuery = $mysqli->query("SELECT t1.id AS cat_id,t1.slug,t1.name AS cat_name,t2.id,t2.name
FROM categories AS t1
LEFT JOIN snippets AS t2 ON t1.id = t2.category
WHERE t1.live=1
ORDER BY t1.name ASC, t2.name ASC") or die(mysqli_error($mysqli));
$current = false;
while($nav = $navQuery->fetch_object()) {
if ($current != $nav->cat_id) {
if ($current) echo '</ul>';
echo ''. $nav->cat_name .'<ul>';
$current = $nav->cat_id;
}
if ($nav->id) { //check for empty category
echo '<li>'. $nav->name .'</li>';
}
}
//last category
if ($current) echo '</ul>';