MySQL clubbing two rows as a single one - mysql

I have a table called connections for a friendship system. The columns are:
id, from,to,direction,liking
Whenever a user sends a friend request, a row is added and direction is set to 1 (1 for forward, 2 for reverse). When the other user accepts the friend request, another row is added and the direction is set to 2.
I'm trying to figure out a way to get a user's friends. But when I do the following query, rows are repeated.
SELECT
`users`.`name`,`users`.`id`
FROM
`connections`,
`users`
WHERE
(
`connections`.`from` = 1234 AND
`connections`.`to` = `users`.`id` AND
`connections`.`direction` = 1
)
OR
(
`connections`.`to` = 1234 AND
`connections`.`from` = `users`.`id` AND
`connections`.`direction` = 2
)
How can this query be modified to include so that rows don't repeat?
Update: I'm adding two rows because there's a column liking. This value is different for "distinct user connections".
Example -A can have a liking of 0.95 for B. And B can have a liking of just 0.25 for A.

Based on your comments, you can add an outer query:
SELECT
name, DISTINCT(id) AS id
FROM
(original query)
You say that you add a row when the friend accepts the request. That creates two rows. Would it not make more sense to update the existing row with the new direction? - ignore this last part as per comment

Related

UPDATE JOIN tables, mathematical operation happens only on single (last?) row

In my application I keep track of users' total unread notifications together with other user data in user table. Notifications are in separate table, notifications of similar nature are stacked into a single row, each row tracks count and last timestamp. Now I want to implement a function of marking all notifications as read until a particular timestamp. I made this query using mathematical subtraction between two columns from two different tables:
UPDATE
core_notification n
LEFT JOIN
core_user u
ON
n.notification__user_id = u.user__id
SET
n.notification__if_read = 1,
u.user__notification_unread_count = u.user__notification_unread_count - n.notification__main_count
WHERE
n.notification__timestamp <= 123456 AND
n.notification__if_read = 0 AND
n.notification__user_id = 123;
Problem: lets say in user table "user__notification_unread_count" has a value of 4 and there are two notifications which both have a "notification__main_count" value of 2. My goal after running this query and updating both notifications as read is to have "user__notification_unread_count" value of 0 (4 - 2 - 2 = 0). However the result is always 2. I tried various join methods but it seems that it is just how databases work when updating multiple rows (each updated row overwrites previous update completely, but that is only my assumption).
Is there a way I could achieve the result I want with a single query?
This is a situation where you are probably better off using a trigger. But . . . you can do it in a single update, just with more work:
UPDATE core_notification n LEFT JOIN
core_user u
ON n.notification__user_id = u.user__id LEFT JOIN
(SELECT n2.notification__user_id,
SUM(n2.notification__main_count) as total_notification__main_count
FROM core_notification n2
WHERE n2.notification__timestamp <= 123456 AND
n2.notification__if_read = 0 AND
n2.notification__user_id = 123;
GROUP BY n2.notification__user_id
) n2
ON n2.notification__user_id = n2.notification__user_id
SET n.notification__if_read = 1,
u.user__notification_unread_count = u.user__notification_unread_count - n2.total_notification__main_count
WHERE n.notification__timestamp <= 123456 AND
n.notification__if_read = 0 AND
n.notification__user_id = 123;
The n2 derived table separately calculates the total that needs to be subtracted.

Compare differences in 2 tables

I am running a MySQL Server on Ubuntu, patched up to date...
In MySQL, I have 2 tables in a database. I am trying to get a stock query change working and it kind of is, but it's not :(
What I have is a table (table A) that holds the last time I have checked stock levels, and another table (table B) that holds current stock levels. Each table has identical column names and types.
What I want to do is report on the changes from table B. The reason is that there are about 1/2 million items in this table - and I cannot just update each item using the table as a source as I am limited to 100 changes at a time. So, ideally, I want to get the changes - store them in a temporary table, and use that table to update our system with just those changes...
The following below brings back the changes but shows both Table A and Table B.
I have tried using a Left Join to only report back on Table B but I'm not a mysql (or any SQL) guy, and googling all this... Can anyone help please. TIA. Stuart
SELECT StockItemName,StockLevel
FROM (
SELECT StockItemName,StockLevel FROM stock
UNION ALL
SELECT StockItemName,StockLevel FROM stock_copy
) tbl
GROUP BY StockItemName,StockLevel
HAVING count(*) = 1
ORDER BY StockItemName;
The query below spit out records that have different stock level in both table.
SELECT s.StockItemName, s.StockLevel, sc.StockLevel
FROM stock s
LEFT JOIN stock_copy sc ON sc.Id = s.Id AND sc.StockLevel <> s.StockLevel
ORDER BY s.StockItemName
ok - I solved it - as there wasn't a unique ID on each table that could be matched, and rather than make one, I used 3 colums to create the unique ID and left joined on that.
SELECT sc.StockItem, sc.StockItemName, sc.Warehouse, sc.stocklevel
FROM stock s
LEFT JOIN stock_copy sc ON (sc.StockItem = s.StockItem AND sc.StockItemName = s.StockItemName AND sc.Warehouse = s.Warehouse AND sc.StockLevel <> s.StockLevel)
having sc.StockLevel is not Null;

Creating joins based on range of number value

