Codeigniter join query failing - php

I am trying to execute this query in codeigniter 2.2. I read the documentation http://www.codeigniter.com/user_guide/database/results.html.
My controller code is this
$query = $this->db->query("SELECT a.id, a.child, a.immune, a.immun_date, b.id, b.fname, b.lname, c.id, c.name
FROM immun a, children b, immun_master c
WHERE a.child = b.id
AND c.id = a.immune
");
$immun = array();
foreach ($query->result()as $row) {
$immun[] = array(
$row->id,
$row->child,
$row->immune,
$row->immun_date,
);
}
The results that are turned is this:
array (
0 =>
array (
0 => '2',
1 => '1001',
2 => '2',
3 => '2011-04-23',
),
1 =>
array (
0 => '3',
1 => '1001',
2 => '3',
3 => '2011-04-30',
),
2 =>
array (
0 => '6',
1 => '1002',
2 => '6',
3 => '2011-04-30',
),
3 =>
array (
0 => '5',
1 => '1002',
2 => '5',
3 => '2011-04-29',
),
4 =>
array (
0 => '1',
1 => '1003',
2 => '1',
3 => '2011-01-06',
),
5 =>
array (
0 => '3',
1 => '1005',
2 => '3',
3 => '2010-10-04',
),
6 =>
array (
0 => '3',
1 => '1231',
2 => '3',
3 => '2014-08-01',
),
)
These are wrong results. I was expecting is the merged results of the query. Below is what I get when I run the query in phpmyadmin
id child immune immun_date id fname lname id name
1 1001 2 2011-04-23 1001 Johny Jame 2 Swine Flu Vaccine
2 1001 3 2011-04-30 1001 Johny Jame 3 Bird Flu Vaccine
3 1002 6 2011-04-30 1002 Chelsea James 6 Hepatitis B
4 1002 5 2011-04-29 1002 Chelsea James 5 Measles Vaccine
5 1003 1 2011-01-06 1003 Charles Jacob 1 H1N1 Vaccine
6 1005 3 2010-10-04 1005 Hansome Little 3 Bird Flu Vaccine
7 1231 3 2014-08-01 1231 Jennifer Ylanan 3 Bird Flu Vaccine
Now, it would be nice if I could get CI to return the same set of merged data. I can see that is it only returning the table query for immun and CI is not join data from the other table.s I read somewhere that CI was not build to handle complex queries? Is that true?
Any ideas how to get the data I need?
Thanks!

You could see the query CI ran in your database.
Put the following code on the controller that render the page where this query is used:
$this->output->enable_profiler(TRUE);
This way CI will output a profiler in the end of the page with lots of information, including the executed queries needed for rendering the page.
This should help.
Another hint, you must use alias in case you need to select columns with equal names from different tables. CI don't handle it well.

function immChild() {
$this->db->select('c.id, c.name, b.id, b.fname, b.lname, a.id, a.child, a.immune, a.immun_date');
$this->db->join('immun_master as c', 'c.id = a.immune','true');
$this->db->join('children as b', 'a.child = b.id', 'true');
$query = $this->db->get('immun as a')->result();
return $query;
}
This is the correct query for the cross join for codeigniter. In my original post, I did not have conditionals. I found it here
https://ellislab.com/codeIgniter/user-guide/database/active_record.html
in the section about join. I seen that there was a place for conditions of the join. Once I added the conditions. I got the correct result set returned.

Related

How to create a three dimensional array from sql query PHP

I have 2 tables in a database, 1 of them are linked with a foreign key to the first one. Each row on table 1 is linked to multiple rows in table 2. I am trying to make a query that looks at a WHERE from table 2 and returns multiple rows from table 2 which are sorted into the rows they linked with in table 1 and then put this all into one big multi dimensional array, so it should work something like this:
$array[0][column_name][0] this would use row 1 from table 1 and give me a the first result in the column called column_name
$array[1][column_name][0] this would use row 2 from table 1 and give me a the first result in the column called column_name
$array[1][column_name][3] this would use row 2 from table 1 and give me a the 4th result in the column called column_name
etc
How can I query this and store it in a 3 dimensional array using PHP.
I have tried to word this in as clear manner as possible, if you are unsure what I am asking, please comment and I will update my question to make it clearer.
Assume that we have two tables, Company and Employee:
Company
------------------
ID Company_Name
1 Walmart
2 Amazon.com
3 Apple
Employee
---------------------------------
ID Company_Id Employee_Name
1 1 Sam Walton
2 1 Rob Walton
3 1 Jim Walton
4 1 Alice Walton
5 2 Jeff Bezos
6 2 Brian T. Olsavsky
7 3 Steve Jobs
8 3 Tim Cook
The easiest way to envision a multi-dimensional (nested) array is to mimic the looping required to get it: outer loop is the company, inner loop is the employees:
// ignoring database access, this is just pseudo code
$outer = [];
// select id, company_name from company
foreach $companyResult as $companyRow {
// select * from employee where company_id = ? {$companyRow['id']}
$inner= [];
foreach $employee_result as $employeeRow {
$inner[] = $employeeRow; // ie, ['id'=>'1','Company_Id'=>'1','Employee_Name'=>'Sam Walton']
}
$outer[] = $inner;
}
print_r($outer);
// yields ====>
Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[Company_Id] => 1
[Employee_Name] => Sam Walton
)
[1] => Array
(
[id] => 2
[Company_Id] => 1
[Employee_Name] => Rob Walton
)
[2] => Array
(
[id] => 3
[Company_Id] => 1
[Employee_Name] => Jim Walton
)
[3] => Array
(
[id] => 4
[Company_Id] => 1
[Employee_Name] => Alice Walton
)
)
[1] => Array
(
[0] => Array
(
[id] => 5
[Company_Id] => 2
[Employee_Name] => Jeff Bezos
)
[1] => Array
(
[id] => 6
[Company_Id] => 2
[Employee_Name] => Brian T. Olsavsky
)
)
[2] => Array
(
[0] => Array
(
[id] => 7
[Company_Id] => 3
[Employee_Name] => Steve Jobs
)
[1] => Array
(
[id] => 8
[Company_Id] => 3
[Employee_Name] => Tim Cook
)
)
)
It is also possible to do if you use associative arrays. Consider the flat file that this query produces:
select company.id company_id, company.name company_name,
emp.id employee_id, emp.employee_name
from company
inner join employee on company.id = employee.company_id
-----
company_id company_name employee_id employee_name
1 Walmart 1 Sam Walton
1 Walmart 2 Rob Walton
1 Walmart 3 Jim Walton
1 Walmart 4 Alice Walton
2 Amazon.com 5 Jeff Bezos
2 Amazon.com 6 Brian T. Olsavsky
3 Apple 7 Steve Jobs
3 Apple 8 Tim Cook
Just use the primary IDs as the keys for your arrays:
$employeeList = [];
foreach($result as $row) {
$cid = $row['company_name'];
$eid = $row['employee_name'];
// avoid uninitialized variable
// $employeeList[$row['company_name']] = $employeeList[$row['company_name']] ?? [];
// easier to read version of above
$employeeList[$cid] = $employeeList[$cid] ?? [];
// assign it...
$employeeList[$cid][$eid] = $row;
}
Or, if you simply want each company row to hold an array of employee names,
$employeeList[$cid][] = $row['employee_name'];
The way that I've shown you is useful if you know the company_id and want to find the associated rows:
foreach($employeeList[2] as $amazon_guys) { ... }
But it's not at all useful if you're trying to group by employee, or some other field in the employee table. You'd have to organize the order of your indexes by your desired search order.
In the end, it's almost always better to simply do another query and let the database give you the specific results you want.

