OK, my problem is little bit specific and harder to explain. So I will try to simplify as much as possible.
I have MySQL table with "hints" that are beeing shown on website. These hints are ordered by int in column "order". So table looks like this: id(int autoincrement), hint (varchar), order(int).
Now when first hint is displayed to user, it is displayed until user acknowledges it and then next hint is displayed and so on.
I came up with query, which gets me next hint based on which hint specific user acknowledged last time:
SELECT hint FROM hints WHERE `order` > $last_seen_item_order ORDER BY `order` DESC LIMIT 1
This works fine. However we also need to add sometimes new hint and it's not usually added as the last hint but somewhere in between. So for example, user has seen last hint with order #6, but we added new hint at position e.g. #3. And it will never be displayed to this user, because we have saved for him that he has seen hint #6.
Is there a way how to manage this ? Possible with only by one or two MySQL queries ?
Thank you for any help and hints in advance.
EDIT: Each user has its own "seen-state". We keep that simply in PHP $_SESSION['last_seen_item_order']
You can't manage it by this logic.
For this, you need to maintain an extra column - seen
You can set this to 1 if the user have seen the hints
So your query would be -
SELECT
hint
FROM
hints
WHERE
`order` > last_seen_item_order
OR seen = 0
ORDER BY
CASE WHEN `order` > last_seen_item_order THEN `order` END DESC
CASE WHEN `order` <= last_seen_item_order THEN `id` END ASC
LIMIT 1
NOTE - This is my suggestion for doing that way.You can have number of ideas of doing it.
Edit -
If you want to maintain user wise hints, then you probably have 2 options to maintain seen.
Store user wise json for hints seen by user.
Make a separate table user_hints_see with columns id(Autoincrement), user_id, hint_id, seen.
i'm trying to make a chat site for learning purposes, so in the course of that, I want the last 30 messages appear in ascending order w.r.t. time. Like, latest messages at the bottom, oldest one at the top. After a huge amount of googling and yet having found no solution that could help, I had to ask this.
This is the MySQL statement.
It returns the data I want but in descending order. That is, latest ones at the top. Even if I change the ASC to DESC, nothing happens.
SELECT * FROM (SELECT msg,sender FROM chatlogs WHERE user1='userone' AND user2='usertwo' ORDER BY 'timeofmsg' DESC LIMIT 30) sub ORDER BY 'sub.timeofmsg' ASC
After a lot of testing and trying solutions out, I found out by myself that when I try to sort the resultant table using PHPMyAdmin's UI, it throws the following error. Turns out it's a MySQL bug of sorts. So how to I work my way around it?
1250 - Table 'sub' from one of the SELECTs cannot be used in global ORDER clause
If you can tell me how to print the query in reverse, even that would help. But no matter how you help, please do explain how your solution would work... I'm a beginner at this.
Your first issue is that you're trying to do an "order by" on a column that is not present in the table "sub". You'll need to return it in the alias:
SELECT * FROM (SELECT msg,sender, timeofmsg FROM chatlogs WHERE user1='userone' AND user2='usertwo' ORDER BY timeofmsg DESC LIMIT 30) sub ORDER BY sub.timeofmsg ASC
Query Error, you cannot use the query as you mentioned it is not possible.
I want to query my database using DQL and find out if there is any record in this table of mine wich collides with one that I'm about to insert, the thing is that I cannot insert records if the time column collides with them.
Each entity represents an Appointment so they have a duration of at least, 45min, and thats what I want my query to check. This is what I've come up with:
If every appointment has a duration of 45min, then I would have to check if there is already a record in the database in the range of (Appointment.time - 45min, Appointment.time)
Can't just make unique the time column and be happy because of the duration matter, we're better than that.
The code I have so far and that doesn't work is this :D
$query = $em->createQuery('SELECT a FROM AcmeStuff\ApiBundle\Entity\Appointment a
WHERE a.time BETWEEN ?1 AND ?2
ORDER BY a.date DESC');
$query->setParameter(1, $appointment->getDate()->sub(new \DateInterval('PT45M')));
$query->setParameter(1, $appointment->getDate());
Can someone please point me in the right direction, feels like I'm far from it.
EDIT:
I'm not getting the records that I should be getting, what is the correct way to query for a range of dates using DQL?
Thanks in advance!
you need to write it like this
createQuery('SELECT a FROM AcmeStuff\ApiBundle\Entity\Appointment a ....
How can I sort a query based on the average Rating in a field in my table, the field itself is JSON text, structured like:
[
{"Type":1,"Rating":5},
{"Type":2,"Rating":5},
{"Type":3,"Rating":5}
]
I need my query to be sorted by the average of the 3 Ratings. There will always ever be only 3 values for this.
My current query is:
SELECT `Name`, `Town`, `Vehicle`, `Review`, `Rating`, `Pics`, `PostedOn`
FROM `tbl_ShopReviews`
WHERE `Approved` = 1
ORDER BY `PostedOn` DESC
Current results:
Name Town Vehicle Review Rating Pics PostedOn
Kevin Chicopee 94 Corolla Great stuff, very glad I brought it here [{"Type":1,"Rating":5},{"Type":2,"Rating":5},{"Type":3,"Rating":5}] \N
Just for those like me, who googles and tries to find solution for laravel 5.4. You can use -> operator to extract JSON, that is equal to json_extract function or to column->"$.key" syntax.
$users->orderBy('column->key', 'desc');
Looks like it would be very useful in late 2013 (smile).
For example field_name has the value like
{"json_field_key1":"2016/11/24","json_field_key2":"value"}
Use this code for get the json field json_field_key1 based value in ORDER BY case
select table.*, SUBSTRING_INDEX(SUBSTRING_INDEX(field_name,'json_field_key1":"',-1),'"',1) as json_field_name from table ORDER BY SUBSTRING_INDEX(SUBSTRING_INDEX(field_name,'json_field_key1":"',-1),'"',1) DESC
If your value is in date format just modify this code like
order by DATE(SUBSTRING_INDEX(SUBSTRING_INDEX(field_name,'json_field_key1":"',-1),'"',1)) DESC
Would this feature from MySQL 5.7 help? http://blog.ulf-wendel.de/2013/mysql-5-7-sql-functions-for-json-udf/
In my opinion the best solution is to be able to hook up update and insert events in your application for that reviews table and calculate the average in to another field.
Then those queries that need this info will be much easier to handle and will have a better performance.
The better solution is to parse the data before the insert, and have it ready for you in 3 columns or in 1 normalized column.
Saying that, if you're dealing with a non-changeable situation, and have exactly 3 ratings always, you can try this
ORDER BY (substring(json, 21, 1)+
substring(json, 43, 1)+
substring(json,65, 1))/3 desc;
Please consider that this solution is the least maintainable and flexible of them all, and very bug prone. The real solution is restructuring your data.
There isn't an easy way to do this, in fact, I'm not even sure it's possible.
That being said, your database structure really shouldn't contain JSON if it's something you need access to in this respect, instead, why not add a Type field to your database?
the Rating field could be a table with user, type and vlaue as columns where the user is the key. Then you can just use mysql AVG() on the value column where the key match and then sort to that.
hope this help
I need to store all the sessions in my db, I want to be able to tell if the users latest session has expired.
I tried this but as you can imagine all the sessions that where less the < current time showed.
"SELECT userid FROM session WHERE expiretime < '".date()."'"
basiclly i need to group the userid I know that.
Then I need it to only limit 1 per userid
Then I need to make sure it is the last session id
CORRECT WAY TO DO THIS!
Ok I figured it out to do this you need to use IN
SELECT * FROM `user_sessions` WHERE id IN (SELECT max(id) as id FROM `user_sessions` GROUP BY userid)
There is a rule.
To do something, one has to know what are they doing.
That's extremely handy principle, always helps me.
For example, if I want to compare some date stored in my database, I have to know what format it is. Is it a unix timestamp or datetime or some custom format?
Next thing I'd have to know is what is PHP date() function output when called without parameters and if it match database format. And if it's just an error message - than how to make it match with database format (I'd read a documentation page for this).
Sounds sensible? I hope so.
Next thing I would research is how to perform date calculations in mysql. It seems I will need some comparison using mysql function DATE_SUB()
Honestly, are you sure you want your custom session storage? A regular one already doing all this job for you.
SELECT * FROM `user_sessions` WHERE id IN (SELECT max(id) as id FROM `user_sessions` GROUP BY userid)
Try using the MySQL NOW() function.
"SELECT userid FROM session WHERE expiretime < NOW()"