Could you guys provide me on the situation below?
I have 2 tables.
Table 1 looks like this:
Meanwhile, this is table 2:
I would like to join table 2 to table 1 to lookup the grade for each job based on the upper and lower limit column.
By conceptualizing some of the lovely answers here, I manage to come up with a statement that looks something like this:
FROM table2 LEFT JOIN table1 ON (table2.[score] >= table1.[lower limit]) AND (table2.[score] <= table1.[upper limit])
The statement above manage to join them according to a range, however, for some unknown reasons, some rows from the left table went missing and I could not determine what it is. e.g (2000 rows in table 2, but only 1800 in the query)
I am sure the join is the cause, as if i change the join to a equal left join, 2000 rows appear in the query.
Can someone advice me on this?
Regards,
Guang Yong
Perhaps it would be much cleaner to create a table with values from 1-100 and assign them each on of your categories, and essentially mirroring your table 1.
Then you can do Table 2
SELECT Table1.Grade, Table2.Score
FROM Table2 LEFT JOIN Table1 ON Table2.Score = Table1.Score
This would definitely cover all integers between 0 and 100.
If you are manually inputing the scores, you could also use a data macro as simple as this:
go to Table Tools >> Table >> Before Change
Then use the Set Field Action, and set
Name = Table2.Grade
Value = IIf([Score]>=70,"Good",IIf([Score]<=59,"bad","so so"))
With this ^ everytime you type in a score, it will automatically populate the grade column.
Another option is create a query as follows, that will evaluate each line and assign the proper grade:
SELECT Table2.Score,
IIf([Score]>=70,"Good",IIf([Score]<=59,"bad","so so")) AS Grade
FROM Table2;
Good luck!

Removing duplicate user entries from mySQL database table

I have a table in my database to store user data. I found a defect in the code that adds data to this table database where if a network timeout occurs, the code updated the next user's data with the previous user's data. I've addressed this defect but I need to clean the database. I've added a flag to indicate the rows that need to be ignored and my goal is to mark these flags accordingly for duplicates. In some cases, though, duplicate values may actually be legitimate so I am more interested in finding several user's with the same data (i.e, u> 2).
Here's an example (tablename = Data):
id---- user_id----data1----data2----data3----datetime-----------flag
1-----usr1--------3---------- 2---------2---------2012-02-16..-----0
2-----usr2--------3---------- 2---------2---------2012-02-16..-----0
3-----usr3--------3---------- 2---------2---------2012-02-16..-----0
In this case, I'd like to mark the 1 and 2 id flags as 1 (to indicate ignore). Since we know usr1 was the original datapoint (assuming the oldest dates are earlier in the list).
At this point there are so many entries in the table that I'm not sure the best way to identify the users that have duplicate entries.
I'm looking for a mysql command to identify the problem data first and then I'll be able to mark the entries. Could someone guide me in the right direction?
Well, first select duplicate data with their min user id:
CREATE TEMPORARY TABLE duplicates
SELECT MIN(user_id), data1,data2,data3
FROM data
GROUP BY data1,data2,data3
HAVING COUNT(*) > 1 -- at least two rows
AND COUNT(*) = COUNT(DISTINCT user_id) -- all user_ids must be different
AND TIMESTAMPDIFF( MINUTE, MIN(`datetime`), MAX(`datetime`)) <= 45;
(I'm not sure, if I used TIMESTAMPDIFF properly.)
Now we can update the flag in those rows where user_id is different:
UPDATE duplicate
INNER JOIN data ON data.data1 = duplicate.data1
AND data.data2 = duplicate.data2
AND data.data3 = duplicate.data3
AND data.user_id != duplicate.user_id
SET data.flag = 1;
UPDATE Data A
LEFT JOIN
(
SELECT user_id,data1,data2,data3,min(id) min_id
FROM Data GROUP BY user_id,data1,data2,data3
) B
ON A.id = B.min_id
SET A.flag = IF(ISNULL(B.min_id),1,0);
If there are duplicate times involved, maybe try this
UPDATE Data A
LEFT JOIN
(
SELECT user_id,data1,data2,data3,,`datetime`,min(id) min_id
FROM Data GROUP BY user_id,data1,data2,data3,`datetime`
) B
ON A.id = B.min_id
SET A.flag = IF(ISNULL(B.min_id),1,0);

MySQL Update Join Does not Affect ALL matching rows

I am attempting to do an UPDATE with a JOIN. I have two tables:
player_tracking has a list of all
players that each user has added to
tracking.
users is the user list. each user
can set fsp_f to 1 or 0.
I want to update all rows in player_tracking for users who have fsp_f set to 1. Here is my example code:
UPDATE player_tracking AS pt
LEFT JOIN users AS u ON u.name = pt.user
SET pt.newtome = pt.newtome - 1
WHERE pt.first = 'Brett'
AND pt.last = 'Gardner'
AND pt.sport = 'mlb'
AND u.fsp_f = 1
The problem is that there are 22 rows to update, yet the UPDATE query only affects 2. Why? Is my query wrong?
Here is the data found in player_tracking pertaining to "Brett" "Gardner" "mlb":
http://pastebin.com/kyf8SCy8
i believe that if you change the LEFT JOIN to JOIN you will see the exact rows that get updated since you are using a field form users in the WHERE part of the statement.
so basically you are trying to check if u.fsp_f = 1 when there could be rows that do not join users and therefore will have the value as NULL.
Additionally it seems that the general layout of your query is not correct either, since you are joining on the SET statement and not in the UPDATE part - where you instructed which table to update