How to conditional order results in mySql? - mysql

I have this scenario:
A user enter my application and push a button to look for a pair on a game. When he click the button, I do a insert in a table, whit his ID, his level, his countryID and a datetime whith NOW().
Then, I need to look in this table, trying to find a pair to play with him.
my problem is, i need to order the results based on the user level.
So, imagine my table have this rows:
|ID |userID|userLv| date_add | country_ID |
----------------------------------------------------
| 1 | 1 |3 |2016-06-24 12:09:06 | 5 |
| 2 | 2 |2 |2016-06-24 04:26:24 | 8 |
| 3 | 3 |2 |2016-06-24 11:38:54 | 1 |
| 4 | 4 |1 |2016-06-24 11:10:06 | 9 |
| 5 | 5 |2 |2016-06-24 11:35:49 | 6 |
| 6 | 6 |1 |2016-06-24 20:09:13 | 10 |
If a user with level 1 click the button, he needs to be matched with another user of level 1, odered by date_add ASC. But if there are no users of level 1 available, he will be paired with a user of level 2, again order by date_add ASC. if there are no level 2 users available, the he will be paired with a user of level 3.
Basically, i need a script that can return the rows ordered first by the userLv = x, then the other levels. How to do this with only one request to the database? Does this even make sense?

You can simple use a correlated query with LIMIT to get the second user id :
SELECT t.*,
(SELECT s.userID FROM YourTable s
WHERE s.userLv >= t.userLv
ORDER BY s.userLv
LIMIT 1) as user2_id
FROM YourTable t
WHERE t.userID = <YourParamOrWhatEver>

You can use your sql commands 1 at a time. Check if a same level query returns something and repeat it for some seconds. Then if you had no result, check the next sql statement for the same time and so on.

Related

MySQL SELECT value from a table column based on a different table and sum()

I've got 2 tables setup like so:
> events
-----------------------------------
id | event | eventHandle | points
-----------------------------------
1 | Event One | eventOne | 5
2 | Event Two | eventTwo | 10
> entries
-----------------------------------
id | user | eventHandle
-----------------------------------
1 | 1 | eventOne
2 | 1 | eventTwo
3 | 1 | eventTwo
5 | 5 | eventOne
And what I need to do is get the amount of 'points' each user has gained related to each event.
For example, user 1 has got 25 points and user 5 has 5 points.
What I can't figure out is how get the points, based one the eventHandle and sum them together.
I managed to select the different data from different tables, and do a basic sum with a different query, but not combined. Mind boggling.
Any help is mighty appreciated!
All you need to do is a simple inner join between the 2 tables on eventHandle fields and sum points by users:
select en.user, sum(ev.points)
from events ev
inner join entries en on ev.eventHandle=en.eventHandle
group by en.user

Returns distinct record in a joins query - Rails 4

I'm trying to get and display an order list including the current status.
#orders = Order.joins(order_status_details: :order_status)
.order('id DESC, order_status_details.created_at DESC')
.select("orders.id, order_status_details.status_id, order_statuses.name, order_status_details.created_at")
It works good but is returning all the rows with order ids duplicated like this:
+----+-----------+----------------------+---------------------+
| id | status_id | name | created_at |
+----+-----------+----------------------+---------------------+
| 8 | 1 | Pending | 2016-01-31 16:33:30 |
| 7 | 3 | Shipped | 2016-02-01 05:01:21 |
| 7 | 2 | Pending for shipping | 2016-01-31 05:01:21 |
| 7 | 1 | Pending | 2016-01-31 04:01:21 |
+----+-----------+----------------------+---------------------+
The correct answer must return uniques ids, for the example above should be the first and second row.
I was already trying with distinct on select, .distinct, .uniq and .group but I'm getting an error.
Thanks.
First of all, I believe your model is "An Order has many OrderStatusDetail". So that is the reason why you have several different name in your result.
So you can modify the query like this:
#orders = Order.joins(order_status_details: :order_status)
.order('id DESC, order_status_details.created_at DESC')
.where('order_status_details.id IN (SELECT MAX(id) FROM order_status_details GROUP BY order_id)')
.select("orders.id, order_status_details.status_id, order_statuses.name, order_status_details.created_at")
Ideally, the where condition is used for selecting just the expected id of order_status_details, I use min_id for example, you can modify it as needed

