I have a codeigniter query to get a list of questions from my database. I'm using some joins to get the category name and the answer type. Its working good to output everything, but when i try and output the id of the row from the "questions" table, it displays as "2" which is the answer_type_id.
Maybe I'm doing this wrong, i'm fairly new to joins. Any help is appreciated:
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Update===============
I have added "left" for my join type but the problem persists. The question id's should be 2 and 3. But when i print my array returned, they are both 2 (which is the answer_type_id).
Here is the updated code (only left join changed)...
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
And here is the output it returns:
Array (
[0] => Array (
[id] => 2
[category] => Herbs
[type] => 2
[question] => What Type of Vehicle do You own?
[answer] => Drop down list [priority] => 0
)
[1] => Array (
[id] => 2
[category] => Herbs
[type] => 3
[question] => What is Your Favorite Herb
[answer] => Drop down list [priority] => 0
)
)
The reason you are not getting the proper ids is you are selecting *.
Use aliases so that give them separate names and you will be access them
as you want like this.
function get_questions($category_id) {
$this->db->select('questions.*');
$this->db->select('answer_type.answer_type_id');
$this->db->select('answer_type.other_column');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
return $this->db->get()->result_array();
}
Also Codeigniter database class provide a method call result_array()
Which is already alternate of the loop you are using. So use it instead of
extra loop code.
Just change it to this:
'id' => $row->category_id
The problem is that the id column is ambiguous. In cases where your selecting columns across tables with columns that have the same name, you can also use the AS keyword to rename a column.
For example:
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
By chance are you (maybe) only getting one row as a result, where all the ids match?
You should specify your join type, or be more specific in your query, so that you keep the question.id value.
For this question, you could specify the join as a left join, to keep all the data from questions table and tack on from categories and answer_types where its found.
see CodeIgniter ActiveRecord docs
The questions id needs to be defined as its own name. To pull ALL the data from the other tables, follow up with asterisks for the other tables, like so...
function get_questions($category_id) {
$this->db->select('questions.id as questions_id, questions.*, categories.*, answer_type.*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->questions_id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Use alias for your id columns like the above example.
...
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
...
...
Now you get your data because only have one id column.
Here you have an article: http://chrissilich.com/blog/codeigniter-active-record-aliasing-column-names-to-prevent-overwriting-especially-columns-named-id/
Related
Is it possible to result any sql query into multidimensional array? In my case if I have a player with multiple teams.. how do I need to get a result like this
array(
'fname' => 'Mark',
'lname' => 'Caguioa',
'teams' => array(
'team' => 'Ginebra',
'team' => 'Hotshots'
)
)
And my idea in my query but it's not working...
$stmt = $this->sql->prepare("
SELECT
usr.fname,
usr.lname,
(
SELECT
team.name
FROM users usr
LEFT JOIN teams team
ON usr.gen_id = team.gen_id
) AS to 'teams'
FROM users usr
");
$stmt->execute(array(':gen_id' => 'generated_id'));
return $stmt->fetchAll(PDO::FETCH_ASSOC);
Any idea how to come up with this problem? Any help is very appreciated
Using the below, I echo a JSON array of the results. But this requires that I identify the column names which I'd like to return from the SQL query:
$new_sql = "SELECT TOP 200 * FROM STracker ORDER BY [ID] DESC";
$check_statement = sqlsrv_query($conn, $new_sql);
$data = array();
while($row = sqlsrv_fetch_array($check_statement, SQLSRV_FETCH_ASSOC)) {
$data['data'][] = array(
'id' => $row['ID'],
's_reference' => $row['s_reference'],
'reference' => $row['reference'],
'customer_name' => $row['customer_name']
);
}
Is there any way to create that array information, but return all of the columns returned by the query dynamically? So by using SELECT * FROM, all of the column data is returned in the array but without me needing to write out all of these individually? (the below)
'id' => $row['ID'],
's_reference' => $row['s_reference'],
'reference' => $row['reference'],
'customer_name' => $row['customer_name']
Ok I forgot to add that I'd tried this:
$data['data'][] = array($row);
Which is clearly wrong, and after using the following, it works perfectly!
$data['data'][] = $row;
I have a table called items and a table called item_pics.
item_pics has an item_id, file_name and a rank field (among others).
What I'm looking for is for each item my index page's $items array to contain the file_name from the item_pics matching the item's item_id with the lowest rank. So I can access like (or something like) this in my Items/index.ctp:
foreach ($items as $item):
$img = $item['Item']['ItemPic']['file_name'];
...
I'm pretty new to CakePHP, this is my first project. I thought that this within the Item model would cause item_pics data to be pulled (although I figured all related item_pics for each item would get pulled rather than just the one with the lowest rank):
public $hasMany = array(
'ItemPic' => array(
'className' => 'ItemPic',
'foreignKey' => 'item_id',
'dependent' => false
)
}
but I can see that no item_pics data is loaded (at the bottom of items/index):
SELECT `Item`.`id`, `Item`.`title`, `Item`.`description`, `Item`.`created`, `Item`.`modified`, `Item`.`type`, `Project`.`id`, `Project`.`item_id`, `Project`.`title`, `Project`.`description`, `Project`.`rank`, `Project`.`created`, `Project`.`modified`
FROM `laurensabc`.`items` AS `Item`
LEFT JOIN `laurensabc`.`projects`
AS `Project`
ON (`Project`.`item_id` = `Item`.`id`)
WHERE `Item`.`type` IN (1, 2)
LIMIT 20
also, while I would like projects to be joined in the view pages, I don't really need them in the index page.
I've done some searching and haven't been able to find exactly what I'm looking for. I suppose I could do a query within the index view item loop, but I'm trying to make sure I do things the right way... the CakePHP way. I assume I need to change something about my model relationships but I haven't had any luck.
CakePHP - Associations - HasMany, this makes it seem like I could order by rank and limit 1. But this didn't work... and even if it did, I wouldn't want that to affect the view pages but rather just the index page.
My Controller looks like this:
public function index($type = null) {
$this->Item->recursive = 0;
$conditions = array();
if ($type == "sale") {
$conditions = array(
"Item.type" => array(self::FOR_SALE, self::FOR_SALE_OR_RENT)
);
} else if ($type == "rent" ) {
$conditions = array(
"Item.type" => array(self::FOR_RENT, self::FOR_SALE_OR_RENT)
);
} else {
$conditions = array("Item.type !=" => self::HIDDEN);
}
$paginated = $this->Paginator->paginate($conditions);
debug($paginated);
$this->set('items', $paginated);
$this->set('title', ($type == null ? "Items for Sale or Rent" : "Items for " . ucwords($type)));
}
I have also tried this on my controller, but it doesn't seem to do anything either:
$this->paginate = array(
'conditions' => $conditions,
'joins' => array(
array(
'alias' => 'ItemPic',
'table' => 'item_pics',
'type' => 'left',
'conditions' => array('ItemPic.item_id' => 'Item.id'),
'order' => array('ItemPic.rank' => 'asc'),
'limit' => 1
)
)
);
$paginated = $this->paginate($this->Item);
First, set containable behavior in AppModel (or if you don't want it on each model, put it on Item model):
public $actsAs = array('Containable');
Then, on your find query:
$items = $this->Item->find('all', array(
'contain' => array(
'ItemPic' => array(
'fields' => array('file_name'),
'order' => 'rank',
'limit' => 1
)
)
));
Then the result array you can access it like:
foreach ($items as $item):
$img = $item['ItemPic']['file_name'];
Edit: Then you should put it on the paginate query:
$this->paginate = array(
'conditions' => $conditions,
'contain' => array(
'ItemPic' => array(
'fields' => array('file_name'),
'order' => 'rank',
'limit' => 1
)
)
);
In this case, I would probably order by rank and limit 1 as you said, and make that a dynamic association just for the index page (See http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#creating-and-destroying-associations-on-the-fly). So use $this->Item->bindModel(array('hasMany' => array('ItemPic' => $options))); (which I believe should replace your current settings for HasMany ItemPic, but you may have to unbindmodel first)
Associations created through bindModel will go through for the next query only, then it'll revert to your normal settings, unless you specifically set an option to keep using the new association.
As for why it's not getting ItemPics with Items, or why trying to order by rank and limit 1 didn't work for you, I can't really say without seeing more of your code.
I am using codeigniter to produce a left join of two tables, but need to remove the brackets that active record applies to the table name. you know SELECT blah FROM ('some table') I really need these brackets to disappear.
here is my input array:
$retrieve_arr = array(
'table' => 'entries',
'select' => array('entries.entry_id', 'entries.score', 'sc_users.name', 'clients.name'),
'joins' => array(
'clients' => 'entries.client_id = clients.client_id',
'sc_users' => 'entries.sc_user_id = sc_users.sc_user_id'
),
'joinType' => 'left',
'where' => 'null'
);
here is my model:
$retrieve = new Data();
if($get_arr['select'] != 'null')
{
$query = $retrieve->db->select($get_arr['select']);
}
foreach($get_arr['joins'] as $additional => $value)
{
$retrieve->db->join($additional, $value, $get_arr['joinType']);
}
if($get_arr['where'] != 'null')
{
foreach ($get_arr['where'] as $name => $value)
{
$retrieve->db->where($name, $value);
}
}
$query = $retrieve->db->get($get_arr['table']);
$queryData = $query->result_array();
return $queryData;
and here is what my query string:
SELECT `entries`.`entry_id`, `entries`.`score`, `sc_users`.`name`, `clients`.`name` FROM (`entries`) LEFT JOIN `sc_users` ON `entries`.`sc_user_id` = `sc_users`.`sc_user_id` LEFT JOIN `clients` ON `sc_users`.`client_id` = `clients`.`client_id`Array
I have been looking for this for a while so your help is very much appreciated.
If you are referring to the ` backticks, in the Select() portion, use a FALSE as the second parameter (refer to the Users Guide for more info)
So, I have three tables. Movies, movies_genres and genres. I want to get a movie by its Id, and also join its genres in the result. I managed to join the results, but it doesn't display as i want it to. I'm not sure if what I'm asking is possible.
This is my query:
SELECT `movies`.*, GROUP_CONCAT(genres.id) AS genre_id, GROUP_CONCAT(genres.name) AS genre_name
FROM (`movies`)
INNER JOIN `movies_genres`
ON `movies_genres`.`movie_id` = `movies`.`id`
INNER JOIN `genres`
ON `genres`.`id` = `movies_genres`.`genre_id` WHERE `movies`.`id` = 19908
GROUP BY `movies`.`id`
The query was generated by Codeigniters Active Record class, here is the Codeigniter code if that helps:
$this->db->select('movies.*, GROUP_CONCAT(genres.id) AS genre_id, GROUP_CONCAT(genres.name) AS genre_name');
$this->db->from('movies');
$this->db->where('movies.id', $movie_id);
$this->db->join('movies_genres', 'movies_genres.movie_id = movies.id', 'inner');
$this->db->join('genres', 'genres.id = movies_genres.genre_id', 'inner');
$this->db->group_by('movies.id');
Here is the result i'm currently getting:
Array
(
[id] => 19908
[movie_title] => Zombieland
[overview] => An easily spooked guy...
[genre_id] => 28,12,35,27
[genre_name] => Action,Adventure,Comedy,Horror
)
And this is what I want:
Array
(
[id] => 19908
[movie_title] => Zombieland
[overview] => An easily spooked guy...
[genres] => array(
0 => array(
'id' => 28,
'name' => Action
),
1 => array(
'id' => 12,
'name' => Adventure
),
1 => array(
'id' => 35,
'name' => Comedy
),
1 => array(
'id' => 27,
'name' => Horror
)
)
)
Is this possible, and if so, how?
The query you listed will have n rows (where n = # of movies) whereas the query it seems you want will have many more rows (# of movie_genre's entries). You're probably better off leaving that query as it is, and doing some post processing.
Consider:
After you get it, just run your result (e.g. $result) array through something like:
foreach($result as &$row)
{
// Split over commas
$gi_elements = explode(',', $row['genre_id']);
$gn_elements = explode(',', $row['genre_name']);
// Build genre
$row['genre'] = array();
for($i=0; $i<count($gi_elements); $i++)
{
$row['genre'][] = array('id' => $gi_elements[$i], 'name' => $gn_elements[$i]);
}
// Cleanup
unset($row['genre_id']);
unset($row['genre_name']);
}
Afterwards, $results will look exactly as you wish without extra database work.
EDIT: Fixed some typos.