How to fix slow query performance using NOT EXISTS MySQL? CodeIgniter - php

I am trying to optimize / speed up the performance the loading of my data, is there a way to fix this?
I have 3 tables involved:
tbl_tt_college_studentpersonalinfo - This table displays the name of students, it is join in my query
tbl_tt_college_preenrollment - This table displays the pending status of pre-enrolled students
tbl_tt_college_enlistment - This table will check the existing record the student has.
Here is my Query: - The problem that I am having is the load of data is slow, it may take 30-50 seconds. Is there a way to improve this or make it like a join query?
public function get_enlists()
{
$this->db->join('tbl_tt_college_studentpersonalinfo','tbl_tt_college_preenrollment.studentID = tbl_tt_college_studentpersonalinfo.studentID');
$this->db->where('tbl_tt_college_preenrollment.departmentID', $this->input->post('course'));
$this->db->where('tbl_tt_college_preenrollment.yearLevel', $this->input->post('yearLevel'));
$this->db->where("NOT EXISTS (SELECT tbl_tt_college_enlistment.studentKeyID FROM tbl_tt_college_enlistment WHERE tbl_tt_college_enlistment.studentKeyID = tbl_tt_college_preenrollment.studentKeyID AND schoolYear = '" . $this->session->userdata('currentAcademicYear') . '-' . ($this->session->userdata('currentAcademicYear') + 1) . "' AND semester = '" . $this->session->userdata('currentSemester') . "')");
$query = $this->db->get('tbl_tt_college_preenrollment');
return $query->result_array();
}
Here is the raw query for the reference:
NOT EXISTS (
SELECT studentKeyID FROM tbl_tt_college_enlistment
WHERE tbl_tt_college_studentpersonalinfo.studentKeyID = tbl_tt_college_enlistment.studentKeyID
AND schoolYear = '" . $this->session->userdata('currentAcademicYear') . '-' . ($this->session->userdata('currentAcademicYear') + 1) . "'
AND semester = '" . $this->session->userdata('currentSemester') . "'
)

See if this composite index on tbl_tt_college_enlistment helps:
INDEX(schoolYear, semester, studentKeyID)
If not adequate, please provide SHOW CREATE TABLE and EXPLAIN SELECT ...

Related

How do I stop duplicate rows on table join in SQL?

Trying to join this table, so that i can change the code if the tutor ID matches the session tutor ID. But it shows multiple results in the calendar that its generating.
Below is the current PHP code, although the entries are being duplicated due to having multiple tutor ID's within the table. i'm not sure how to change this.
<?php
$sqlAssignments = "SELECT * FROM tbl_assignments LEFT JOIN tbl_tutorModules ON tbl_assignments.module_code = tbl_tutorModules.module_code"; //
$qryAssignments = mysqli_query($con, $sqlAssignments); // running the query
while($rowAssignment = mysqli_fetch_assoc($qryAssignments)){
if ($_SESSION["ID"] == $rowAssignment['tutor_id']) {
echo "{ title: '" . $rowAssignment['assignment_name'] . "', start: '" . $rowAssignment['hand_in_date'] . "', end: '" . $rowAssignment['hand_in_date'] . "', url: 'view/assignments.php?id=" . $rowAssignment['assignment_id'] . "', color: '#f1f1f1'},";
} else {
echo "{ title: '" . $rowAssignment['assignment_name'] . "', start: '" . $rowAssignment['hand_in_date'] . "', end: '" . $rowAssignment['hand_in_date'] . "', url: 'view/assignments.php?id=" . $rowAssignment['assignment_id'] . "'},";
}
}
?>
The actual results at the moment is that when the tutorModules has multiple tutors, the output duplicates calendar results.
Thanks
Edit: Tables look like this with some example data
tbl_tutorModules
con_id module_code tutor_id
2 ISYS30025 1
3 ISYS30025 2
tbl_assignments
assignment_id
module_code
assignment_name
assignment_weight
set_date
hand_in_date
hand_in_method
assignment_type
This is the current output
The expected output is for these not to be duplicated.
You want to know whether a certain tutor is involved in an assignment. So pass the tutor ID to the DBMS in order to let it find out in a query.
SELECT
assignment_id, assignment_name, hand_in_date,
case when module_code in (SELECT module_code FROM tbl_tutorModules WHERE tutor_id = ?)
then 'yes' else 'no'
end as tutor_involved
FROM tbl_assignments
ORDER BY assignment_id;
As you can see, I don't join the tables, because I'm not interested in the joined result. I merely want to look up a record in tbl_tutorModules. We use IN or EXISTS in SQL to look up records in another table.
See here how to pass parameters to the DBMS in mysqli: http://php.net/manual/en/mysqli.prepare.php

