Codeigniter query generating multiple rows - php

Codeigniter:
public function get_customers(){
$this->db->select('*,customer.ID as ID,customer.Create_date as Create_date,transport.Name as Transporter, state.Name as State, city.Name as City, area.Name as Area, shipping_state.Name as Shipping_state, shipping_city.Name as Shipping_city, shipping_area.Name as Shipping_area');
$this->db->from('customer');
$this->db->join('transport','transport.ID = customer.Transporter','LEFT');
$this->db->join('state','state.ID = customer.State','LEFT');
$this->db->join('state as shipping_state','state.ID = customer.Shipping_state','LEFT');
$this->db->join('city','city.ID = customer.City','LEFT');
$this->db->join('city as shipping_city','city.ID = customer.Shipping_city','LEFT');
$this->db->join('area','area.ID = customer.Area','LEFT');
$this->db->join('area as shipping_area','area.ID = customer.Shipping_area','LEFT');
return $this->db->get()->result_array();
}
In customer table, there are 2 columns joining to the same table. in the customer table, there are only 1 rows. but when the query is generating it generating 1000+ rows. Anyone can please help me why it generating 1000+ rows and How can I resolve it.

You can always use $this->db->last_query() to visually understand and debug your code. It's good to do this, as you then you can start to understand how Active Record works.
$results = $this->db->get()->result_array();
log_message( "debug", "get_customers sql: ". $this->db->last_query() );
return $results;
So when you see your query in raw format; it looks like this:
SELECT
*,customer.ID as ID,
customer.Create_date as Create_date,
transport.Name as Transporter,
state.Name as State,
city.Name as City,
area.Name as Area,
shipping_state.Name as Shipping_state,
shipping_city.Name as Shipping_city,
shipping_area.Name as Shipping_area
FROM
customer
LEFT JOIN transport ON (
transport.ID = customer.Transporter
)
LEFT JOIN state ON (
state.ID = customer.State
)
LEFT JOIN state as shipping_state ON (
state.ID = customer.Shipping_state
)
LEFT JOIN city as shipping_state ON (
city.ID = customer.City
)
LEFT JOIN city as shipping_city ON (
city.ID = customer.Shipping_city
)
LEFT JOIN area ON (
area.ID = customer.Area
)
LEFT JOIN area as shipping_area ON (
area.ID = customer.Shipping_area
)
There's so many left joins here; that it will repeat any matched rows on each left join. It's hard to say without knowing the data, but it would appear that you would prefer to use a Hard Join.

With the amount of joins you have you might have to add a group by
so before your get add:
$this->db->group_by('customer.ID');

Related

Show rows with highest number, even if it's the same

I'm using the following SQL
SELECT
testjob.id AS id,
testjob.EndTime AS Date,
testsuitecollectionname,
testsuitecollection,
TestSuiteName,
TestSuite
FROM
Testreportingdebug.testjob
LEFT JOIN
testsuitecollection ON testsuitecollection.id = testjob.testsuitecollectionid
LEFT JOIN
testsuitecollectionlink ON testsuitecollection.id = testsuitecollectionlink.testsuitecollection
LEFT JOIN
testsuite ON testsuite.id = testsuitecollectionlink.testsuite
WHERE
testjob.Engine = 'SeqZap'
AND TestSuiteName IN (
'AlertManagement')
AND testjob.EndTime IN ('2020-05-18 05:18:58','7305', '2020-03-18 04:57:31', 'gin_mixit_simulated', '34', 'AlertManagement', '987'
, '2020-05-17 16:39:03', '2020-03-03 18:07:28', '2020-05-18 16:07:44')
AND testjob.id IN ('13382', '13372', '5921', '13391', '7305')
ORDER BY TestSuiteName;
and I get the following
Rows from table
Is it possible to filter this table so I get only the rows marked here:
Wanted rows
NOTE: I can have multiple TestSuiteNames, and they have to always with the highest date, and show all rows for it.
Could it be possible to use MAX(testjob.EndTime), and then if there is more than one Max date for that specific TestSuiteName, then it shows them, instead not showing?
SELECT
testjob.id AS id,
testjob.EndTime AS Date,
testsuitecollectionname,
testsuitecollection,
TestSuiteName,
TestSuite
FROM
Testreportingdebug.testjob
LEFT JOIN
testsuitecollection ON testsuitecollection.id = testjob.testsuitecollectionid
LEFT JOIN
testsuitecollectionlink ON testsuitecollection.id = testsuitecollectionlink.testsuitecollection
LEFT JOIN
testsuite ON testsuite.id = testsuitecollectionlink.testsuite
WHERE
testjob.Engine = 'SeqZap'
AND TestSuiteName IN (
'AlertManagement')
AND testjob.EndTime IN ('2020-05-18 05:18:58','7305', '2020-03-18 04:57:31', 'gin_mixit_simulated', '34', 'AlertManagement', '987'
, '2020-05-17 16:39:03', '2020-03-03 18:07:28', '2020-05-18 16:07:44')
AND testjob.id IN ('13382', '13372', '5921', '13391', '7305')
AND testsuitecollectionname = 'ceops1_pwm64_circ1'
ORDER BY TestSuiteName;
How about that?
Added (one line above Order by):
AND testsuitecollectionname = 'ceops1_pwm64_circ1'

