Yii2 select by max date? - mysql

Suppose I have table A with its active record in yii2, What is the best way to can load the record with max created date to the model.
This is the query :
select *
from A
where created_date = (
select max(created_date) from A
)
Now I am getting the max date first then use it in another access to database ie:
$max = A::find()->select("created_date)")->max();
$model = A::find()->where("created_date = :date",[":date"=>$max])->one();
I am sure that this can be done with one access to database , but I don't know how.
please any help.

Your query is the equivalent of:
SELECT * FROM A ORDER BY created_date DESC LIMIT 1;
You can order your records by created_date in descending order and get the first record i.e:
$model = A::find()->orderBy('created_date DESC')->limit(1)->one();
Why limit(1)? As pointed out by nicolascolman, according to the official Yii documentation:
Neither yii\db\ActiveRecord::findOne() nor yii\db\ActiveQuery::one() will add LIMIT 1 to the generated SQL statement. If your query may return many rows of data, you should call limit(1) explicitly to improve the performance, e.g., Customer::find()->limit(1)->one().

$maxdate=A::find()->max('created_date');

Try this
$model = A::find()->orderBy("created_date DESC")->one();

Related

How to count all records if use alias in select query?

I use Sphinx with Yii2 and need to query with filter by jSON field.
$query = new \yii\sphinx\Query();
$query->from('announcements');
$query->addSelect("*");
$query->addSelect(new Expression("IN(filters['color'], 'blue', 'red', 'green') AS f_color"));
$query->where("is_active = 1");
$query->andWhere("f_color = 1");
$announces = $query->all();
There is jSON field filters in my Sphinx index. For example:
[filters] => {"brand":"Toyota","model":"Prius","color":"red","price":"12000"... etc]
It works OK. But now I need to make a pagination... and there is a problem when I try to count records before $query->all()
$count = $query->count(); // Return error "no such filter attribute 'f_color'"
Generated query was:
SELECT COUNT(*) FROM announcements WHERE ( is_active = 1 ) AND ( f_color = 1 )
count() by default replaces the select part with * and this is where your alias is defined hence the error.
There are different ways to achieve it like:
use ActiveDataProvider like described here,
use META information like described here
Since you want to make a pagination I would go with the first example.

How can I "order by" only the LIMIT results in a mysql Query?

Hi I need to get the results and apply the order by only in the limited section. You know, when you apply order by you are ordering all the rows, what I want is to sort only the limited section, here is an example:
// all rows
SELECT * FROM users ORDER BY name
// partial 40 rows ordered "globally"
SELECT * FROM users ORDER BY name LIMIT 200,40
The solution is:
// partial 40 rows ordered "locally"
SELECT * FROM (SELECT * FROM users LIMIT 200,40) AS T ORDER BY name
This solution works well but there is a problem: I'm working with a Listview component that needs the TOTAL rows count in the table (using SQL_CALC_FOUND_ROWS). If I use this solution I cannot get this total count, I will get the limited section count (40).
I hope you will give me solution based on the query, for example something like: "ORDER BY LOCALLY"
Since you're using PHP, might as well make things simple, right? It is possible to do this in MySQL only, but why complicate things? (Also, placing less load on the MySQL server is always a good idea)
$result = db_query_function("SELECT SQL_CALC_FOUND_ROWS * FROM `users` LIMIT 200,40");
$users = array();
while($row = db_fetch_function($result)) $users[] = $row;
usort($users,function($a,$b) {return strnatcasecmp($a['name'],$b['name']);});
$totalcount = db_fetch_function(db_query_function("SELECT FOUND_ROWS() AS `count`"));
$totalcount = $totalcount['count'];
Note that I used made-up function names, to show that this is library-agnostic ;) Sub in your chosen functions.

Codeigniter - convert mysql query to CodeIgniter's active record query

