Get the records using left join - php

I try to get the records from opportunity that created manually, so it means it’s not created via Converted from Leads or other module.
I’m trying to do is to get the opportunity record that is not converted from leads.
Below, you will see my query using left join the leads to opportunity using
opportunity id from leads table and the opportunity id from Opportunity table.
But whenever I try to run this query it doesn’t show the records that created manually in the opportunity,
I just want to get the records that are not converted and created manually in the opportunities. May I know why it is not showing? Thanks guys.
$strQuery = " SELECT
*
FROM
leads l
LEFT JOIN
opportunities O
ON
l.opportunity_id = O.id
WHERE
l.deleted = '0'
AND
O.deleted = '0'
AND
l.converted = '0'
AND
DATE_FORMAT(O.date_created, '%y-%m-%d') = CURDATE()";
//
$hQuery = $db->query($strQuery);
//
while ( $arRow = $db->fetchByAssoc($hQuery) ){
// My logic
}

I just want to get the records that are not converted and created manually in the opportunities
You may need to reverse the table relationships, e.g.
SELECT *
FROM opportunities O
LEFT JOIN leads l ON O.id = l.opportunity_id
WHERE l.opportunity_id IS NULL
AND O.deleted = '0'
AND DATE_FORMAT(O.date_created, '%y-%m-%d') = CURDATE()
here there is no assocated "lead", just an "opportunity".

Related

Equivalent expression to MySql Left Join

I'm working on my website and I'm stuck on writing MySQL query which uses "LEFT JOIN" syntax. A simple example of my query is shown bellow:
SELECT p.surname, f.f_path as players_image
FROM player p LEFT JOIN file f ON p.id_image = f.id_file
The problem is that I'm actually using 8 different tables to get necessary data and I'm joining them after WHERE clause(I found it more easier to do that way):
SELECT p.surname, f.f_path as players_image
FROM player, file
WHERE p.id_image = f.id_file
Can I somehow modify the second queries WHERE clause to get the same result as the first query returns?
I know that Oracle DB uses syntax like WHERE p.id_image(+) = f.id_file to manage that. It tried that on MySQL data base but it gave me an error.
The original SQL query(table names are different):
SELECT sp.id_speletajs, sp.vards, sp.uzvards, ss.numurs, f.f_path as attels, k.id_komanda, p.nosaukums as pozicija
FROM speletajs sp, fails f, speletaja_statistika ss, cempionata_komanda ck, komanda k, cempionats c, sezona s, pozicija p
WHERE
sp.id_attels = f.id_fails
and sp.id_speletajs = ss.id_speletajs
and ss.id_cempionata_komanda = ck.id_cempionata_komanda
and ss.id_pozicija = p.id_pozicija
and ck.id_komanda = k.id_komanda
and ck.id_cempionats = c.id_cempionats
and c.id_sezona = s.id_sezona
and k.mana_komanda = true
and s.nosaukums = (select max(s1.nosaukums) from sezona s1)

Sanity check: Will this SQL query join how I want?

