SQL Filter Results by User - mysql

I have a simple MySQL database with one table, call it X. Users interact with X via PHP. Simple stuff. Now I would like I would like to allow each user to flag specific "rows" in X so that they don't appear when they search X in the future.
Ex. Each user is shown, say rows 1 to 10. User A doesn't want to see rows 4, 8, 9. Ever. But User B, Q and Z love those rows and just can't live without them. Oh, and we can't forget User D who hates every row but 2. And so on...
How should I go about doing this?
Update:
I should have noted: I realize I can create another table with all the rows that people don't want, but what's the best way to design the table(s) in order to support an increasing number or users and data rows?

You need a table called X_blacklist.
It will have two columns: userid and postid. Those two columns together are the composite primary key.
For a user identified by userid to hide a post identified by postid she inserts that row into X_blacklist. Then when you display items from X to your users, you do this:
SELECT X.postid, X.postcontent
FROM X
LEFT JOIN X_blacklist ON X.postid = X_blacklist.postid AND X_blacklist.userid = ?
WHERE X_blacklist.postid IS NULL
This eliminates the items from your X table that are mentioned in the other table for the particular user.

Related

Loading time when counting numbers of followers

Say I'll get all the followers of a certain content from my project; here is my db
table
contents
users
Now, everytime I want to get content's numbers of followers, I have this table here to get connections with users called content-followers.
table
contents
users
content-followers <
columns
user_id
content_id
Now my concern is say this will run getting the numbers of followers of a content, but this will be along with the other queries and stuff and I understand it may get the sql slower on process.
See, everytime people will visit the content, I'll have to show that count, but that count (as I imagine) will run through the entire table just to count.
Is there other way to make it simple? Like counting only once a certain time and save to contents table?
I have no proper database lessons so, thanks guys for your help in advance!
CREATE TABLE ContentFollowers (
user_id ...,
content_id ...,
PRIMARY KEY(user_id, content_id),
INDEX(content_id, user_id)
) ENGINE=InnoDB;
SELECT ...,
( SELECT COUNT(*) FROM ContentFollowers
WHERE user_id = u.id
) AS follower_count
FROM Contents AS c
JOIN Users AS u ON ...
WHERE ...
The COUNT(*) will efficiently use the PRIMARY KEY of ContentFollowers. The added time taken will be a few milliseconds, even with many millions of users and contents.
If you want to discuss further, please provide the SHOW CREATE TABLE for each relevant table and your tentative SELECT (which will have more than what I specified). So "... counting only once ..." should be unnecessary (and a hassle).
Is it possible for a "user" to "follow" a "content" more than once? This is a potential hack to mess up your numbers, but I think what I say here avoids that possibility. (A PRIMARY KEY includes an 'uniqueness' constraint.) Without this, a user could repeatedly click on [Follow] to inflate the number of 'followers'.
In what you have specified so far, I don't see the need for a TRIGGER. Furthermore, a Trigger would reopen the possibility of the above 'hack'.

MySQL: Grouping results by perceptual hash similarity

Let's say we have MySQL table Image with following columns
id
user_id
p_hash
I know how to calculate hamming distance (to reveal similar images) between newly inserted row's perceptual hash and all existing data in table. SQL query looks like this:
SELECT `Image`.*, BIT_COUNT(`p_hash` ^ :hash) as `hamming_distance`
FROM `Image`
HAVING `hamming_distance` < 5
I want to do the same to every existing image.(to check if there are similar images in the database)
So, I have go through every row of the Image table, do the same process as above and find similar images from the table.
Now the question is, after whole procedure I want to get similar image groups only if elements of each group has at least one different user_id id?
So if, found group of similar images belongs to one user, then skip it. But if it belongs to multiple different users then return it as one of results.
Please help to figure out.
Sounds like you want a self-join.
SELECT i1.id, GROUP_CONCAT(i2.id) AS similar_images
FROM Image AS i1
JOIN Image AS i2 ON i1.user_id != i2.user_id AND BIT_COUNT(i1.`p_hash` ^ i2.p_hash) < 5
GROUP BY i1.id
DEMO

How can I get the most recent result from a table with a column that has multiple of the same values