I'm trying to convert this SQL query into a codeigniter query
SELECT
uploads.EMAIL
FROM
uploads
JOIN (
SELECT EMAIL, COUNT(*) as num FROM uploads GROUP BY EMAIL
) c ON uploads.EMAIL = c.EMAIL
ORDER BY
c.num DESC,
EMAIL ASC
Thanks for the help
kind regards
I am not sure why you can't figure this out yourself using the active record documentation, but:
$this->db->select('uploads.EMAIL');
$this->db->from('uploads');
$this->db->join('(SELECT EMAIL, COUNT(*) as num FROM uploads GROUP BY EMAIL) c','uploads.EMAIL = c.EMAIL','',FALSE);
$this->db->order_by('c.num desc, uploads.EMAIL asc');
and then
$query = $this->db->get();
FYI, passing FALSE as the fourth parameter to the db->join() method will cause it not to escape the statement, so you should be careful if you're going to take external variables. This is, until CodeIgniter 3, the only way to do subqueries with active record without extending the active record class to add them.

How to make a 1 column query by choosing from two columns mysql

I have a messaging system (very basic) that has a table like this:
**MESSAGE_ID** **RUSER_ID** **SUSER_ID** **MESSAGE_DATA** **DATE**
RUSER is the receiving user, and SUSER is the sending user. If I wanted to output a query that would output a certain users messages, I would currently do:
Select * from PRIVATE_MESG where RUSER_ID=$USER_ID or SUSER_ID=$USER_ID
That would give me all message_id's that are associated with that USER_ID. What I would like, is to create a column that would produce only the ID associated with RUSER_ID or SUSER_ID associated with a specific user. I need it to choose the messages that RUSER_ID or SUSER_ID are equal to a USER_ID but only display the one that isn't USER_ID
I would then like to do a group by the output of that query.
Any help is greatly appreciated!
Thanks!
update I am not really looking for a message_id, I am just looking for a list of users who that person has written to or received from.
UPDATE
Just so everyone knows, I recieved the answer to this question perfectly! I tweaked it later on so that it would also display them by date from newest to oldest. I did this by spliting the DATETIME into DATE and TIME USING the DATE() and TIME() Function. Here was my final query:
SELECT
IF(RUSER_ID = $USER, SUSER_ID, RUSER_ID) as THE_OTHER_GUY, DATE(DATE) as DAY, TIME(DATE) as TIME
FROM PRIVATE_MESG
WHERE RUSER_ID = $USER
OR SUSER_ID = $USER;
group by THE_OTHER_GUY ORDER BY DAY DESC, TIME DESC
Hope this helps the next person!
You can query:
SELECT
*,
IF(RUSER_ID = $USER_ID, SUSER_ID, RUSER_ID) as THE_OTHER_GUY
FROM PRIVATE_MESG
WHERE RUSER_ID = $USER_ID
OR SUSER_ID = $USER_ID;
SELECT SUSER_ID FROM PRIVATE_MESG WHERE RUSER_ID=$USER_ID
UNION
SELECT RUSER_ID FROM PRIVATE_MESG WHERE SUSER_ID=$USER_ID
It retrieves:
- the list of user IDs who sent messages to $USER_ID
- the list of user IDs who received messages from $USER_ID
And UNION groups the 2 lists in a single result set.

Cast function output as column name

I have come across a scenario where I need to "cast" the output of a function as the column name I want to select:
(SELECT
LOWER(DATE_FORMAT(NOW(), '%b'))
FROM lang_months
WHERE langRef = lang_statements.langRef
) AS month
Just returns the current month which is expected, but I want this to select the column called "may" in this case.
How would I do this?
Thanks, your answer gave me an idea. I just put the current date into a variable and used that in the query like so:
$thisMonth = strtolower(date('M')) ;
(SELECT
$thisMonth
FROM lang_months
WHERE langRef = lang_statements.langRef
) AS month
This is not possible. The name of an entity must be known when the query reaches MySQL.
The easiest option would probably be to determine the column name in whatever language you're using then to just use that. For example, in PHP:
$col = 'someAlias';
$query = "SELECT blah as `{$col}` FROM tbl";
I don't think this is possible.
You could create a view that offers this view on your data so you can they query it more expressively, but you're still going to have to write those 12 subqueries and aliases by hand.
This should work:
$month = LOWER(DATE_FORMAT(NOW(), '%b')); // Results in 'may'
$result = mysql_query('SELECT * FROM $month'); // Returns all records in table 'may'