My deepest apologies for the query, that's legacy code for you. I basically want to check my code makes logical sense.
Essentially I want to return all rows of the "signatures" table where the "claim_id" = the "claim_id" on the "claims" table.
From that, I intend to check if the "signature_id" = null for each claim. If it does, that claim has no related signature, correct?
$SQL="
SELECT
`claims`.`claim_id`,
CONCAT(`insurers`.`insurer_name`,IF((`insurers`.`insurer_branch`<>''),CONCAT(' - ',`insurers`.`insurer_branch`),'')) as 'insurer',
`claims`.`claim_number` as 'claim_number',
UNIX_TIMESTAMP(claims.overflow_date) as 'overflow_date',
UNIX_TIMESTAMP(claims.reassigned_date) as 'reassigned_date',
UNIX_TIMESTAMP(claims.reassigned_from_fr_date) as 'reassigned_from_fr_date',
UNIX_TIMESTAMP(claims.date_of_first_contact) as 'date_of_first_contact',
UNIX_TIMESTAMP(`claims`.`date_surveyor_made_contact`) as 'date_surveyor_made_contact',
UNIX_TIMESTAMP(`claims`.`date_of_inspection`) as 'date_of_inspection',
UNIX_TIMESTAMP(`claims`.`surveyor_completed`) as 'surveyor_completed',
UNIX_TIMESTAMP( CASE 1 WHEN (claims.overflow_date>0) THEN claims.overflow_date WHEN (claims.reassigned_date>0) THEN claims.reassigned_date WHEN (claims.reassigned_from_fr_date>0) THEN claims.reassigned_from_fr_date ELSE claims.date_of_first_contact END ) as 'date_of_first_contact_debug',
`claims`.`date_surveyor_made_contact` as 'date_surveyor_made_contact_debug',
`claims`.`date_of_inspection` as 'date_of_inspection_debug',
`claims`.`surveyor_completed` as 'surveyor_completed_debug',
`claims`.`letter_of_findings`,
`claims`.`int_settlement_reason`,
`claims`.`ext_settlement_reason`,
`claims`.`original_surveyor_id`,
`claims`.`surveyor_id`,
`claims`.`broker_name`,
`insurers`.`insurer_type`,
`insurers`.`insurer_id`,
`signatures`.`signature_id`,
`signatures`.`claim_id`
FROM
(((`claims` claims INNER JOIN `insurers` insurers ON claims.`insurer_id` = insurers.`insurer_id`)
INNER JOIN `users` users ON claims.surveyor_id = users.user_id)
LEFT JOIN `signatures` signatures on claims.claim_id = signatures.claim_id)
WHERE
(`claims`.`claim_type` <> ".$conn->qstr(TYPE_DESKTOP).") AND
(`claims`.`claim_type` <> ".$conn->qstr(TYPE_AUDIT).") AND
(`claims`.`insurer_id` NOT IN ('".implode("','",$arrSURGE)."')) AND
(`users`.`status` = ".$conn->qstr(STATUS_LIVE).") AND
(`claims`.`claim_cancelled_id` = 0) AND
$where
";
The code I've added is both the signatures. selectors, and the LEFT JOIN 'signatures' signatures on claims.claim_id = signatures.claim_id) line.
claim_id is PK on the claims table, and signature_id is PK on signatures table.
Thanks!
The null check will only shows items with signatures. If you leave the null check out of the picture, you will get nulls for items where signature is not present.
check this

JOIN Query while loading comments

I'm loading comments for product with id = '3'
$get_comments = mysql_query("SELECT * FROM products_comments WHERE product_id = '3'");
Now I want to add the "report abuse" option for each comment, for this purpose I'm having another table as "abuse_reports" which user abuse reports will be stored in this table, now if a user reported a comment, the report abuse option should not be there for that comment for that user there anymore, for this I'm doing:
while($row = mysql_fetch_array($get_comments)){
echo blah blah blah // comment details
// now for checking if this user should be able to report this or not, i make this query again:
$check_report_status = mysql_query("SELECT COUNT(id) FROM abuse_reports WHERE reporter_user_id = '$this_user_id' AND product_id = 'this_product_id'");
// blah blah count the abuse reports which the current user made for this product
if($count == 0) echo "<a>report abuse</a>";
}
With the above code, for each comment I'm making a new query, and that's obviously wrong, how I should join the second query with the first one?
Thanks
Updated query (that is working now, commited by questioner)
SELECT pc. * , count( ar.`id` ) AS `abuse_count`
FROM `products_comments` pc
LEFT OUTER JOIN `abuse_reports` ar ON pc.`id` = ar.`section_details`
AND ar.`reporter_id` = '$user_id'
WHERE pc.`product_id` = '$product_id'
GROUP BY pc.`id`
LIMIT 0 , 30
The query works as follow: You select all the fields of your products_comments with the given product_id but you also count the entries of abuse_reports for the given product_id. Now you LEFT JOIN the abuse_reports, which means that you access that table and hang it on to the left (your products_comments table). The OUTER allows that there is no need for a value in the abuse_reports table, so if there is no report you get null, and therefore a count of 0.
Please read this:
However, I needed to group the results, otherwise you get only one merged row as result. So please extend your products_comments with a field comment_id of type int that is the primary key and has auto_increment.
UPDATE: abuse count
Now you can do two things: By looping through the results, you can see for each single element if it has been reported by that user or not (that way you can hide abuse report links for example). If you want the overall number of reports, you just increase a counter variable which you declare outside the loop. Like this:
$abuse_counter = 0;
while($row = mysql....)
{
$abuse_counter += intval($row['abuse_count']); // this is 1 or 0
// do whatever else with that result row
}
echo 'The amount of reports: '.$abuse_counter;
Just a primitive sample
I believe your looking for a query something like this.
SELECT pc.*, COUNT(ar.*)
FROM products_comments AS pc
LEFT JOIN abuse_reports AS ar ON reporter_user_id = pc.user_id AND ar.product_id = pc.product_id
WHERE product_id = '3'"
try this SQL
SELECT pc.*, COUNT(ar.id) AS abuse_count
FROM products_comments pc
LEFT JOIN abuse_reports ar ON pc.product_id = ar.product_id
WHERE pc.product_id = '3' AND ar.reporter_user_id = '$this_user_id'
GROUP BY pc.product_id
The result is list of products_comments with abuse_reports count if exist for reporter_user_id