Get rank within table for any number

I have a bidding system in place. The user enters how much he wants to bid, which then sends a request via ajax to a PHP script, which then gets what rank that bid would place under the existing bids, and then displays it back to the bidder. This allows him to increase his bid to get the rank he wants.
For example
+-----------+------------+
| bidder_id | bid_amount |
+-----------+------------+
| 1 | 20 |
| 2 | 20 |
| 3 | 30 |
| 5 | 40 |
| 6 | 10 |
+-----------+------------+
The user bids 15$, the query gets the rank as 5th.
How would this query look like? Is is possible to insert a fake row with the new user's bid and then order everything?
Something simple like this should do it;
SELECT COUNT(*)+1 rank
FROM bids
WHERE bid_amount > 15
An SQLfiddle to test with.

Mysql query Max not working

What i want to happen is group by parentid first, then group by position, which i have done. In that group i want the name with the highest rating to be displayed, which isn't happening. Instead the lowest id for each group is being displayed. The results should be tv1,tv3,tv5,tv7; as these are the highest rated values for each group.
id | name| parentid| position| rating |
1 | tv1 | 1 | 1 | 6 |
2 | tv2 | 1 | 2 | 5 |
3 | tv3 | 1 | 2 | 7 |
4 | tv4 | 1 | 2 | 3 |
5 | tv5 | 5 | 1 | 8 |
6 | tv6 | 5 | 1 | 2 |
7 | tv7 | 3 | 1 | 9 |
8 | tv8 | 3 | 1 | 3 |
$getquery = mysql_query("SELECT name,MAX(rating) FROM outcomes GROUP BY position,parentid") or die(mysql_error());
while($row=mysql_fetch_assoc($getquery)) {
$name = $row['name'];
$rating = $row['rating'];
echo "<p>Name: $name - $rating</p><p></p>";
}
It's not that the lowest id is being displayed -- you're not actually selecting the id column. Probably what you are seeing is the first entry in the name column for each group.
SELECT name, MAX(rating)
doesn't do what you think it does -- it doesn't instruct MySQL to pick the maximum value from the rating column, and also return the name that is associated with that row (aside: what do you think it would return if there was a tie for the maximum rating? What do you think it would return if you used AVERAGE rather than MAX?)
What it does instead is return the correctly calculated MAX(rating), and then one of the names out of that group. It doesn't guarantee which one gets returned, and it can change depending on how it decides to execute the query.
In fact, because of the undefined nature of a query such as this, it's not even legal SQL in other databases. (Try this in Postgres, and you'll get an error. Heck, try it in MySQL with the ONLY_FULL_GROUP_BY option enabled, and you'll get a similar error)
If what you want to do is find the maximum rating for each group, and then find the name associated with it, you'll have to do something like this:
SELECT name, max_rating FROM outcomes
JOIN (SELECT position, parentid, MAX(rating) AS max_rating from outcomes group by position, parentid) AS aggregated_table
USING (position, parentid)
WHERE rating = max_rating
(There are four or five other ways to do this, searching this site for mysql and aggregation will likely turn them up)

How to update a 'Sort Index' column of a list of records with one call

Basically, I have a list of records in a mysql db. These records are ordered 1 to 10. The user can re-order these records to whatever order they want. They will press a button to update all the records to their newly, respective order number. For example:
ID | Sort_Index | Name
----------------------
1 | 1 | Jim
2 | 2 | Bob
3 | 3 | Carl
4 | 4 | Bill
5 | 5 | Wendy
The user can change these to this for example:
Note: the changed values are stored into an array before I make the UPDATE calls
ID | Sort_Index | Name
----------------------
1 | 1 | Carl
2 | 2 | Wendy
3 | 3 | Bob
4 | 4 | Jim
5 | 5 | Bill
My question is, how can I make this mysql call with one call, using the new values in my array, instead of one call for each record?
If this is impossible or simply the "wrong way to do it", please feel free to suggest new ideas as I am not fully committed to this idea as of now.
If you have a limited number of rows, you could implement this with an sql CASE statement --
Update users set sort_index = case id when 1 then <newval> when 2 then <newval>...