MySql query duplicating results (with certain parameters)

I have a fairly complex query (to me) that returns duplicate results ONLY when the parameter passed results in 'dest_xdock: ' . $row['dest_xdock'] as a certain value. Can anyone identify why this is happening in the Query? I don't have duplicates of this in the table that I can see. Here is the query:
select
`orig_lookup`.`zipcode` AS `orig_zipcode`,
`orig_lookup`.`state` AS `orig_state`,
`orig_lookup`.`svcnotes` AS `orig_svcnotes`,
`orig_lookup`.`svcterms` AS `orig_svcterms`,
`orig_lookup`.`daysout` AS `orig_daysout`,
`orig_lookup`.`daysin` AS `orig_daysin`,
`orig_lookup`.`pcity` AS `orig_city`,
`orig_lookup`.`scac` AS `orig_scac`,
`orig_lookup`.`xdock` AS `orig_xdock`,
`orig_lookup`.`scac2` AS `orig_scac2`,
`orig_lookup`.`xdock2` AS `orig_xdock2`,
`orig_lookup`.`scac3` AS `orig_scac3`,
`orig_lookup`.`xdock3` AS `orig_xdock3`,
`orig_ssas`.`ssa` AS `orig_ssa`,
`orig_hcas`.`hca` AS `orig_hca`,
`dest_lookup`.`zipcode` AS `dest_zipcode`,
`dest_lookup`.`state` AS `dest_state`,
`dest_lookup`.`svcnotes` AS `dest_svcnotes`,
`dest_lookup`.`svcterms` AS `dest_svcterms`,
`dest_lookup`.`daysout` AS `dest_daysout`,
`dest_lookup`.`daysin` AS `dest_daysin`,
`dest_lookup`.`pcity` AS `dest_city`,
`dest_lookup`.`scac` AS `dest_scac`,
`dest_lookup`.`xdock` AS `dest_xdock`,
`dest_lookup`.`scac2` AS `dest_scac2`,
`dest_lookup`.`xdock2` AS `dest_xdock2`,
`dest_lookup`.`scac3` AS `dest_scac3`,
`dest_lookup`.`xdock3` AS `dest_xdock3`,
`dest_ssas`.`ssa` AS `dest_ssa`,
`dest_hcas`.`hca` AS `dest_hca`,
`tbl_matx_20160321`.`trmnljoin` AS `TrmnlMatx`,
`tbl_matx_20160321`.`trmnlsvcdays` AS `TrmnlSvcDays`,
`tbl_matx_20160321`.`trmnltranspts` AS `TrmnlTransPts`,
IF(ISNULL(`orig_lookup`.`daysin`+ `dest_lookup`.`daysout`+ `tbl_matx_20160321`.`trmnlsvcdays`), 'No Service',(`orig_lookup`.`daysin`+ `dest_lookup`.`daysout`+ `tbl_matx_20160321`.`trmnlsvcdays`)) AS `TotalSvcDays`
FROM ((`tbl_uscomp_20160321` AS `orig_lookup` LEFT JOIN `tbl_hcas_20160321` AS `orig_hcas` ON `orig_lookup`.`zipcode` = `orig_hcas`.`zipcode` LEFT JOIN `tbl_ssas_20160321` AS `orig_ssas` ON `orig_lookup`.`zipcode` = `orig_ssas`.`zipcode`)
INNER JOIN (`tbl_uscomp_20160321` AS `dest_lookup` LEFT JOIN `tbl_hcas_20160321` AS `dest_hcas` ON `dest_lookup`.`zipcode` = `dest_hcas`.`zipcode` LEFT JOIN `tbl_ssas_20160321` AS `dest_ssas` ON `dest_lookup`.`zipcode` = `dest_ssas`.`zipcode`)
INNER JOIN `tbl_matx_20160321` ON (`orig_lookup`.`xdock` = `tbl_matx_20160321`.`otrmnl` AND `dest_lookup`.`xdock` = `tbl_matx_20160321`.`dtrmnl`))
WHERE `orig_lookup`.`zipcode` = '$ziporig' AND `dest_lookup`.`zipcode` = '$zipdest'",