Retrieve multiple rows from multiple tables

I am trying retrieve multiple rows from multiple tables but I think I am not doing it in the right way. The project is kind of a shop online, I have 3 tables in it: orders, orderdetails and services, which all are linked with an ID:
I have Order ID and Service ID in orderdetails' table, it means I inserts a row for each item on the basket linked to Service ID to see which service is, and Order Id to check for which order are. Example:
services table
-
service_id|name |price
------------------------
2 |Tech |100
------------------------
4 |Support|150
------------------------
10 |Mainten|50
------------------------
orders table
-
order_id|customer_id|name|lastname
----------------------------------
10 |16 |John|Smith
----------------------------------
orderdetails table
-
orderdetails_id|order_id|service_id|price|quantity
--------------------------------------------------
1 |10 |2 |100 |4
--------------------------------------------------
2 |10 |4 |150 |2
--------------------------------------------------
3 |10 |10 |50 |1
--------------------------------------------------
I inserts service's price on orderdetails table because maybe the services price can change AFTER a customer order it.
At this moment I have this query:
$query = $this->db->prepare(
'SELECT orders.*, orderdetails.*, services.*
FROM orders
LEFT JOIN orderdetails
ON orderdetails.order_id = orders.order_id
LEFT JOIN services
ON orderdetails.service_id = services.service_id
WHERE orders.order_id = ?
AND orders.customer_id = ?');
And I got this result:
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => Tech
[lastname] => Smith
[orderdetails_id] => 1
[service_id] => 2
[price] => 100
[quantity] => 4
)
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => Support
[lastname] => Smith
[orderdetails_id] => 2
[service_id] => 4
[price] => 150
[quantity] => 2
)
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => Mainten
[lastname] => Smith
[orderdetails_id] => 3
[service_id] => 10
[price] => 50
[quantity] => 1
)
I have two problems. The 1st problem is I have the same column name in orders table and services table. The 2nd is the query returns all the information (because I know I am not querying well), but I expect to receive something like this:
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => John
[lastname] => Smith
[orderdetails_id] => 1
[service_id] => 10
[price] => 50
[quantity] => 1
[service_name] => Mainten
[orderdetails_id2] => 2
[service_id2] => 4
[price2] => 150
[quantity2] => 2
[service_name2] => Support
[orderdetails_id3] => 3
[service_id3] => 2
[price3] => 100
[quantity3] => 4
[service_name3] => Tech
)
I mean, I am not an expert in SQL Queries, and I read a lot, but I think you guys could help me to figure it out this because I have other two tables to link with: customer-service-worker who will get the order to process, and area's table who will receive the order.
I use this code for getting the objects:
$array = array();
while($loop = $result->fetch_object()){ $array[] = $loop; }
return $array;
The problem is that you are using fetch_object() for getting the result but you are not renaming in the query the columns with the same name, and since you can't have two different object attributes with the same name the rest of columns are discarded.
You can either use other method for getting the values like fetch_row() or change the query to rename columns with the same name, for example:
SELECT orders.*, orderdetails_id, service_id, orderdetails.price as detail_price, quantity,
services.name as service_name, services.price as service_price
FROM orders
LEFT JOIN orderdetails ON orderdetails.order_id = orders.order_id
LEFT JOIN services ON orderdetails.service_id = services.service_id
WHERE orders.order_id = ?
As a side note if order_id is the primary key of orders you don't need to use customer_id in the where condition, and if the primary key is composed of both columns (i.e., you can have the same order ID for different customers) I recommend change it and use only order_id.

