MySQL Function and CodeIgniter Active Record - mysql

CodeIgniter Active Record is easy, well documented and powerful. But when I try to insert MySQL built in functions CONCAT, NOW, GROUP_CONCAT, DATEDIFF, TRIM etc or my custom functions it is giving errors. The following code works fine...
$result = $this->db->select('p.first_name, p.last_name, p.mobile_number, p.email_address')->from('profile p')->get()->result();
But When I want to contact first_name and last_name and use MySQL CONCAT function like this...
$result = $this->db->select('CONCAT(p.first_name, " ", p.last_name) fullname, p.mobile_number, p.email_address')->from('profile p')->get()->result();
It is showing database errors
A Database Error Occurred
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '", `p`.`last_name)` fullname, `p`.`mobile_number`, `p`.`email_address` FROM (`pr' at line 1
SELECT CONCAT(p.first_name, `"` ", `p`.`last_name)` fullname, `p`.`mobile_number`, `p`.`email_address` FROM (`profile` p)
Filename: D:\xampp\htdocs\example\system\database\DB_driver.php
Line Number: 330
Is there a any way to insert MySQL Functions inside CodeIgniter Active Record? Hope I am clear. Thanks in advance.

Since I don't know your exact error:
From user_guide:
$this->db->select() accepts an optional second parameter. If you set it to FALSE, CodeIgniter will not try to protect your field or table names with backticks. This is useful if you need a compound select statement.
$result = $this->db->select('CONCAT(p.first_name, " ", p.last_name) fullname, p.mobile_number, p.email_address', FALSE)->from('profile p')->get()->result();

Place you "select " in array
$this->db->select(array('CONCAT(p.first_name, " ", p.last_name) fullname, p.mobile_number, p.email_address'))
by.

For the case of update using active records you can use
$this->db->set("date_read", "NOW()", FALSE);
Will output something like this
`SET `date_read` = NOW(),

FIXED THE ISSUE
adding the field names in active record array can fix this problem. inside array you can use any mysql functions. the fix of above.
MySQL Table :
fullname mobile_number email_address
------------------- ------------- ------------------------------
sitaramaiah javvadi 9989403339 gnt.sitaramaiah#mstonline.in
raja kumar guthula 9949526012 gnt.rajkumar#mstonline.in
chandra sekhar k.l 9912144556 gnt.sekhar#mstonline.in
khadar basha 98884884584 khadar333332#gmail.com
super administrator 9841866445 admin#gmail.com
CodeIgniter Active Record :
$result = $this->db->select(array('CONCAT(p.first_name, " ", p.last_name) `fullname`', 'p.mobile_number', 'p.email_address'))->from('profile `p`')->get()->result();
echo '<pre>';
print_r($result);
Output :
Array
(
[0] => stdClass Object
(
[fullname] => sitaramaiah javvadi
[mobile_number] => 9989403339
[email_address] => gnt.sitaramaiah#mstonline.in
)
[1] => stdClass Object
(
[fullname] => raja kumar guthula
[mobile_number] => 9949526012
[email_address] => gnt.rajkumar#mstonline.in
)
[2] => stdClass Object
(
[fullname] => chandra sekhar k.l
[mobile_number] => 9912144556
[email_address] => gnt.sekhar#mstonline.in
)
[3] => stdClass Object
(
[fullname] => khadar basha
[mobile_number] => 98884884584
[email_address] => khadar333332#gmail.com
)
[4] => stdClass Object
(
[fullname] => super administrator
[mobile_number] => 9841866445
[email_address] => admin#gmail.com
)
)

Related

cakephp resultset for multiple joins and aggregate function...i.e. complex queries

I am using cakephp in one of my project. What i need is to handle complex query using single model and single array out.Since I am new to cakephp i got stucked really very bad here :
$rs = $this->User->query("
SELECT (wd.wajebaat_amt) as commited,
SUM(pd.sila_waje) as paid,
(wd.wajebaat_amt-sum(pd.sila_waje)) as balance,
FROM wajebaat_details as wd
LEFT JOIN waje_pay_details as pd ON (pd.waje_id=wd.waje_id)
WHERE wd.hof_id="123" and wd.year="2010"
GROUP BY wd.waje_id");
print_r($rs); exit();
// it displays output as
Array
(
[0] => Array
(
[wd] => Array
(
[commited] => 252000
)
[0] => Array
(
[paid] => 253829
[balance] => -1829
)
)
)
//however i need it following format
Array
(
[0] => Array
(
[wd] => Array
(
[commited] => 252000
[paid] => 200000
[balance] => 52000
)
)
)
You can use Hash (utility) method format() in cakephp 2.5 to convert the nested array into string,in previous version of cakephp the method is set(),
Hash::format(array $data, array $paths, $format)
Example :
$result = Hash::format($rs,array('{n}.wd.commited','{n}.wd.0.paid','{n}.wd.0.balance'),'%1$d,%2$d,%$d');
Output:
252000,2000000,52000
For More formating option refere cook book of cakephp

SQL statement returning in wrong format

I'm writing a query to return a post id and a timestamp in one object. I have the post ID and the timestamp returning, but the timestamp key is post_id, and it should be timestamp. Also, it's storing it as a individual item in the array, and I want it to be combined with the post_id. Here's my sql statement:
$meta_key = '_birs_client_id';
$meta_value = $client_id[0]->post_id;
$adjusted_time = strtotime("+1 day");
$timestamp_meta_key = '_birs_appointment_timestamp';
$sql = "SELECT post_id FROM wp_habitera_postmeta WHERE meta_key = %s AND meta_value = %d
UNION
SELECT meta_value FROM wp_habitera_postmeta WHERE meta_key = %s";
$appointments = $wpdb->get_results($wpdb->prepare($sql, $meta_key, $meta_value, $timestamp_meta_key));
Here's an example subset of my return from the sql statement:
[19] => stdClass Object
(
[post_id] => 996
)
[20] => stdClass Object
(
[post_id] => 999
)
[21] => stdClass Object
(
[post_id] => 1002
)
[22] => stdClass Object
(
[post_id] => 1398370500
)
[23] => stdClass Object
(
[post_id] => 1398284100
)
[24] => stdClass Object
(
[post_id] => 1398196800
)
This is the format I'm trying to get:
[18] => stdClass Object
(
[post_id] => 993
[timestamp] => 1398370500
)
Can someone tell me how to get it in this format?
EDIT
here's a picture of the database I'm working with that should help clarify:
http://i59.tinypic.com/10sgml3.png
the 2 rows I'm interested in are the timestamp and appointment id. The column before the timestamp column "1000" is the post id that matches up with the column after the post id column "1000" again.
EDIT > My last answer was rubbish, edited to try to give an answer to the question.
A UNION won't help you to solve the problem: all the values retrieved from the DDBB are concatenated, the first query will retrieve the values of the field post, and the second one the values of the timestamp, but with the UNION you're telling MySQL to put them together in the same field. What you'll need to do is JOIN the table with itself to get the values you want as different fields, but for that you need to establish the a relationship between the rows. I can't say what is that relationship without knowing the structure of your table and the data it has, but if you write that relation rule in the query below you'll have the query you want:
SELECT post_id, meta_value as timestamp
FROM wp_habitera_postmeta wphp1
INNER JOIN wp_habitera_postmeta wphp2
ON ( RELATION_RULE_BETWEEN_ROWS_ON_YOUR_TABLE )
WHERE meta_value = %d

Pagination using joining multiple models

Each exam has one syllabus, each syllabus has one exam. So, I did this in the Exam model:
public $hasOne = 'Syllabuses'; //table: syllabuses, model: Syllabuses
From UsersController I did this:
public $uses = array('Setting', 'Exam', 'Syllabuses');
And in a method in UsersController I wanted to call paginate:
$options = array(
'fields' => array('Exam.id', 'Exam.name', 'Syllabuses.id', 'Syllabuses.name', 'Syllabuses.syllabus', 'Syllabuses.last_updated'),
'joins' => array(
'table' => 'syllabuses',
'conditions' => array('Exam.id = Syllabuses.exam_id')
)
);
$this->paginate = $options;
$this->set('syllabuses', $this->Paginator->paginate('Syllabuses'));
exams table:
---+------+
id | name |
---+------+
and syllabuses table:
---+---------+------+----------+--------------+
id | exam_id | name | syllabus | last_updated |
---+---------+------+----------+--------------+
So, I got some error. Like this:
Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'syllabuses Array LEFT JOIN oes.syllabuses AS Syllabuses ON (Syllabuses.`' at line 1
And my SQL that CakePHP prepared is:
SELECT `Exam`.`id`, `Exam`.`name`, `Syllabuses`.`id`, `Syllabuses`.`name`, `Syllabuses`.`syllabus`, `Syllabuses`.`last_updated`
FROM `oes`.`exams` AS `Exam` syllabuses Array
LEFT JOIN `oes`.`syllabuses` AS `Syllabuses` ON (`Syllabuses`.`exam_id` = `Exam`.`id`)
WHERE 1 = 1 LIMIT 20
But what I want is something like the query bellow. I have tested it in mysql:
SELECT `Exam`.`id` AS eid, `Exam`.`name` AS ename, `Syllabuses`.`id` AS sid, `Syllabuses`.`name` AS sname, `Syllabuses`.`syllabus` , `Syllabuses`.`last_updated`
FROM `oes`.`syllabuses` AS `Syllabuses` , exams AS Exam
WHERE Exam.id = Syllabuses.exam_id
ORDER BY Exam.id
LIMIT 20
Now anybody please help me achieve this. What kind of change can make CakePHP to prepare query like that(what I've tasted) to make my Pagination done.
Ok, I think this can be helpful for many programmers. That's why I want to share what I did finally:
$options = array(
'fields' => array(
'Exam.id',
'Exam.name',
'Syllabuses.id',
'Syllabuses.name',
'Syllabuses.exam_id',
'Syllabuses.syllabus',
'Syllabuses.last_updated'
),
'recursive' => 0,
'conditions' => array('Exam.id = Syllabuses.exam_id'),
'limit' => 3
);
$this->paginate = $options;
$syllabuses = $this->Paginator->paginate('Exam');

How to insert data which does not have specific sequence?

My array print_r is :
Array
(
[email] => xxx#cs.caddmu.edu
[attempt] => 0
[timestamp] => 1369676665
[smtp-id] => <1369676650.51a39b6a76cec#www.openaccesspub.org>
[response] => 451 4.2.0 Temporarily Grey listed. Try again in a couple of minutes
[category] => Invitation
[event] => deferred
)
Array
(
[email] => reidsdds#cs.cdsmu.edu
[timestamp] => 1369676845
[smtp-id] => <1369676650.51a39b6a76cec#www.openaccesspub.org>
[response] => 250 2.0.0 r4RHlOGH017661 Message accepted for delivery
[category] => Invitation
[event] => delivered
)
Array
(
[email] => jrai#openhh.com
[timestamp] => 1369678994
[smtp-id] => <1369678990.51a3a48e93428#ohhpb.org>
[category] => Reviewers
[event] => processed
)
Array
(
[email] => sss#lusst.fi
[timestamp] => 1369678997
[smtp-id] => <1369678990.51a3a48e93428#oub.org>
[response] => 250 2.0.0 Ok: queued as 02C103F0454
[category] => Revie
[event] => delivered
)
And the tables have these rows :
event_id, event, email, category, timestamp, response, attempt, url, status, reason, type, action, m_id .
I'm trying to insert in mysql table with this :-
foreach ($temp_array as $key => $poke)
{
mysql_query ("INSERT INTO temp_array (email,timestamp,category,event,response,attempt,reason,o_id,operator,action,...)VALUES ('$poke[email]','$poke[timestamp]','$poke[category]','$poke[event]',.... )" );
}
But i'm getting error " Undefined index: category in
C:\xampp\htdocs\eembeta\array_temp.php on line 34
How to insert data which does not have specific sequence?
This is not about sequence, but $poke['category'] does not exist in that array (element to insert). Be sure that all array fields you want to use are initialised:
$poke['category'] = $poke['category'] ? $poke['category'] : '';
That code means: Is that field set? yes: use it. no: use empty string.
That way $poke['category'] is known, so you get no error.
Btw, you can replace '' by 0, null or whatever you need.
Before using the data inside your query, sanatize it to avoid SQL Injections. To achieve this, consider using PDO.
Answering your question
For each key, create a temporary variable like:
$event = isset($_GET ['event']) ?$_GET ['event'] : null;

mysql if condition in query can't get tablename from mysql_field_table

This query works:
SELECT Article.id,
Article.post_time,
Article.post_locked,
Article.comments_locked, Article.title,
IF(CHAR_LENGTH(Article.content)>2000,
RPAD(LEFT(Article.content,2000),2003,'.'),
Article.content) as content,
Article.tags, Category.*,
User.id, User.user_name,
Comment.comment_count
FROM `articles` as `Article`
LEFT JOIN `categories` as `Category` ON `Article`.`category_id` = `Category`.`id`
LEFT JOIN `users` as `User` ON `Article`.`user_id` = `User`.`id`
LEFT OUTER JOIN (SELECT article_id, count(*) comment_count FROM `comments`) as `Comment` ON `Article`.id = `Comment`.article_id
WHERE '1'='1'
ORDER BY `Article`.`id` DESC
But when I loop through the resultset to assign the table name along with the field using 'mysql_field_table', the 'content' returns a table name of nothing, while all others have their correct table:
Array (
[0] => Article
[1] => Article
[2] => Article
[3] => Article
[4] => Article
[5] =>
[6] => Article
[7] => Category
[8] => Category
[9] => User
[10] => User
[11] => Comment )
using
for ($i = 0; $i < $numOfFields; ++$i) {
array_push($table,mysql_field_table($this->_result, $i));
array_push($field,mysql_field_name($this->_result, $i));
}
Anyone ever try to do this? Have a solution? I want to return less data from my DB in my query. Or is it less intensive (on mysql, memory, cpu) to simply select all content and truncate the content via PHP? I thought returning less from DB would be better.
Thanks a bunch!!
Peace.
EDIT
to clear up, this is the result, you will see why it isnt what I want:
Array (
[0] => Array (
[Article] => Array (
[id] => 8
[post_time] => 1278606312
[post_locked] => 0
[comments_locked] => 0
[title] => Article 8
[tags] => test )
[] => Array (
[content] => my content for Article )
[Category] => Array (
[id] => 2
[name] => cat2 )
[User] => Array (
[id] => 3
[user_name] => user3 )
[Comment] => Array (
[comment_count] => 1 )
)
[1] => Array (
[Article] => Array (
[id] => 7
etc...
In order to use characters beyond the English alphabet and spaces in a column alias, the standard SQL means requires using double quotes (though MySQL supports using backticks IE: "`" too):
...,
IF(CHAR_LENGTH(Article.content)>2000,
RPAD(LEFT(Article.content,2000),2003,'.'),
Article.content) AS "Article.content",
...
no you cant use a as [tablename].[columnname]-like format for custom column names.
It would be weird anyway if it would work, because how can content be defined as 'Article.content' if it's not really part of the Article table dataset.
Just select the columns you need and join where needed.
But what's WHERE '1' = '1' doing in there? that will just evaluate to true as it is a boolean expression, but it won't affect your resultset.
But when I loop through the resultset
to assign the table name along with
the field using 'mysql_field_table',
the 'content' returns a table name of
nothing, while all others have their
correct table
Once you've done that magic on Article.content, to create the content field, it no longer belongs to the Article table. Rather, it belongs to the result set of that query. I believe that's the explanation for having no table associated with that field.
Imagine a GROUP BY query, with something like COUNT(*) as number. 'number' doesn't belong to any table.
If you really need the ability to know that the column had a particular source, could you have a view on top of Article which does this manipulation to content? Then the source would appear to be the view? Unfortunately, MySQL doesn't support declared computed columns in tables, that might also be useful to you in this case.
while ($row = mysql_fetch_row($this->_result)) {
$prev_table;
for ($i = 0;$i < $numOfFields; ++$i) {
if ($table[$i] == "") {
$tempResults[$prev_table][$field[$i]] = $row[$i];
}else {
$tempResults[$table[$i]][$field[$i]] = $row[$i];
}
$prev_table = $table[$i];
}
}
Oh well, mysql couldnt do what I wanted. I added the prev_table to take the one before ;)
Thanks to everyone for the help.