Mysql Random Row Query on Inner Join

I have a query and i want random result on advertisement table. Advertise table have own id but when i use RAND(advertise.id) it won't work and i don't know how it will. I am using laravel framework so if possible i can use PHP also to show random advertise result. Here is code can anyone tell me where i use RAND() Mysql function.
SELECT providers.id,
adv__managements.id AS 'adv_id',
adv__managements.images,
adv__managements.categories,
adv__managements.subcategories,
adv__managements.title,
adv__managements.description,
adv__managements.role,
adv__managements.plan_id,
userinformation.user_id,
userinformation.zip_code,
plans.active
FROM userinformation INNER JOIN providers ON userinformation.user_id = providers.user_id
INNER JOIN adv__managements ON adv__managements.range = providers.range
INNER JOIN plans ON plans.user_id = userinformation.user_id
where GetDistance('km'," . doubleval($info->lat) . ", " . doubleval($info->lon) .", " . doubleval(\Auth::user()->userinfo->latitude) . ", " . doubleval(\Auth::user()->userinfo->longitude) . ") < providers.range AND plans.active = 1 LIMIT 3
And can anyone tell how to convert this query into laravel ?

cannot retrieve data from 2 tables getting no result

I have 2 tables:
competition_winners where I am storing people who won competition and table competition where I am storing info about actual competition.
So I am retrieving winners and competition's end date. But the query responsible for date doesn't return anything. I am using Opencart so performing query in model. Here is its code.
public function getWinnersByDate($date) {
$qr = "SELECT competition_id FROM " . DB_PREFIX . "competition_winners";
//$fcid = $qr->row['competition_id'];
$query = "SELECT cometition_id,end_date FROM " . DB_PREFIX . "competition WHERE competition_id = '" .$qr->row['competition_id'] . "'";
return $query->row;
Query works fine in PhpMyadmin. What am I missing or doing wrong?
Instead of running this in two queries You should be using JOIN (search about SQL JOIN on google).
public function getWinnersByDate($date) {
$qr = $this->db->query("
SELECT cw.competition_id, c.end_date
FROM " . DB_PREFIX . "competition_winners cw
LEFT JOIN " . DB_PREFIX . "competition c ON c.competition_id = cw.competition_id
");
return $query->rows;
}
I do not know Your DB structure, but the query above has no sense in it's current state - I believe You want to add some WHERE clause using the provided $date argument and that You want to select more information from competition_winners table, so please, either do it Yourself or provide us with more details on Your problem.

MySQL Counting Results Within a Range and First Occurance In Any Range

Looking for some advice on the best way to accomplish this. I've tried Unions, Joins, and Alias examples from a few Stack Overflow questions - none seems to get me where I want to go to no fault of theirs. I think I've just been looking to solve this the wrong way.
I've got one table that logs all activity from our users. Each log contains a column with an ID and another with a TIMESTAMP. There is no column that states what the event type is.
What I'm looking to do is grab counts within a range and append a virtual column with the activation date (first access) regardless if it is in the range or not. The business case for this is that I'd like to have reports that show users active within a range, their activation date, and the amount of events in the range.
The HTML output of this would look like this:
User / Total Visits in the Range / First Visit (in the range or not) / Most Recent Visit (in the range)
How I've gotten this far is by doing this:
$result = mysql_query("
SELECT user, MIN(timestamp), MAX(timestamp), count(user)
AS tagCount FROM " . $table . "
WHERE date(timestamp) BETWEEN '" . $startdate . "' AND '" . $enddate . "'
GROUP BY user
ORDER BY " . $orderby . " " . $order) or die(mysql_error());
I then loop:
$i = 1;
while($row = mysql_fetch_array($result)){
$user_name = str_replace("www.", "", $row['user']); // removing www from usernames
if( $i % 2 != 0) // used for alternating row colors
$iclass = "row";
else
$iclass = "row-bg";
echo "<div class=\"" . $iclass . "\"><div class=\"number\">" . $i . "</div><div class=\"number\">" . $row['tagCount'] . "</div><div class=\"name\">" . "" . $server_name . "" . "</div>" . "<div class=\"first\">" . $row['MIN(timestamp)'] . "</div><div class=\"recent\">" . $row['MAX(timestamp)'] . "</div></div>";
$i++;
}
The MIN(timestamp) in the above grabs the first timestamp in the range - I want to grab the first timestamp regardless of range.
How can I do this?
The key is to create a virtual derived table that calculates their first access separately and then join to it from your query that returns records for the time period you specify.
The below is SQL Server code, but I think it's fine in mysql too. If not, let me know and i'll edit the syntax. The concept is sound either way though.
Just setup code for the sample
if object_id('tempdb..#eventlog') is not null
drop table #eventlog
create table #eventlog
(
userid int ,
eventtimestamp datetime
)
insert #eventlog
select 1,'2011-02-15'
UNION
select 1,'2011-02-16'
UNION
select 1,'2011-02-17'
UNION
select 2,'2011-04-18'
UNION
select 2,'2011-04-20'
UNION
select 2,'2011-04-21'
declare #StartDate datetime
declare #EndDate datetime
set #StartDate = '02-16-2011'
set #EndDate = '05-16-2011'
Here's the code that would solve your problem, you can replace #eventlog with your tablename
select e.userid,
min(eventtimestamp)as FirstVisitInRange,
max(eventtimestamp) as MostRecentVisitInRange,
min(e2.FirstAccess) as FirstAccessEver,
count(e.userid) as EventCountInRange
from #eventlog e
inner join
(select userid,min(eventtimestamp) as FirstAccess
from #eventlog
group by userid
) e2 on e.userid = e2.userid
where
e.eventtimestamp between #StartDate and #EndDate
group by e.userid

MySQL/PHP Eliminating duplicate, non-identical, returns from a MySQL self-join

I have a small database, holding the details of just under 400 ponies. I wish to query that table and return a table showing the pertinant details of each pony, and it's owner's and breeder's names. The data is held primarily like so:
profiles - a table holding all info assigned to each individual pony, including it's sire's and dam's reg numbers, and it's owner's and breeder's DB assigned id's.
contacts - a table for the people's info. Joined as 'owner' and again as 'breeder' in the query below.
prm_* - multiple parameter tables, holding broad details such as colour, breed, etc.
Where I am running into trouble is when trying my first self join: querying the profiles table three times in order to retrieve the names of the sire and dam for each profile, as well as the pony's own name to begin with. When I run the query, it returns duplicate rows for many (not all) profiles. Using DISTINCT eliminated most of these, but the issue remains with the non-identical results, particularly for those ponies where no sire or dam is on record.
I have googled the problem, and it does appear here and there, but I cant quite grasp what happening in the solutions given. I'm not even certain why the problem occurs at all. Can someone please step me through the issue and the solving of it? I'd be most grateful.
My query as it stands (returns 408 results, from only 387 ponies!):
include 'conn.php';
?>
<table class="admin-display">
<thead><tr><th>No:</th><th>Name:</th><th>Sire:</th><th>Dam:</th><th>Age:</th><th>Colour:</th><th>Gender:</th><th>Owner:</th><th>Breeder:</th></tr></thead>
<?php
$i=1;
$sql = mysql_query("SELECT DISTINCT p.ProfileID, p.ProfileOwnerID, p.ProfileBreederID, p.ProfilePrefix, p.ProfileSireReg, p.ProfileDamReg,
p.ProfileGenderID, p.ProfileAdultColourID, p.ProfileColourModifierID, p.ProfileYearOfBirth,
p.ProfileYearOfDeath, p.ProfileLocalRegNumber, p.ProfileName,
sire.ProfileName AS sireName, sire.ProfilePrefix AS sirePrefix,
dam.ProfileName AS damName, dam.ProfilePrefix AS damPrefix,
owner.ContactFirstName AS owner_fname, owner.ContactLastName AS owner_lname,
breeder.ContactFirstName AS breeder_fname, breeder.ContactLastName AS breeder_lname,
BreedGender, BreedColour, BreedColourModifier
FROM profiles AS p
LEFT JOIN profiles AS sire
ON p.ProfileSireReg = sire.ProfileLocalRegNumber
LEFT JOIN profiles AS dam
ON p.ProfileDamReg = dam.ProfileLocalRegNumber
LEFT JOIN contacts AS owner
ON p.ProfileOwnerID = owner.ContactID
LEFT JOIN contacts AS breeder
ON p.ProfileBreederID = breeder.ContactID
LEFT JOIN prm_breedgender
ON p.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN prm_breedcolour
ON p.ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON p.ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
WHERE p.ProfileName != 'Unknown'
ORDER BY p.ProfileID ASC");
while($row = mysql_fetch_array($sql)) {
$id = $row['ProfileID'];
$name = $row['ProfilePrefix'] . ' ' . $row['ProfileName'];
if ($row['ProfileYearOfDeath'] > 0000) { $age = ($row['ProfileYearOfDeath'] - $row['ProfileYearOfBirth']); }
elseif ($row['ProfileYearOfDeath'] <= 0000) { $age = (date('Y') - $row['ProfileYearOfBirth']); }
$reg = $row['ProfileLocalRegNumber'];
$sire = $row['sirePrefix'] . ' ' . $row['sireName'];
$dam = $row['damPrefix'] . ' ' . $row['damName'];
$colour = $row['BreedColour'];
$gender = $row['BreedGender'];
$owner = $row['owner_fname'] . ' ' . $row['owner_lname'];
$breeder = $row['breeder_fname'] . ' ' . $row['breeder_lname'];
echo '<tr><td>' . $i++ . '</td><td>' . $name . '</td><td>' . $sire . '</td>';
echo '<td>' . $dam . '</td><td>' . $age . '</td><td>' . $colour . '</td><td>' . $gender. '</td>';
echo '<td>' . $owner . '</td><td>' . $breeder. '</td></tr>';
}
echo '</table>';
mysql_close($con);
Use GROUP BY over DISTINCT:
http://msmvps.com/blogs/robfarley/archive/2007/03/24/group-by-v-distinct-group-by-wins.aspx
The problem is going to be in the data - one of the tables that you're joining against has multiple rows on associated to the join key.
I recommend executing the query in stages. Start with the base query (taking out the field list):
SELECT count(*)
FROM profiles AS p
WHERE p.ProfileName != 'Unknown'
And then add the join tables in one at a time until you see the count increase...
SELECT count(*)
FROM profiles AS p
LEFT JOIN profiles AS sire
ON p.ProfileSireReg = sire.ProfileLocalRegNumber
WHERE p.ProfileName != 'Unknown'
You should then be able to see where the duplicate is. If you want to easily see which record is duplicated, you can run this query:
SELECT p.Profile_id, count(*) cnt
FROM profiles AS p
LEFT JOIN profiles AS sire
ON p.ProfileSireReg = sire.ProfileLocalRegNumber
-- (all other joins)
WHERE p.ProfileName != 'Unknown'
GROUP BY p.Profile_id
HAVING count(*) > 1
Then you can look at the details of the duplicated records.

Categories