sorting a result mysql/php

Lets say i have a list full of phones.
It's easy to print all the phones out in a unordered list like:
$get_phones = $mysqli->query("
SELECT
a.id,
b.phone_id,
a.phonename AS pname,
b.modelname AS mname,
FROM phone_brands
a LEFT OUTER JOIN phone_models b
ON a.id = b.phone_id");
while($phones = $get_phones->fetch_assoc()){
echo $phones['pname'] . $phones['mname'];}
But how can i make the list more readable by sorting all the models and phones like:
Iphone
3G
3GS
4G
Nokia
Lumia 1020
Lumia 925
Lumia 520
My guess is that i should do something like:
if($phones['pname'] == $phones['pname']{}
But i don't know if i'm far away here? Any help would be appreciated :)
Well ofcourse you could order the query by mname:
$get_phones = $mysqli->query("
SELECT
a.id,
b.phone_id,
a.phonename AS pname,
b.modelname AS mname,
FROM phone_brands
a LEFT OUTER JOIN phone_models b
ON a.id = b.phone_id
ORDER BY mname");
And then in php do something like:
$currentModel = "";
while($phones = $get_phones->fetch_assoc()){
if($currentModel != $phones['mname']){
echo $phones['mname'].'<br/>';
$currentModel = $phones['mname'];
}
echo $phones['pname'];
}
Sorting on the database level is much faster and at the end, the result is the same. You can just read it in a PHP array and have it sorted.
$get_phones = $mysqli->query("
SELECT
a.id,
b.phone_id,
a.phonename AS pname,
b.modelname AS mname,
FROM phone_brands
a LEFT OUTER JOIN phone_models b
ON a.id = b.phone_id
order by pname, mname");
SELECT
a.id,
b.phone_id,
a.phonename AS pname,
b.modelname AS mname,
FROM phone_brands AS a
LEFT OUTER JOIN phone_models AS b
ON a.id = b.phone_id
ORDER BY pname, mname DESC
That should do the job from what your question asks?
[edit]
I need to improve the code, i'm thinking using something like a foreach so it's more useable later than just order by :P – Simon Duun
Going on that comment, you could still use the order by in the query but do something like:
$phone_array = array();
while($phones = $get_phones->fetch_assoc()){
$phone_array[$phones['pname']] = $phones['pname'] . $phones['mname'];
}
ksort($phone_array);
foreach($phone_array as $phone_pname => $phone_value){
echo $phone_pname . ' -> ' . $phone_value . "\r\n";
}

combining two mysql queries in php

I am creating a dashboard to keep me updated on call agent status.an agent will have multiple records in the log. I need to pull the most recent status from the agent log. The only way I have found is to query the agent table to pull the agents with status changes made today and then query the agent log table to pull the most recent status.
is there a way to combine the two queries.? Here are my queries
$sql_get_agents = "SELECT id FROM agent WHERE lastchange LIKE '{$today}%'";
if($dta = mysql_query($sql_get_agents)){
while($agent = mysql_fetch_assoc($dta)){
$curr_agent[] = $agent;
}
foreach($curr_agent as $agents_online){
$get_status_sql = "SELECT a.firstname,a.lastname,al.agentid,al.agent_statusid,s.id as statusid,s.status,MAX(al.datetime) as datetime FROM agent_log al
INNER JOIN agent a ON al.agentid = a.id
INNER JOIN agent_status s ON a.agent_statusid = s.id
WHERE al.agentid = '{$agents_online['id']}'";
if($dta2 = mysql_query($get_status_sql)){
while($agent_status = mysql_fetch_assoc($dta2)){
$curr_status[] = $agent_status;
}
}
}//end for each
return $curr_status;
}//end if
Why don't you join the 2 queries into one adding the WHERE lastchange LIKE '{$today}%' condition in the second query?
Using the IN clause should work :
"SELECT a.firstname,a.lastname,al.agentid,al.agent_statusid,s.id as statusid,s.status,MAX(al.datetime) as datetime FROM agent_log al
INNER JOIN agent a ON al.agentid = a.id
INNER JOIN agent_status s ON a.agent_statusid = s.id
WHERE al.agentid IN (SELECT id FROM agent WHERE lastchange LIKE '{$today}%');
You were close with what you have. This will get rid of the need to do both queries, or query in a loop.
edit: adding example code to loop over the results as well.
edit2: changed query.
$query = "SELECT
a.firstname,
a.lastname,
al.agentid,
al.agent_statusid,
s.id as statusid,
s.status,
MAX(al.datetime) as datetime
FROM agent a
LEFT JOIN agent_log al ON al.agentid = a.id
LEFT JOIN agent_status s ON a.agent_statusid = s.id
WHERE a.lastchange LIKE '{$today}%'";
$status = array();
$results = mysql_query( $query );
while( $agent = mysql_fetch_assoc( $results ) )
$status[] = $agent;
print_r( $status );

Advanced MySQL Joining. Speeding up query

I have a list of users on my php application (using codeigniter). Each user may have completed a form with about 1000 or so total fields. The structure looks similar to this:
users
id|username|...
completed_form_fields
id|formid|userid|fieldkey|data
where field key is just a unique key for that particular form field, ie: "first_name"
I have a user search page where people can filter out specific users by the fields they chose (eye color, race, gender...) Then I need to display these fields so I would love (and currently have) an output like this:
$filteredmembers = array(
[0] = Object(
[id] => 1
[username] => kilrizzy
...
[fields] => Array(
[fname] => Jeff
[gender] => Male
...
Currently my script is obviously taking forever since I query all the members who filled out this form, then loop through each one to query all of their fields. THEN filter those out based on criteria + page / offset.
I know there needs to be a way to join these together in one query I am not familiar with
Simplified version of my very slow code:
function get_members(){
$this->db->select('u.*');
$this->db->from('users AS u');
$query = $this->db->get();
if ($query->num_rows() > 0){
$members = $query->result();
//Get fields from each user
foreach($members as $mk => $mv){
$fields = $this->get_form_fields($mv->id,1,true);
$members[$mk]->fields = $fields;
}
return $members;
}else{
return false;
}
}
function get_form_fields($uid,$form,$values=false){
$this->db->where('user', $uid);
$this->db->where('form', $form);
$query = $this->db->get('form_fields');
if ($query->num_rows() > 0){
$result = $query->result();
return $result;
}else{
return false;
}
}
There is a way but it gets over expensive the more you add fields. The same thing occurs with many CMS that choose to store additionnal user data in that form.
You can get a working search SQL using this:
SELECT
users.*,
firstname.data AS firstname,
lastname.data AS lastname,
eyecolor.data AS eyecolor,
FROM
users
LEFT JOIN completed_form_fields AS firstname ON firstname.userid = users.id AND firstname.fieldkey = "firstname"
LEFT JOIN completed_form_fields AS lastname ON lastname.userid = users.id AND lastname.fieldkey = "lastname"
LEFT JOIN completed_form_fields AS eyecolor ON eyecolor.userid = users.id AND eyecolor.fieldkey = "eyecolor"
WHERE
firstname.data LIKE '%searchdata%'
OR lastname.data LIKE '%searchdata%'
OR eyecolor.data LIKE '%searchdata%'
This method gets very big and expensive for the MySQL server the more you add tables. Therefore, i would recommend not to go more than 10-15 joins like that and then again, i'd profile it to make sure.
SELECT u.username, f.formid, f.userid, f.fieldkey, f.data FROM user AS u
LEFT JOIN completed_form_fields AS f
ON f.userid = u.id
you should look at indexing your userid, index(userid), via phpmyadmin or sql file
mysql-indexes
I'm not sure I completely understand the problem. You can use a single query to get all users, and all of their fields (basically, this is what Philip suggested):
SELECT u.username, f.*
FROM user AS u
INNER JOIN completed_form_fields AS f
ON f.userid = u.id
ORDER BY u.id, f.fieldkey
To filter the results, add a WHERE clause with the conditions. For example, to only get data from fieldkeys 'k1', 'k2' and 'k3':
SELECT u.username, f.*
FROM user AS u
INNER JOIN completed_form_fields AS f
ON f.userid = u.id
WHERE f.fieldkey IN ('k1', 'k2', 'k3')
ORDER BY u.id, f.fieldkey
Is this what you're looking for?

Categories