I'm trying to count the number of rows in a relational table many to many, but always returns the wrong value. When it is 1, always returns 2.
PS: All models and foreign keys in mysql are configured correctly.
Comments Table:
id | name
10 Comment Test
Users Table:
id | name
20 User Test
Likes (Comment/User) Many to Many:
user_id | comment_id
20 10
Code:
$criteria = new CDbCriteria;
$criteria->select='*, COUNT(likes.id) AS count_likes'; // I believe the error is in the use of COUNT (likes.id).
$criteria->with=array('likes'=>array('on'=>'user_id=20'));
$model = Comments::model()->findByPk($_GET['id'], $criteria);
// Return Wrong Value
echo $model->count_likes; // Return 2 where should be 1. (I need to use this case)
echo count($model->likes); // Return right value 1.
You should use Statistical Query, e.g. :
In your Comments model :
public function relations()
{
return array(
// ...
// I assume your relation table's name is "likes"
'likes'=>array(self::MANY_MANY, 'Users', 'likes(comment_id, user_id)'),
'likesCount'=>array(self::STAT, 'Users', 'likes(comment_id, user_id)'),
// ...
);
}
Are you planning on selecting from the LIKES table and group by them by their userid and comment id?
If so, you can use GROUP BY
Please take a look at the SQLFiddle here
http://sqlfiddle.com/#!2/bc29b8/1/0
SELECT uid, cid, COUNT(likes.cid) FROM likes GROUP BY uid, cid
Related
I have 4 tables vendors, project,project_quotas and project_vendors
Table Structures:
vendors: id (Primary), name, email
project: id (Primary), name, status
project_quotas: quota_id (Primary), project_id (Foreign Key), quota_name, description
project_vendors: pv_id (Primary), project_id(Foreign Key), vendor_id, spec_quota_ids(comma separated, Foreign Keys), description
Lets Say For project_id = 1
I want to fetch All Project Quotas and their Project Vendors
here is Raw query I have created to get this data:
SELECT
pq.id as pq_id, pq.project_id as project_id, pq.name as pq_name, pv.id as pv_id, pv.vendor_id as pv_vendor_id, pv.spec_quota_ids as quotas
FROM `project_quotas` pq
LEFT JOIN
project_vendors pv ON pv.project_id = 1 AND find_in_set(pq.id, spec_quota_ids) > 0
WHERE pq.project_id = 1
GROUP BY pv.vendor_id, find_in_set(pq.id, spec_quota_ids)
Order BY pq.id
Here is the output
The only issue is that I want this query to Run Eloquent way.
I have ProjectQuota, ProjectVendors Model
I want something like
$data = ProjectQuota::where('project_id', '=', '1')->with('projectVendors', 'projectVendors.Source')->get();
I don't know how can I create a conditional hasManyrelationship in eloquent, will appreciate the help.
I this is the way to do this.
if($this->project_id===2) {
return $this->belongsTo(Foo::class);
}
if($this->project_id===3) {
return $this->belongsTo(Bar::class);
}
I am trying to count the record with the same group in a table. I know this is attainable easily with a query and yes I already done it but I am thinking of the proper way to place the count on main models and search models.
The database looks like this:
Device
----------------------------
id name group_id
1 Phone Sony 2
2 Computer 1
3 Printer 1
4 Phone LG 1
Group
----------------------------
id name
1 Home
2 Office
OUTPUT TABLE:
Group Name Device Count
Home 1
Office 3
I have done this by doing a query on the controller.
SELECT COUNT( * )
FROM `hosts`
WHERE group_id = *~DESIRED NUMBER HERE~*
I am looking for a better approach. I am new to SQL and I think joining tables is the proper way to do this but I am still not very sure.
Under GroupSearch model I will add this:
$dataProvider->setSort(['attributes' => [
'devicecount' => [
'asc' => [ 'devicecount' => SORT_ASC ],
'desc' => [ 'devicecount' => SORT_DESC ],
],
]
]);
Since devicecount is not available in the tables it will show an error. Where should I put the counting of the same store_id? Under Device model or under Group model? How will I be able to sort them also?
There is an example of handling this kind of situations in official guide.
Example of model:
class Group extends \yii\db\ActiveRecord
{
public $devicesCount;
// ...
public function getDevices()
{
return $this->hasMany(Device::className(), ['group_id' => 'id']);
}
}
Example of query:
$customers = Group::find()
->select([
'{{group}}.*', // select all customer fields
'COUNT({{device}}.id) AS ordersCount' // calculate orders count
])
->joinWith('devices') // ensure table junction
->groupBy('{{group}}.id') // group the result to ensure aggregation function works
->all();
where {{group}} and {{device}} - table names for groups and devices accordingly, or you can use Group::tableName() and Device::tableName() for better code maintaining.
Then because you added count as model property, you will be able to sort results by this column.
I have a messages table.
+----+---------+----------+
| id | conv_id | body |
+----+---------+----------+
| 1 | 1 | haha |
| 2 | 1 | blabl|
| ...| ... | ... |
| 25| 2 | hehe |
+----+---------+----------+
... = rest of messages with conv_id of 2's or 1's or 3's or n's.
Let's say I have conv_id = array(2,1) and I want to obtain 10 messages after matched with an array of ids in conv_id so I did
select * from `messages` where `conv_id` in (2, 1) order by `created_at` desc limit 10
The sql above gave me 10 messages after matching both conv_ids and getting all combined messages. However, this is NOT what I wanted. Instead, I wanted 10 messages of EACH conv_id matched.
How do I get 10 messages of EACH conv_id matched? No PHP for loop, please. Thank you!
NOTE : the array conv_id can easily be extended to include many other values unique to each other, not only 2s or 1s.
P.s., bonus points for Laravel Eloquent answer! Here are the details :
Two models, Conversations and Messages linked by Conversations hasMany Message and Message belongsTo a Conversation.
My sql above was translated from Messages::with('User')->whereIn('conv_id',$conv_id)->orderBy('created_at','desc')->take(10);
I think Jared is right but if you can add another column to the table, solution would be more efficient. Add a column which indicates message number for each conv_id (earliest will have 1 and the latest will have number of messages conversation have). After that, you can achieve your goal by scanning table twice with HAVING clause.
SELECT * FROM messages JOIN
(SELECT conv_id, MAX(msg_no) FROM messages WHERE conv_id IN (2,1) GROUP BY conv_id) as M
ON messages.conv_id=M.conv_id HAVING messages.msg_no > M.msg_no-10
Another possibility. Get last conv_ids and their 10th (message)id with a group_concat - substring_index trick and re-join of message-table.
SELECT `messages`.*
FROM (
SELECT
conv_id,
substring_index(
substring_index(
group_concat(`messages`.id),
',',
10
),
',',
-1
) AS lastMessageId
FROM `messages`
WHERE `conv_id` in (2, 1)
GROUP BY `conv_id`
) AS msub
INNER JOIN `messages` ON `messages`.conv_id = msub.conv_id AND `messages`.id <= msub.lastMessageId
Warning: This approach is potentially wrong. I'm trying to validate it and will update it once I reach a conclusion
Yesterday I just learnt something new about Eloquent relationship from an answer by deczo in Getting just the latest value on a joined table with Eloquent. And I think we can adapt it to your case as well.
What you're essentially trying to do, I put in my view as:
A Conversation model that has many Messages.
But I want only 10 latest messages per each conversation. All come eager-loaded.
In Eloquent, I would probably do something along the line of:
Conversation::with('messages')->whereIn('conv_id', [1, 2])->get();
But two things I note of your question.
I assume you don't have another table called conversations.
The code above does not limit to how many messages per conversation.
So I decided that here should be two models, one called Message, another called Conversation.
Both call to the same table, but we will tell Eloquent to use different columns as primary key.
So to get a Conversation model, I added a distinct() to my newQuery function, and select only conv_id out since that's the only information about a conversation.
So in the end I have this:
models/Message.php
class Message extends Eloquent
{
protected $table = 'messages';
protected $primaryKey = 'id';
public $timestamps = false;
}
models/Conversation.php
class Conversation extends Eloquent
{
protected $table = 'messages';
protected $primaryKey = 'conv_id';
public $timestamps = false;
public function newQuery($excludeDeleted = true)
{
return parent::newQuery()
->select('conv_id')
->distinct();
}
public function messages()
{
return $this->hasMany('Message', 'conv_id')
->orderBy('id', 'desc')
->take(10);
}
}
Now I can do:
Conversation::with('messages')->whereIn('conv_id', [1, 2])->get();
which gives me a list of conversations with conv_id 1 and 2, along with the 10 latest messages for each of them.
This is the first time I do something like this. So I code-tested and it works.
Update: The code in my answer perform these two queries only (retrieved from DB::getQueryLog()):
select distinct `conv_id` from `messages` where `conv_id` in (?, ?);
select * from `messages` where `messages`.`conv_id` in (?, ?) order by `id` desc limit 10;
I have 2 tables in a single database.
For example:
Table 1 Columns:
id | code | name
Table 2 Columns:
id | code | family | etc.
How can I query both tables based on the overlapping code column to retrieve family column?
This is what I currently have:
$query = $this->db
->select('*')
->from('table 1')
->where('code', '123');
$query->get()->result();
The above query will retrieve the row(s) with code 123 but I'd like to get the corresponding family data from table 2. How can I do this?
Use join(). Something like:
$query = $this->db
->select('*')
->from('table1')
->join('table2', 'table1.code = table2.code')
->where('code', '123');
Docs on the function are here: http://ellislab.com/codeigniter/user-guide/database/active_record.html#select
well you must add a sentence Join, it will let you query two tables.
$dataquery = array('table1.code' => '123'); //var in order to where
$this->db->select('table1.id As id1, table2.id As id2') //separate the ids with names
$this->db->join('table2.code','tabla1.code'); //code is overlapping
$query = $this->db->get_where('table1',$dataquery);
return $query->get()->result_array();//Return array if you want
Cheers!
I have a Database table in MYSQL, it looks like this:
Project_ID user_ID name
11 1 fred
11 2 rick
11 1 fred
I want to get the names in the table, but when I display it I get the same name twice because the user_ID 1 appears twice in the table. I tried to display it with GROUP BY and SUM, but I don't want to do it this way. How do I get it not to return duplicate rows?
Use DISTINCT
SELECT DISTINCT user_ID
, verschil_ma
FROM project_uren
WHERE project_ID = 11
GROUP BY user_ID
Point 1 is that should the user be assigned to the project twice?
Point 2 - Use the DISTINCT keyword to return only unique records - http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html
SELECT DISTINCT user_ID
FROM TABLE
WHERE Project_id = 11
That will return you 1 and 2 (You won't get 1 twice)
Thanks
$results = // query
$results = array_unique($results);