More efficient way to do SQL queries

I've been using the below php and sql for loading schedule information and real time information for passenger trains in the UK. Essentially you have to find the relevant schedules, and then load the realtime information for each schedule which is in a different table relating to todays trains.
The query is taking a little longer than is really idea and using lots of CPU% which again isn''t ideal. I'm pretty weak when it comes to sql programming so any pointers as to what is inefficient would be great.
This is for an android app and so i've tried to all with one call over http. The prints(*) and > is for splitting the string at the other end.
Here is the code:
<?
//Connect to the database
mysql_connect("localhost","XXXX","XXXX")
or die ("No connection could be made to the OpenRail Database");
mysql_select_db("autotrain");
//Set todays date from system and get HTTP parameters for the station,time to find trains and todays locations table.
$date = date('Y-m-d');
$test = $_GET['station'];
$time = $_GET['time'];
$table = $_GET['table'];
//Find the tiploc associated with the station being searched.
$tiplocQuery = "SELECT tiploc_code FROM allstations WHERE c LIKE '$test';";
$tiplocResult =mysql_query($tiplocQuery);
$tiplocRow = mysql_fetch_assoc($tiplocResult);
$tiploc=$tiplocRow['tiploc_code'];
//Now find the timetabled trains for the station where there exists no departure information. Goes back two hours to account for any late running.
$timeTableQuery = "SELECT tiplocs.tps_description AS 'C', locations$table.public_departure, locations$table.id,schedules.stp_indicator
,schedules.train_uid
FROM locations$table, tiplocs, schedules_cache, schedules,activations
WHERE locations$table.id = schedules_cache.id
AND schedules_cache.id = schedules.id
AND schedules.id =activations.id
AND '$date'
BETWEEN schedules.date_from
AND schedules.date_to
AND locations$table.tiploc_code = '$tiploc'
AND locations$table.real_departure LIKE '0'
AND locations$table.public_departure NOT LIKE '0'
AND locations$table.public_departure >='$time'-300
AND locations$table.public_departure <='$time'+300
AND schedules.runs_th LIKE '1'
AND schedules_cache.destination = tiplocs.tiploc
ORDER BY locations$table.public_departure ASC
LIMIT 0,30;";
$timeTableResult=mysql_query($timeTableQuery);
while($timeTablerow = mysql_fetch_assoc($timeTableResult)){
$output[] = $timeTablerow;
}
//Now for each id returned in the timetable, get the locations and departure times so the app may calculate expected arrival times.
foreach ($output as $value) {
$id = $value['id'];
$realTimeQuery ="SELECT locations$table.id,locations$table.location_order,locations$table.arrival,locations$table.public_arrival,
locations$table.real_arrival,locations$table.pass,locations$table.departure,locations$ table.public_departure,locations$table.real_departure,locations$table.location_cancelled,
tiplocs.tps_description FROM locations$table,tiplocs WHERE id =$id AND locations$table.tiploc_code=tiplocs.tiploc;";
$realTimeResult =mysql_query($realTimeQuery);
while($row3 = mysql_fetch_assoc($realTimeResult)){
$output3[] = $row3;
}
print json_encode($output3);
print("*");
unset($output3);
unset($id);
}
print('>');
print json_encode($output);
?>
Many Thanks
Matt
The biggest issue with your setup is this foreach loop because it is unnecessary and results in n number of round trips to the database to execute a query, fetch and analyze the results.
foreach ($output as $value) {
Rewrite the initial query to include all of the fields you will need to do your later calculations.
Something like this would work.
SELECT tl.tps_description AS 'C', lc.public_departure, lc.id, s.stp_indicator, s.train_uid,
lc.id, lc.location_order, lc.arrival, lc.public_arrival, lc.real_arrival, lc.pass, lc.departure, lc.real_departure, lc.location_cancelled
FROM locations$table lc INNER JOIN schedules_cache sc ON lc.id = sc.id
INNER JOIN schedules s ON s.id = sc.id
INNER JOIN activations a ON s.id = a.id
INNER JOIN tiplocs tl ON sc.destination = tl.tiploc
WHERE '$date' BETWEEN schedules.date_from AND schedules.date_to
AND lc.tiploc_code = '$tiploc'
AND lc.real_departure LIKE '0'
AND lc.public_departure NOT LIKE '0'
AND lc.public_departure >='$time'-300
AND lc.public_departure <='$time'+300
AND s.runs_th LIKE '1'
ORDER BY lc.public_departure ASC
LIMIT 0,30;
Eliminating n query executions from your page load should dramatically increase response time.
Ignoring the problems with the code, in order to speed up your query, use the EXPLAIN command to evaluate where you need to add indexes to your query.
At a guess, you probably will want to create an index on whatever locations$table.public_departure evaluates to.
http://dev.mysql.com/doc/refman/5.0/en/using-explain.html
A few things I noticed.
First, you are joining tables in the where clause, like this
from table1, table2
where table1.something - table2.something
Joining in the from clause is faster
from table1 join table2 on table1.something - table2.something
Next, I'm not a php programmer, but it looks like you are running similar queries inside a loop. If that's true, look for a way to run just one query.
Edit starts here
This is in response to gazarsgo's that I back up by claim about joins in the where clause being faster. He is right, I was wrong. This is what I did. The programming language is ColdFusion:
<cfsetting showdebugoutput="no">
<cfscript>
fromtimes = ArrayNew(1);
wheretimes = ArrayNew(1);
</cfscript>
<cfloop from="1" to="1000" index="idx">
<cfquery datasource="burns" name="fromclause" result="fromresult">
select count(distinct hscnumber)
from burns_patient p join burns_case c on p.patientid = c.patientid
</cfquery>
<cfset ArrayAppend(fromtimes, fromresult.executiontime)>
<cfquery datasource="burns" name="whereclause" result="whereresult">
select count(distinct hscnumber)
from burns_patient p, burns_case c
where p.patientid = c.patientid
</cfquery>
<cfset ArrayAppend(wheretimes, whereresult.executiontime)>
</cfloop>
<cfdump var="#ArrayAvg(fromtimes)#" metainfo="no" label="from">
<cfdump var="#ArrayAvg(wheretimes)#" metainfo="no" label="where">
I did ran it 5 times. The results, in milliseconds, follow.
9.563 9.611
9.498 9.584
9.625 9.548
9.831 9.769
9.792 9.813
The first number represents joining in the from clause, the second joining in the where clause. The first number is lower only 60% of the time. Had it been lower 100% percent of the time, it would have shown that joining in the from clause is faster, but that' not the case.

mysql join based on $get value

I have 2 tables.
contacts and complaints.
contacts has 3 columns:
contact_id, contact_name, score
complaints has 4 columns:
complaint_id, contact_id, score_deduction, complaint_type
I am able to obtain value $_GET['complaint_id'] from previous page.
What i am trying to do is delete the record with that particular complaint_id and get the value of complaints.score_deduction and add it back to contacts.score.
I have spent hours and cant seem to figure it out.
Please help.
if (isset($_GET['complaint_id'])) {
record_set('complaints',"SELECT * FROM add_complaints WHERE complaint_id = ".$_GET['complaint_id']."");
$contact_id = $row_complaints['contact_id'];
record_set('contact',"SELECT * FROM contacts WHERE contact_id = $contact_id");
$score = $row_contact['contact_score'];
echo $score;
}
You can just combine that into a single query.
SELECT * FROM add_complaints AS ac
INNER JOIN contacts AS c on ac.contact_id = c.contact_id
WHERE ac.complaint_id = ?
I am not familiar with whatever you are using to make the DB queries. But I assume you would know how to get the contact id, current score, and score deduction values. And make the update query and delete queries from there.
IF you wanted to get more fancy and just update the contact record in place without needing to select anything you could also do:
UPDATE add_complaints AS ac
INNER JOIN contacts AS c on ac.contact_id = c.contact_id
SET c.score = c.score - ac.score_deduction
WHERE ac.complaint_id = ?
Then just delete the complaint
DELETE FROM add_complaints WHERE complaint_id = ?

Categories