I have a table like this:
// users
+---------+------------+
| user_id | reputation |
+---------+------------+
| 1 | null |
| 2 | null |
+---------+------------+
Also I have an array like this: [1 => 15, 2 => 83].
I can parse that array and restruct it to any case needed. I want to know how can I update that value to that table like this:
// users - expected result
+---------+------------+
| user_id | reputation |
+---------+------------+
| 1 | 15 |
| 2 | 83 |
+---------+------------+
An idea how can I do that?
I want a query similar to this:
update users u
join ( ... ) as temp
on u.user_id = temp.user_id
set u.reputation = temp.rep
Related
I have a example table below. I am trying to create a SQL query that gets all user_ids besides user_id of the current user and then orders by number of matches to the row with the current user_id
For example, if the user has a user_id of '1', I want to get all of the user_ids corresponding with the rows of id 2-8, and then order the user_ids from most matches to the row of the current user to least matches with the row of the current user
Let's say var current_user = 1
Something like this:
SELECT user_id
FROM assets
WHERE user_id <> `current_user` and
ORDER BY most matches to `current_user`"
The output should get 7,8,3,9,2
I would appreciate anyone's input on how I can effectively achieve this.
Table assets
+----------+---------+-------+--------+-------+
| id | user_id | cars | houses | boats |
+----------+---------+-------+--------+-------+
| 1 | 1 | 3 | 2 | 3 |
| 2 | 8 | 3 | 2 | 5 |
| 3 | 3 | 3 | 2 | 2 |
| 4 | 2 | 5 | 1 | 5 |
| 5 | 9 | 5 | 7 | 3 |
| 8 | 7 | 3 | 2 | 3 |
+----------+---------+-------+--------+-------+
I think you can just do this:
select a.*
from assets a cross join
assets a1
where a1.user_id = 1 and a.user_id <> a1.user_id
order by ( (a.cars = a1.cars) + (a.houses = a1.houses) + (a.boats = a1.boats) ) desc;
In MySQL, a boolean expression is treated as an integer in a numeric context, with 1 for true and 0 for false.
If you want to be fancier, you could order by the total difference:
order by ( abs(a.cars - a1.cars) + abs(a.houses - a1.houses) + abs(a.boats - a1.boats) );
This is called Manhattan distance, and you would be implementing a version of a nearest neighbor model.
+------+---------+--------+---------+---------+---------+
| id | user_id | obj_id | created | applied | content |
+------+---------+--------+---------+---------+---------+
| 1 | 1 | 1 | 1 | 1 | ... |
| 2 | 1 | 2 | 1 | 1 | ... |
| 3 | 1 | 1 | 1 | 2 | ... |
| 4 | 1 | 2 | 2 | 2 | ... |
| 5 | 2 | 1 | 1 | 1 | ... |
| 6 | 2 | 2 | 1 | 1 | ... |
+------+---------+--------+---------+---------+---------+
I have a table similar to the one above. id, user_id and obj_id are foreign keys; created and applied are timestamps stored as integers. I need to get the entire row, grouped by user_id and obj_id, with the maximum value of applied. If two rows have the same applied value, I need to favour the maximum value of created. So for the above data, my desired output is:
+------+---------+--------+---------+---------+---------+
| id | user_id | obj_id | created | applied | content |
+------+---------+--------+---------+---------+---------+
| 1 | 1 | 1 | 1 | 1 | ... |
| 4 | 1 | 2 | 2 | 2 | ... |
| 5 | 2 | 1 | 1 | 1 | ... |
| 6 | 2 | 2 | 1 | 1 | ... |
+------+---------+--------+---------+---------+---------+
My current solution is to get everything ordered by applied then created:
select * from data order by applied desc created desc;
and sort things out in the code, but this table gets pretty big and I'd like an SQL solution that just gets the data I need.
select *
from my_table
where id in (
/* inner subquery b */
select max(id)
from my_table where
(user_id, obj_id, applied, created) in (
/* inner subquery A */
select user_id, obj_id, max(applied), max(created)
from my_table
group by user_id, obj_id
)
);
Then inner subquery A return the (distinct) rows having user_id, obj_id, max(applied), max(created). Using these with in clause the subquery B retrive a list of single ID each realated the a row with a proper value of user_id, obj_id, max(applied), max(created). so you have a collection of valid id for getting your result.
The main select use these ID for select the result you need.
Thanks to Mark Heintz in the comments, this answer got me to where I need to be.
SELECT
data.id,
data.user_id,
data.obj_id,
data.created,
data.applied,
data.content
FROM data
LEFT JOIN data next_max_applied ON
next_max_applied.user_id = data.user_id AND
next_max_applied.obj_id = data.obj_id AND (
next_max_applied.applied > data.applied OR (
next_max_applied.applied = data.applied AND
next_max_applied.created > data.created
)
)
WHERE next_max_applied.applied IS NULL
GROUP BY user_id, obj_id;
Go read the answer for details on how it works; the left join tries to find a more recently applied row for the same user and object. If there isn't one, it will find a row applied at the same time, but created more recently.
The above means that any row without a more recent row to replace it will have a next_max_applied.applied value of null. These rows are filtered for by the IS NULL clause.
Finally, the group by clause handles any rows that have identical user, object, applied and created columns.
Please consider the following table:
_____________________
| sentence_word |
|---------|---------|
| sent_id | word_id |
|---------|---------|
| 1 | 1 |
| 1 | 2 |
| ... | ... |
| 2 | 4 |
| 2 | 1 |
| ... | ... |
With this table structure I want to store the words of sentences. Now I want to find out which words are together with a specific word in a sentence. The result should look like this:
_____________________
| word_id | counted |
|---------|---------|
| 5 | 1000 |
| 7 | 800 |
| 3 | 600 |
| 1 | 400 |
| 2 | 100 |
| ... | ... |
The query Looks like the following:
SELECT
word_id,
COUNT(*) AS counted
FROM sentence_word
WHERE sentence_word.sent_id IN (SELECT
sent_id
FROM sentence_word
WHERE word_id = [desired word]
)
AND word_id != [desired word]
GROUP BY word_id
ORDER BY counted DESC;
The query is working as it should but it always scans the full table. I created an index for sent_id and word_id. Do you have any ideas to optimize it that it doesn't Need to scan the full table all the time?
You could try a self join like this:
SELECT COUNT(DISTINCT sw1.word_id)
FROM sentence_word sw1
JOIN sentence_word sw2 ON (
sw1.sent_id = sw2.sent_id
AND sw2.word_id = [your word id]
)
WHERE sw1.word_id != [your word id]
or perhaps even better
SELECT COUNT(DISTINCT sw1.word_id)
FROM sentence_word sw1
JOIN sentence_word sw2 ON (
sw1.sent_id = sw2.sent_id
AND sw2.word_id = [your word id]
AND sw2.word_id != sw1.word_id
)
I have a table like this:
+----------------------------+
| id | name | helper |
+----------------------------+
| 1 | user1 | NULL |
| 2 | user1 | NULL |
| 3 | user1 | NULL |
| 4 | user2 | NULL |
| 5 | user2 | NULL |
+----------------------------+
Now I want to update the LAST occurrence of "user1" - how do I do that?
This is my example query right now:
UPDATE Table SET helper = 'bob' WHERE name = 'user1' AND helper IS NULL;
However, this updates all the "user1" Entries.
Thanks in advance.
update t set helper = 'bob' where name = 'user1' order by id desc limit 1;
see it working live in an sqlfiddle
This should work.
UPDATE Table SET helper = 'bob' WHERE id = (SELECT MAX(id) FROM Table WHERE name = 'user1')
Just use MAX(id) to get the last row of 'user1'.
I'm trying to select all my areas and join the deals for those areas... this query is returning 0 results when I have verified that I have data to match what I'm expecting to get... does anyone see anything obviously wrong?
SELECT
deal.*,
area.id AS area_id
FROM area
INNER JOIN account_areas ON (
account_areas.account_id = 1 AND
account_areas.area_id = area.id
)
JOIN deal ON (
deal.area_id = area.id AND
deal.site_id = 1 AND
DAYOFYEAR(deal.created) = DAYOFYEAR(NOW()) AND
deal.end >= NOW()
)
ORDER BY area.name ASC
The idea is that I want to pull all deals for a certain area, but if there are no deals, still have the area in the result query.
account
---------------------------------
| id | email |
---------------------------------
| 1 | test_test.com |
---------------------------------
account_areas
------------------------
| account_id | area_id |
------------------------
| 1 | 81 |
| 1 | 42 |
------------------------
deal
--------------------------------------------------------
| id | area_id | Title |
--------------------------------------------------------
| 1 | 81 | Test Title |
--------------------------------------------------------
Expected results WITH a deal:
id | area_id | title
Expected results WITHOUT a deal
area_id
Use a ...LEFT JOIN DEAL... which will return nulls for all DEAL columns if there are no deals.