How to count particular value in a field of a table in codeigniter query command

I am trying to do a report and for this I need to fetch and count the number of child's of each employee if married. I tried a way but its only getting one employee information when add the asterik line in query else its fetch all employee's information as a beginner I don't know why . relation are coming from a array . I am giving the array here with table and my code to understand ! let me remind you I want child's total thats mean total of son and daughter not only son or daughter total .
this is the relation array ;
$config['relation'] = array(
'1' => 'father',
'2' => 'mother',
'3' => 'brother',
'4' => 'sister',
'5' => 'husband',
'6' => 'wife',
'7' => 'son',
'8' => 'daughter',
'9' => 'uncle',
'10' => 'unty',
'11' => 'cousin',
'13' => 'grand father',
'14' => 'grand mother',
);
this is the database table to fetch
EMP_FAMILY_ID EMP_ID NAME NAME_BENGALI RELATION BIRTH_DATE AGE OCCPATION CONTACT_NO
1 1 fghn vbn 7 2000-09-02 15 4 23546585
2 1 dgh dfgh 7 2003-10-02 12 4 453273
3 1 fghjm fgn 8 1970-01-01 14 4 4520752
4 1 fgbbn bmnbnm 8 1970-01-01 14 4 4532
5 2 bfhb fghfg 5 1970-01-01 20 8 634565
6 3 bfhb fghfg 6 1970-01-01 20 9 634565
$query = $this->db->select('
emp.EMPLOYEE_NAME_BENGALI,
emp.EMPLOYEE_FATHER_BENGALI,
emp.EMPLOYEE_MOTHER_BENGALI,
emp.BIRTH_DATE,
emp.EMP_BLOOD_GROUP,
emp.MARITAL_STATUS,
emp.EMP_JOB_NATURE,
emp.QUOTA_ID,
**sum(case when emf.RELATION="7" || emf.RELATION="8" then 1 else 0 end) as son,**
')
->from('hrm_ls_employee as emp')
->join('hrm_ls_emp_family as emf','emp.EMP_ID = emf.EMP_ID','left')
->where('emp.IS_DELETED',0)
->order_by('emp.EMP_ID')
->get();
$emp_details_report = $query->result();

Getting the most from a single MySQL query

I have a website that lists apartments that are available for rent. I have a few different tables in my MySQL database. One table is for basic information about the Apartment building as a whole, including address, ammenities, photos, an ID (NID), etc.
Another table lists the units available for rent within each building. So each apartment building has multiple floorplans, with a few studios, a few 1 bedroom units, sometimes a few 2 bedroom units, etc.
Currently I query my 'unit' table and ask for all units in a given apartment building. My query looks something like SELECT * FROM node_unit WHERE nid='555'
This might return something like the following:
NID Name Rent SqFT Bedrooms Bathrooms
555 Unit 1 $500 620 0 1
555 Unit 2 $550 680 0 1
555 Unit 3 $600 820 1 1
555 Unit 4 $650 920 1 1
555 Unit 5 $700 1220 2 1
555 Unit 6 $800 1420 2 2
555 Unit 7 $900 1500 3 2
555 Unit 8 $1100 1620 3 3
etc, etc
What I am then doing in my PHP is using an accordian to group the 1 bedrooms together, the 2 bedrooms together, etc.
Not all apartments have 2 bedrooms units, some only have 1 bedroom units, so I need to know within my PHP code if I should print another accordian.
Currently I am using multiple hits to the database to determine if a given building has any 2 bedroom units, if so print another row. Does this building have any 3 bedroom units? If so print another row, but I would like to stop hitting my database so much.
Finally, here is my question:
How can I store the results from my first DB call and somehow parse thru the data and and determine if a given NID has studios, 1 beds, 2 beds, etc? (I just started learning PHP/MySQL recently)
I would suggest a query like this:
SELECT * FROM node_unit WHERE nid='555'
ORDER BY Bedrooms ASC, Bathrooms ASC, Rent ASC
This would return your records ordered by # of bedrooms, # bathrooms, and rent amount (in that order).
You could easily store this in multidimensional array when reading from database like this (assuming mysqli use with result set stored in $result, but concept is same for other DB connection libraries)
$room_array = array();
while ($row = mysqli_fetch_assoc($result)) {
$room_array[(int)$row['Bedrooms']][] = $row;
}
You now have a multidimensional array with number of bedrooms as first index. The array might look like this if you var_dump it:
Array (
[0] => Array (
[0] => Array (
'NID' => '555',
'Name' => 'Unit 1',
'Rent' => '$500',
'SqFt' => '620',
'Bedrooms' => '0',
'Bathrooms' => '1',
)
[1] => Array (
'NID' => '555',
'Name' => 'Unit 2',
'Rent' => '$550',
'SqFt' => '680',
'Bedrooms' => '0',
'Bathrooms' => '1',
)
)
[1] => Array (
[0] => Array (
'NID' => '555',
'Name' => 'Unit 3',
'Rent' => '$600',
'SqFt' => '820',
'Bedrooms' => '1',
'Bathrooms' => '1',
)
[1] => Array (
'NID' => '555',
'Name' => 'Unit 4',
'Rent' => '$650',
'SqFt' => '920',
'Bedrooms' => '1',
'Bathrooms' => '1',
)
[2] => Array (
...
)
[3] => Array (
...
)
)
This makes it really easy to iterate over the number of bedrooms values in an outer loop, which creates your accordions, and then iterate the individual rooms in an inner loop.
foreach ($room_array as $num_bedrooms => $rooms) {
// start accordion
foreach ($rooms as $room) {
// output room details
}
// end accordion
}
All this would only require the single query.
Also make sure you have indexes on bedrooms, bathrooms, rent (or whichever you use in the sort) as well as on nid since it is used as the filter.
Try this as your database query, it will generate a row for each building for each unit type it has. You could also use it as a subquery and join to the parent table to get any other details you need about the building in one shot.
select 'studio' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 0 then 1 end) > 0
union all
select 'one bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 1 then 1 end) > 0
union all
select 'two bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 2 then 1 end) > 0
union all
select 'three bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 3 then 1 end) > 0

Top 5 Rankings Issue

So I'm wondering if this is even the best way to manage my data for this table because with my query I'm not getting the correct results I want.
I am wanting it to grab the top5 rankings from the last date entry in the table. A problem is if there is a 0 for the character_id. When I do my php to see if there isn't a value then it should echo TBD but its still not showing it in the array to be 0.
Table: top5
id ranking # character_id status_id date_created
1 1 1 1 2011-10-17 17:18:54
2 2 2 1 2011-10-17 17:18:54
3 3 3 1 2011-10-17 17:18:54
4 4 4 1 2011-10-17 17:18:54
5 5 5 1 2011-10-17 17:18:54
6 1 6 1 2011-10-24 12:18:54
7 2 7 1 2011-10-24 12:18:54
8 3 8 1 2011-10-24 12:18:54
9 4 9 1 2011-10-24 12:18:54
10 5 0 1 2011-10-24 12:18:54
function getTop5()
{
$this->db->select('characters.character_name, top5.character_id');
$this->db->from('top5');
$this->db->join('characters', 'characters.id = top5.character_id');
$this->db->where('top5.status_id', '1');
$this->db->order_by('top5.date_created','desc');
$this->db->limit(5);
$query = $this->db->get();
return $query->result_array();
}
Array ( [0] =>
Array ( [character_name] => \"Mr. Magnificent\" Matt Sharp
[character_id] => 9 )
[1] =>
Array ( [character_name] => \"The Unforgettable\" Jimmy Watkins
[character_id] => 8 )
[2] =>
Array ( [character_name] => Romie Rains
[character_id] => 7 )
[3] =>
Array ( [character_name] => Monica Dawson
[character_id] => 6 )
[4] =>
Array ( [character_name] => \"The Outlaw\" Mike Mayhem
[character_id] => 5 ) )
EDIT: Anyone else want to give it a try?
So lost and can't get the desired results still
You'd want to order by top5.date_created in descending order. If you really only want the last day, you'd also want a WHERE condition for that.
Not sure what db class is it, but just append
AND date(date_created) = CURDATE();
to the query
or append DESC to ORDER clause
So something like
$this->db->select('characters.character_name, top5.character_id');
$this->db->from('top5');
$this->db->join('characters', 'characters.id = top5.character_id');
$this->db->where('top5.status_id', '1');
// WHERE date(top5.date_created) = CURDATE()
$this->db->order_by('top5.date_created');
$this->db->limit(5);
$query = $this->db->get();
function getTop5()
{
$this->db->select('characters.character_name, top5.character_id');
$this->db->from('top5');
$this->db->join('characters', 'characters.id = top5.character_id');
$this->db->join( '( SELECT DATE(MAX(date_created)) AS lastdate
FROM top5
WHERE status_id = 1
) AS tm'
, 'top5.created_at >= tm.lastdate
AND top5.created_at < tm.lastdate + INTERVAL 1 DAY');
$this->db->where('top5.status_id', '1');
$this->db->order_by('top5.ranking','asc');
$this->db->limit(5);
$query = $this->db->get();
return $query->result_array();
}

Categories