I have two tables, users, and comments.
Users:
id - name - email
comments:
user_id - comment - rating
I am trying to get all the comments for every user, but then put them into an array of this sort of structure.
array(
'john' => array(
'comment' => array(
'text' => "had a great time thanks",
'rating' => 5,
)
'comment' => array(
'text' => "awesome",
'rating' => 5,
)
)
'amy' => array(
'comment' => array(
'text' => "it was ok",
'rating' => 3,
)
'comment' => array(
'text' => "awesome",
'rating' => 3,
)
)
)
Is this possible with one sql statement? Here is my code so far
//get the comments
$stmt = $con->prepare('SELECT c.comment,
c.rating,
u.username
FROM comments c
INNER JOIN users u
ON c.customer_id = u.id');
$stmt->execute();
$result = $stmt->get_result();
$comments = array();
while($row = $result->fetch_assoc()){
$comments[] = array(
'comment' => $row['comment'],
'rating' => $row['rating'],
'username' => $row['username']
);
}
I cant think of the best way to get this structure
Each key of an array must be unique so you cannot have multiple comment keys at the same level in your array.
This may be what you need:
$comment[$row['username']][] = array(
'comment' => $row['comment'],
'rating' => $row['rating'],
);
Related
$users = $this->db->query("SELECT * FROM `users`)->rows();
$rootUser = $this->db->query("SELECT * FROM `users` WHERE id = 1")->row();
the output array is:
array(
[0] => array(
'id' => 1,
'login' => 'test1',
'parent_id' => 0
),
[1] => array(
'id' => 2,
'login' => 'test2',
'parent_id' => 1
),
[2] => array(
'id' => 3,
'login' => 'test3',
'parent_id' => 2
)
)
How can I select all the nodes starting from the root node, using php, without mysql joins beacuse they have limit as far as I know only 61 joins is allowed,
Can you explain your question little more?
Otherwise if you mean to select only root nodes, then you can use sql below:
SELECT * FROM `users` WHERE parent_id=0
I have a rather complex query, that I'm using CSqlDataProvider with:
$sql = "
SELECT c.id AS id,
c.enabled AS enabled,
s.store_name AS store_name,
s.store_url AS store_url,
c.verified AS verified,
r.rating_total AS rating
FROM compete_settings c
LEFT JOIN stores s
ON c.compete_id = s.id
LEFT JOIN (
(SELECT store_id, rating_total FROM amazon_sellers)
UNION
(SELECT store_id, rating_total FROM ebay_sellers)
) AS r
ON c.compete_id = r.store_id
WHERE c.store_id = :store_id
";
$itemCount = Yii::app()->db->createCommand("SELECT COUNT(id) FROM compete_settings WHERE store_id = $store_id")->queryScalar();
return new CSqlDataProvider($sql, array(
'totalItemCount' => $itemCount,
'params' => array(
'store_id' => $store_id,
),
'sort' => array(
'attributes' => array ( 'enabled, store_name, rating' ),
'defaultOrder' => array('store_name'=>false)
),
'pagination' => array('pageSize' => Yii::app()->user->getState('pageSize_cs', Yii::app()->params['defaultPageSize']),),
));
The query works great. However, the columns are not sortable.
I've made sure to follow Yii CGridview sorting with CSqlDataProvider, but they are still not clickable column headers.
Here are my column arrays:
'columns' => array(
array(
'header' => 'Enabled',
'type'=>'raw',
'name'=>'enabled',
'htmlOptions'=>array('class'=>'enabled-column'),
'value' => 'CHtml::checkbox("", $data["enabled"], array("id"=>"c{$data[\'id\']}", "class"=>"enable-switch"))',
),
array(
'header' => 'Name',
'htmlOptions' => array('class' => 'account-name-column'),
'type' => 'raw',
'name'=>'store_name',
),
array(
'header' => 'Store Rating',
'name'=>'rating',
),
),
Help? ):
Turns out unlike what was mentioned in the question I followed, Yii accepts the attributes param as an array of values and not an array with one CSV value.
So:
'sort' => array(
'attributes' => array ( 'enabled', 'store_name', 'rating' ),
'defaultOrder' => array('store_name'=>false)
),
And not:
'sort' => array(
'attributes' => array ( 'enabled, store_name, rating' ),
'defaultOrder' => array('store_name'=>false)
),
I've been trying to figure out how to add some computed fields to a model in CakePHP. I'm able to achieve the desired result with the following query:
SELECT project_id,
COUNT(*) AS clicks_total,
SUM(CASE WHEN clicks.redirect_url = projects.url THEN 1 ELSE 0 END) AS clicks_redirected,
SUM(CASE WHEN clicks.redirect_url = projects.url THEN 0 ELSE 1 END) AS clicks_not_redirected
FROM clicks
LEFT JOIN projects ON clicks.project_id = projects.id
GROUP BY project_id
If I attempt to execute it as a custom query Cake transforms the result in such a way that it would require much array manipulation to be usable. I tried to do it the Cake way with the following code, but for some reason the calculated fields end up in a separate array which causes strange behavior in the view:
$this->paginate = array(
'Project' => array(
'fields' => array(
'id', 'name', 'url', 'url_mac', 'url_mobile',
'COUNT(*) AS clicks_total',
'SUM(CASE WHEN Click.redirect_url = Project.url THEN 1 ELSE 0 END) AS clicks_redirected',
'SUM(CASE WHEN Click.redirect_url = Project.url THEN 0 ELSE 1 END) AS clicks_not_redirected'
),
'joins' => array(
array(
'table' => 'clicks',
'alias' => 'Click',
'type' => 'LEFT',
'conditions' => array('Click.project_id = Project.id')
)
),
'group' => 'project_id'
));
$this->set('projects', $this->paginate());
Produces the following result:
array(
(int) 0 => array(
'Project' => array(
'id' => '508705c8-126c-48f9-bd9a-6d79d13bb9ea',
'name' => 'Test Project',
'url' => 'http://www.test.com',
'url_mac' => 'http://www.mac.com',
'url_mobile' => 'http://www.mobile.com'
),
(int) 0 => array(
'clicks_total' => '80',
'clicks_redirected' => '35',
'clicks_not_redirected' => '45'
)
),
(int) 1 => array(
'Project' => array(
'id' => '508b1073-2aa8-4895-b8d9-152ed13bb9ea',
'name' => 'Another Project',
'url' => 'http://another.com',
'url_mac' => 'http://anothermac.com',
'url_mobile' => 'http://anothermobile.com'
),
(int) 0 => array(
'clicks_total' => '134',
'clicks_redirected' => '70',
'clicks_not_redirected' => '64'
)
)
)
Does anyone have any ideas for getting the calculated click counts to show up under the Project array?
You can add virtual fields to your model:
Check it out: http://book.cakephp.org/1.3/view/1608/Virtual-fields
In Project model:
public $virtualFields = array('clicks_total' => 'COUNT(*)');
I am working on a web application and would like to improve my code a little bit.
This is the SQL table structure I made for the application:
Now my question: Is there an easy way in PHP to select (with join or whatever?) the information from one specific event_id on all tables and save them in an array with followed structure for example:
$events = array(
'event_id' => 1,
'event_name' => '{"de":"Weltwirtschaftsforum","fr":"Forum \u00e9conomique mondial","it":"Forum Economico Mondiale"}',
'event_description' => '{"de":"Description DE","fr":"Description FR","it":"Description IT"}',
'event_lastedit' => 2011-12-01 10:23:35,
'locations' => array(
array(
'location_id' => 1,
'location_name' => 'Bern',
'location_date' => '01.01.2012',
'location_deadline' => 1323340607,
'timestamps' => array(
array(
'timestamp_id' => 1,
'timestamp_time' => '10:30',
'timestamp_seats' => 30
),
array(
'timestamp_id' => 2,
'timestamp_time' => '16:30',
'timestamp_seats' => 40
)
)
),
array(
'location_id' => 2,
'location_name' => 'Davos',
'location_date' => '02.02.2012',
'location_deadline' => 1323340607,
'timestamps' => array(
array(
'timestamp_id' => 3,
'timestamp_time' => '12:30',
'timestamp_seats' => 50
),
array(
'timestamp_id' => 4,
'timestamp_time' => '15:30',
'timestamp_seats' => 60
)
)
)
)
);
I hope the question is clear enough.
Greetings
Spinne
Edit:
What i did so far:
$event = $event_db->querySingle("SELECT * FROM rf_events WHERE event_id={$event_id}", true)
$rf_locations = $event_db->query("SELECT * FROM rf_locations WHERE event_id={$event_id}");
$locations = array();
$timestamps = array();
$counter = 0;
// Loop sql query result and save entries in $events array.
while ( $row = $rf_locations->fetchArray() ){
$locations[$counter] = array(
'location_id' => $row['location_id'],
'location_name' => json_decode($row['location_name'], true),
'location_date' => $row['location_date'],
'location_deadline' => $row['location_deadline']
);
$rf_timestamps = $event_db->query("SELECT * FROM rf_timestamps WHERE location_id={$row['location_id']}");
$counter2 = 0;
while ( $row2 = $rf_timestamps->fetchArray() ){
$locations[$counter]['timestamps'][$counter2] = array(
'timestamp_id' => $row2['timestamp_id'],
'timestamp_time' => $row2['timestamp_time'],
'timestamp_seats' => $row2['timestamp_seats']
);
$counter2++;
}
$counter++;
}
SELECT * FROM rf_events, rf_locations, rf_timestamps WHERE
rf_locations.event_id = rf_events.event_id AND
rf_timestamps.location_id = rf_locations.event_id
Then, use add the data into php accordingly.
You can refer to: MYSQL JOIN
As the title says, I'm having troubles with joins in my find-query, with errors appearing like:
preg_match() expects parameter 2 to be string, array given [CORE/cake/libs/model/behaviors/containable.php, line 301]
I've tried adding joins to the array over there, but it didn't change anything.
These are the options I'm passing to the find method.
$options = array(
'contain' => array(
'Answer' => array(
'conditions' => array('Answer.type' => 'answer'),
'joins' => array(
$this->votesJoin()
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'joins' => array(
$this->votesJoin()
)
)
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'joins' => array(
$this->votesJoin()
)
),
'User',
'Tag' => array()
),
'joins' => array(
$this->votesJoin()
),
'conditions' => array(
'Question.id' => $id
)
);
return $this->find('first', $options);
with votesJoin() returning the following array.
(
[table] => (SELECT Vote.node_id, SUM(value) as total FROM votes AS `Vote` WHERE 1 = 1 GROUP BY `Vote`.`node_id` )
[alias] => Vote
[conditions] => Vote.node_id = Question.id
)
What I'm trying to do:
Each user can up/downvote a node (question/answer/comment). With the join I'm trying to add the sum of those votes.
database http://github.com/navale/QA/wiki/img/datamodel.png
You should use "joins" only for things that can't be done with Cake model relationship and Containable. I don't know the details of your database, but I think the find operation can be simplified. Why don't you post the schema for these tables on here?
try this:
$options = array(
'contain' => array(
'Answer' => array(
'conditions' => array('Answer.type' => 'answer'),
'Vote' => array(
'fields' => array('SUM(Vote.value)'),
'group' => array('Vote.parent_id')
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'Vote' => array(
'fields' => array('SUM(Vote.value)'),
'group' => array('Vote.parent_id')
)
)
),
'Comment' => array(
'conditions' => array('Comment.type' => 'comment'),
'Vote' => array(
'fields' => array('SUM(Vote.value)'),
'group' => array('Vote.parent_id')
)
),
'User',
'Tag' => array()
),
'conditions' => array(
'Question.id' => $id
)
);
You get the Vote sum value for each answer, comment, and comment for answer. (You might need to add 'hasMany' Vote in the Node model if you haven't done that yet)
If instead you want to get one single total sum of Vote for the question, then I'd suggest:
get the list of the answers and comments of the question:
$lvl1 = find('list','fields'=>array('id'),'conditions'=>array('Node.parent_id'=>$id))
then get list of the comments of the answers
$lvl2 = find('list','fields'=>array('id'),'conditions'=>array('Node.parent_id'=>$lvl1))
then just combine the 2 array then do a sum over that.