I'm trying to get make my table get only 1 of the results that I have in the table. My table stores a posted_by column that allows more than 1 user to post more than once. So, my posted_by column has multiple of the username Chowderrunnah because that user has posted more than once. I only want to display one of the results so each user can be clicked on in the table instead of displaying many of the same user. (I'm trying to create a support ticket system if you're wondering why).
At the moment, my table is getting all the results from my table, even duplicates with the same posted_by (username). I only want it to display one result if there are more than 1 of the same posted by (username).
At the moment, my code is only the minimum -
SELECT * from support WHERE last_post_by != 'Admin'
Help is much appreciated.
Edit
Here is the table I'm using
Here is my support ticket system
The following Query fixed my problem :)
SELECT * from support WHERE last_post_by != 'Admin' GROUP BY posted_by
Using GROUP BY allowed me to only display one of the duplicate posted_by results.

Best way to store ordered lists in a database?

What's the best way to store "ordered lists" in a database, so that updating them (adding, removing and changing the order of entries) is easily done?
Consider a database where you have a table for users and movies. Each user has a list of favorite movies.
Since many users can like the same movie, I made users and movies separate tables and uses a third table to connect them, usermovies.
usermovies contains an id of a user and a movie and an "order number". The order number is used to order the list of movies for users.
For example, user Josh might have the following list:
Prometheus
Men in Black 3
The Dictator
and user Jack might have a list like:
The Dictator
Prometheus
Battleship
Snow White and the Huntsman
So, they share some favorites, but not necessarily in the same order.
I can get the list of movie IDs for each user using a query:
SELECT movie_id FROM usermovies WHERE user_id =? ORDER BY order_number
Then, with the ordered movie_ids, I can get the list of movies using another query
SELECT name FROM movies WHERE id in (?,?,?) ORDER BY FIELD (id, ?,?,?)
So queries work, but updating the lists seems really complex now - are there better ways to store this information so that it would be easy to get the list of movies for user x, add movies, remove them and change the order of the list?
If you are not looking for a "move up / move down" kinda solution, and then defaulting to adding at the bottom of the list, here are a few more pointers:
Inserting new rows into a specific position can be done like this: (inserting at position 3)
UPDATE usermovies SET order_number = ordernumber + 1
WHERE ordernumber > 3 and user_id = ?;
INSERT INTO usermovies VALUES (?, 3, ?);
And you can delete in a similar fashion: (deleting position 6)
DELETE usermovies WHERE order_numer = 6 and user_id=?;
UPDATE usermovies SET order_number = ordernumber - 1
WHERE ordernumber > 6 and user_id = ?;
A junction/link table with additional columns for the attributes of the association between movies and users is the standard way of realizing a many-many association with an association class - so what you have done seems correct.
Regarding the ease of insert/update/delete, you'll have to manage the entire association (all rows for the user-movie FKs) every time you perform an insert/update/delete.
There probably isn't a magical/simpler way to do this.
Having said this, you'll also need to run these operations in a transaction and more importantly have a 'version' column on this junction table if your application is multi-user capable.
To retrieve user favourites movies you could use a single query:
SELECT um.order_number, m.name FROM movies m
INNER JOIN usermovies um ON m.id = um.movie_id
WHERE um.user_id = ?
ORDER BY um.order_number
To add/remove a favourite movie simply add/remove related record in usermovies table.
To alter a movie order simply change all order_number field in user_movies table related to user.
In addition to what others have said, reordering existing favorites can be done in a single UPDATE statement, as explained here.
The linked answer explains reordering of two items, but can be easily generalized to any number of items.

building activity feed

I want to create some kind of 'activity feed'. For example, There are total 1000 users in database, of which there are 100 people in contact list of user X, who is concerned with those 100 users only, and want that if any of them posts a note (in general, takes an action), he wants to get that update on my page. For this purpose, do i need to make a database table, like:
id user_id note_id
In this table, there will be users which are not concerned to user X, so I will make some query like,
select user_id from activity_table which exists in contact list of user X
Is my approach correct regarding this matter (for example database table design and query)?
Is there any better approach?
If I understand you correctly I think you need a relation table where you will store user_ids of the user that is being concerned and of the user that concerns.