So, there's the User model, and the Item model. It's a many-to-many relation: an item can belong to many users, and a user can have many items. Therefore, there's the UserItemRel model.
To summarize:
item
id
name
date_created
date_updated
user
id
email
password
date_created
date_updated
user_item_rel
user_id
item_id
date_created
My query, before making the switch to Yii2, was this:
SELECT COUNT(UIR.`user_id`) as `favourited`, IT.`id`, IT.`name`, CA.`name` as `category`
FROM `user_item_rel` UIR
LEFT JOIN `item` IT ON UIR.`item_id` = IT.`id`
LEFT JOIN `category_item` CI ON UIR.`item_id` = CI.`item_id`
LEFT JOIN `category` CA ON CI.`category_id` = CA.`id`
WHERE UIR.`date_created` >= (SYSDATE() - INTERVAL 3 YEAR)
GROUP BY UIR.`item_id`
ORDER BY
`favourited` DESC
LIMIT 20
I've used the yii2-enhanced-gii extension to generate the models.
I want to show the 20 most favourited items in the past 48 hours, with their counts. I'm migrating from Yii1.1, and it's been quite the ride so far, and I can't figure this out.
I've found
$this->hasMany(UserItemRel::className(), ['id' => 'user_id'])
->viaTable('user_item_rel', ['id' => 'item_id'], function ($query) {
$query->andWhere(['date_created < INTERVAL 2 DAY'])
->orderBy(['COUNT(*)' => SORT_DESC]);
});
}
but how to properly use this?
The query would something like bellow. I would try to run a native query instead of trying to find out how this could be done withing the orm.
SELECT item_id, item.name, count(*) favorite
FROM user_item_rel
LEFT JOIN user ON user.id = user_item_rel.user_id
LEFT JOIN item ON item.id = user_item_rel.item_id
WHERE user_item_rel.date_created >= (sysdate() - interval 2 DAY)
GROUP BY item_id, name
ORDER BY favorite DESC
LIMIT 20
You might be able to try something like this:
$items = UserItemRel::find()
->asArray()
->select("COUNT(`user_id`) as favourited, `item_id`")
->groupBy("item_id")
->joinWith("item")
->orderBy("favourited DESC")
->indexBy("item_id")
->where("'date_created' >= '".date("Y-m-d", strtotime("-2 days"))."'")
->limit(3)
->all();
In my testing it gives me something like this:
Array
(
[1] => Array
(
[favourited] => 4
[item_id] => 1
[item] => Array
(
[id] => 1
[name] => Donec
[date_created] => 2015-08-26
[date_updated] => 2015-08-26
)
)
[8] => Array
(
[favourited] => 3
[item_id] => 8
[item] => Array
(
[id] => 8
[name] => Tellus
[date_created] => 2015-08-26
[date_updated] => 2015-08-26
)
)
[7] => Array
(
[favourited] => 2
[item_id] => 7
[item] => Array
(
[id] => 7
[name] => Mollis
[date_created] => 2015-08-26
[date_updated] => 2015-08-26
)
)
)
Related
I have query like this,
SELECT * FROM users ORDER BY score
So, the result is like this.
Array
(
[0] => stdClass Object
(
[userid] => 3
[user] => John Doe
[score] => 50
)
[1] => stdClass Object
(
[userid] => 1
[user] => Mae Smith
[score] => 38
)
[2] => stdClass Object
(
[userid] => 2
[user] => Mark Sam
[score] => 26
)
)
But, I want to add a rank using find_in_set query. So the result might be like this. So that the user can view their ranks when they login to their account.
Array
(
[0] => stdClass Object
(
[userid] => 3
[user] => John Doe
[score] => 50
[rank] => 1
)
[1] => stdClass Object
(
[userid] => 1
[user] => Mae Smith
[score] => 38
[rank] => 2
)
[2] => stdClass Object
(
[userid] => 2
[user] => Mark Sam
[score] => 26
[rank] => 3
)
)
I tried this one.
$listOfUser = array();
foreach($users as $user) {
$listOfUser[] = $user->userid;
}
And used another query
$userid = 2 // => id of loggedin user
SELECT *, find_in_set($userid, $listOfUser) as rank FROM users where userid=$userid ORDER BY score
So, I got this result
Array
(
[1] => stdClass Object
(
[userid] => 2
[user] => Mark Sam
[score] => 26
[rank] => 3
)
)
Which is somehow correct. But, is there another way of querying that result using only one SQL query and without using foreach loop?
Something like this.
$userid = 2 // => id of loggedin user
SELECT *, find_in_set($userid, (SELECT * FROM users ORDER BY score)) as rank FROM users where userid=$userid ORDER BY score
But I got this error Subquery returns more than 1 row
If You don't insist on using find_in_set, you can get result with simple join. You ask for list of users (p) and for each user you ask, how many users have better score than him or her (c):
SELECT p.userid, COUNT(c.userid) AS rank
FROM users AS p
LEFT JOIN users AS c ON c.score > p.score
GROUP BY p.userid
This works even if you add other conditions, like WHERE p.userid = 123.
If more users have the same score, the ranks would look like 0,1,2,2,2,5,6.
In your query, you can add counter, like this:
set #n:=0;
SELECT #i := #i + 1 AS rank, * FROM users ORDER BY score
The rank here is relative to the score distribution across all users. I believe you should try something originally proposed in this answer:
SELECT users.*,
#rownum := #rownum + 1 as rank
FROM users
CROSS JOIN (select #rownum := 0) r
ORDER BY score DESC
What it does is basically order all users by score, and assign each of them an incremental value "rank". So the top scorer would have a rank of 1, the second scorer would have a rank of 2 etc.
Keep in mind that this solution is not "fair" - each user will have a different rank, even if all users have the same score. If you try to rank users as they do in sports (if two top competitors have the same score, they both take 1st place, and the next best competitor takes 3rd place, not second), you should think of a different solution.
I am trying to display ALL blogs regardless of whether there are comments associated with it or not BUT I have 1 problem as these are as follows:
Not all fields from the COMMENTS TABLE and ENTRY TABLE are displayed (seems like if there is a duplicate field name it is not displayed, however, as you can see, I use the full field names eg. tablename.fieldname)
Here is my MODEL:
class A_User_Blog_Comments_model extends CI_Model {
public function get_blog($id) {
$this->db->select('
entry.user_id,
entry.entry_id,
entry.entry_name,
entry.entry_body,
entry.status,
entry.created_timestamp,
entry.updated_timestamp,
comments.id,
comments.comment,
comments.user_id,
comments.blog_id,
comments.status,
comments.created_timestamp,
comments.updated_timestamp
');
$this->db->from('entry');
$this->db->join('comments', 'entry.entry_id=comments.blog_id', 'left');
$this->db->where('entry.entry_id',$id);
$query = $this->db->get();
if($query->num_rows() != 0)
{
return $query->result_array();
}
else
{
return false;
}
}
Here is a simple dump in my view file:
Array
(
[0] => Array
(
[user_id] => 1
[entry_id] => 1
[entry_name] => twkla nnn xxx
[entry_body] => this is just UPDATED
[status] => active
[created_timestamp] => 2017-01-03 00:00:00
[updated_timestamp] => 2017-01-04 00:00:00
[id] => 1
[comment] => This is a comment
[blog_id] => 1
)
[1] => Array
(
[user_id] => 1
[entry_id] => 1
[entry_name] => twkla nnn xxx
[entry_body] => this is just UPDATED
[status] => active
[created_timestamp] => 2016-12-04 00:00:00
[updated_timestamp] => 2017-01-03 00:00:00
[id] => 2
[comment] => This is another comments
[blog_id] => 1
)
)
But, as you can see, there are MANY fields missing from the view because this is the SQL that was executed:
SELECT `entry`.`user_id` , `entry`.`entry_id` , `entry`.`entry_name` ,
`entry`.`entry_body` , `entry`.`status` , `entry`.`created_timestamp` ,
`entry`.`updated_timestamp` , `comments`.`id` , `comments`.`comment` ,
`comments`.`user_id` , `comments`.`blog_id` , `comments`.`status` ,
`comments`.`created_timestamp` , `comments`.`updated_timestamp`
FROM `entry`
LEFT JOIN `comments` ON `entry`.`entry_id` = `comments`.`blog_id`
WHERE `entry`.`entry_id` =1
Why are all the fields displaying?
You have same column names in "entry" table as well as "comments" like user_id,status and etc.. which has same column name then the main table values will be returned. Just create alias for the matching columns liek below.
comments.user_id as cuser_id, comments.status as cstatus
Replace your select statement with this.
$this->db->select('
entry.user_id as euid,
entry.entry_id,
entry.entry_name,
entry.entry_body,
entry.status as entry_status ,
entry.created_timestamp as entry_addtime,
entry.updated_timestamp as entry_updatetime,
comments.id as comments_id,
comments.comment,
comments.user_id as comments_userID,
comments.blog_id,
comments.status as comments_status,
comments.created_timestamp as comments_addtime,
comments.updated_timestamp as comments_addtime
');
I am using corequery of mysql in cakephp. I want the records in descending order. This is my table structure
enter code here
$coreQueryUser = $this->Message->query(
"select * from messages where messages.list_id = 3
group By (if(sender_id > reciever_id, sender_id, reciever_id)),
(if(sender_id > reciever_id, reciever_id, sender_id))
order by id desc
"
);
I want last message that belongs to (sender_id and reciver_id and viceversa) that belongs to list id 3
when i run this query i get the following output
<pre>Array
(
[0] => Array
(
[messages] => Array
(
[id] => 1
[sender_id] => 21
[reciever_id] => 10
[list_id] => 3
[message] => hello
[add_date] => 2016-09-25 00:00:00
[is_check] => 0
)
)
[1] => Array
(
[messages] => Array
(
[id] => 3
[sender_id] => 22
[reciever_id] => 10
[list_id] => 3
[message] => hello s
[add_date] => 2016-09-25 16:39:41
[is_check] => 0
)
)
)
but i wnat result like that:
Array
(
[0] => Array
(
[messages] => Array
(
[id] => 2
[sender_id] => 10
[reciever_id] => 21
[list_id] => 3
[message] => hello sir
[add_date] => 2016-09-25 00:00:00
[is_check] => 0
)
)
[1] => Array
(
[messages] => Array
(
[id] => 6
[sender_id] => 22
[reciever_id] => 10
[list_id] => 3
[message] => new
[add_date] => 2016-09-25 16:39:41
[is_check] => 0
)
)
)
Can anyone help me :(
The problem is that your query is against the sql standard because you have several fields in the select list that are neither in the group by list, nor are subject of an aggregate function, such as sum(). MySQL unfortunately allows such invalid queries to run under certain sql mode settings (the default settings of the most recent versions of MySQL would prevent such queries from running).
As MySQL documentation on group by clause says (bolding is mine):
If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard
SQL use of GROUP BY permits the select list, HAVING condition, or
ORDER BY list to refer to nonaggregated columns even if the columns
are not functionally dependent on GROUP BY columns. This causes MySQL
to accept the preceding query. In this case, the server is free to
choose any value from each group, so unless they are the same, the
values chosen are indeterminate, which is probably not what you want.
Furthermore, the selection of values from each group cannot be
influenced by adding an ORDER BY clause. Result set sorting occurs
after values have been chosen, and ORDER BY does not affect which
value within each group the server chooses.
You apparently want the latest record (with max(id) for each group. The proper way is to have a subquery that returns the max(id) per group and in the outer query join back to your main table using the ids to get the value of the other fields:
select m.*
from
messages m
inner join (
select max(id) as maxid
from messages
where messages.list_id = 3
group By (if(sender_id > reciever_id, sender_id, reciever_id)),
(if(sender_id > reciever_id, reciever_id, sender_id))
) t1 on m.id=t1.maxid
This code working:
SELECT * FROM generate_invoice
WHERE id IN
(
SELECT max(id) as id
FROM generate_invoice
GROUP by pay_id
ORDER by id DESC
)
How to group by DESC order
Try
SELECT * FROM ( SELECT * FROM generate_invoice ORDER BY id DESC ) AS g GROUP BY g.pay_id
OR
Use this code
SELECT m1.*,m2.* FROM generate_invoice m1 LEFT JOIN generate_invoice m2 ON (m1.pay_id = m2.pay_id AND m1.id < m2.id ) order by m1.id desc
I have array below and I need to update database according to this.
It should be something like example code below but I don't know how to do it correctly:
UPDATE productPercent SET percent="$percent" WHERE
store="$store" AND
startDate>"$start_date" AND
endDate<"$end_date" AND
storeGroup="$storeGroup" AND
productGroup="$product_group" AND
productName LIKE '$search%'
I need to check for each store, store group, product (if contains word) and product group and then update productPercent table. Percent, product group, store group, product name and store are in different tables so some kind of inner join is needed.
I need some directions regarding this because I don't know how to start, thank you.
Array
(
[percent] => 3
[store] => Array
(
[0] => 36
[1] => 45
[2] => 56
)
[start_date] => 2015-02-09
[end_date] => 2015-03-31
[storeGroup] => Array
(
[0] => 2
[1] => 4
)
[product_group] => Array
(
[0] => 13
[1] => 31
[2] => 32
)
[search] => iphone
[setPercent] => Submit
)
UPDATED: data model - tableName: columns(connected tables)
store: id,name,startDate,endDate
storeGroup: id,storeGroupID(in table storeGroupName: id,name),storeID
productGroup: id,productID(in table productName: id,name),groupID(in table productGroupName: id,name)
productName: id,name
productPercent: id,productID,storeID,percent
$pdoHandle = $this->getPDOHandle();
$searchword = 'iphone';
$sql = "UPDATE
productPercent
inner join store on productPercent.storeID=store.id
inner join storeGroup on storeGroup.storeID=store.id
inner join productGroup on productGroup.id=storeGroup.groupID
inner join productName on productPercent.productID=productName.id and productGroup.productID=productName.id
SET percent=:percent
WHERE productName.name like :searchword";
$pdo->prepare($sql);
$pdo->setAttribute('percent', floatval($percent/100));
$pdo->setAttribute('searchword', $searchword . '%');
With a big Thanks to others here i get this query now. its working fine, but i would need to get just the highest value of the post_id (how_many). it seems not possible to set a MAX(count(*)) on that. so how could i change this to get only the highest count by every id? i just need the value of every id where count == highest. how could i do this? thanks for any help.
$test = $wpdb->get_results('select
posts_id, value,count(*) as how_many
From wp_mrp_rating_item_entry_value
group by
posts_id, value
order by count(*) desc');
echo '<pre>';
print_r($test);
echo '</pre>';
i would need something like order by MAX((count(*)) or MAX((count(how_many))
i already read this but i dont know how to use this for my purpose Filtering log file using COUNT, GROUP BY, ORDER BY MAX
this is an example of the output i get now. so number 1 should not appear because number [0] has been voted 2 times. (how_many). i just need every id 1x in the output. no id shouldt appear twice or more. cause just the highest count is needed. thanks and sorry for the bad english.
Array
(
[0] => stdClass Object
(
[posts_id] => 336
[value] => 8
[how_many] => 2
)
[1] => stdClass Object
(
[posts_id] => 336
[value] => 7
[how_many] => 1
)
[2] => stdClass Object
(
[posts_id] => 380
[value] => 5
[how_many] => 1
)
[3] => stdClass Object
(
[posts_id] => 378
[value] => 7
[how_many] => 1
)
[4] => stdClass Object
(
[posts_id] => 329
[value] => 2
[how_many] => 1
)
[5] => stdClass Object
(
[posts_id] => 327
[value] => 3
[how_many] => 1
)
)
You can filter the resulting groups in a HAVING clause based on a match against a subquery for the maximal count:
SELECT posts_id, value, COUNT(*) AS how_many
FROM wp_mrp_rating_item_entry_value t1
GROUP BY posts_id, value
HAVING how_many = (
SELECT COUNT(*)
FROM wp_mrp_rating_item_entry_value t2
WHERE t2.posts_id = t1.posts_id
GROUP BY t2.value
ORDER BY COUNT(*) DESC
LIMIT 1
)