Scenario
I have three elements in this problem. One is an array of ids in this format: (1,3,5,6,8). That array is a list of id of users I want to display. The second element is table that contains user information something simple like: id name surname email. The third element is a second table that contains users configuration. There are two parameters in that last table, one is lid, and the other is usraction (among others, but the important are those two). lid represent a permission type and usraction the value, if the user wants his data to be public there will be a row on that table where lid=3 and usraction="accepted", also I register the datetime of the action every time the user changes this permission, so each time he change it a new row is added, and in order to retrieve the actual state of the permission i have to retrieve the last row for the user an check the value of usraction like this:
SELECT * FROM legallog WHERE uid = '.$user['id'].' AND lid = 3 ORDER BY ABS(`registration` - NOW()) LIMIT 1
Then in php:
if($queryresult && $queryresult[0]['usraction']=='accepted') //display data
The problem
In the scenario id described how im getting the actual state of the permission set by one user at the time, the problem now is I want to sort of clean an array of ids in one or two sql calls. Lets say I want to print the user information of 4 users, one function gives me the ids in this format: (2,6,8,1), but those users may not want to display their information, using the query I showed before I can make a call to the sql server for each user and then generate a new array, if the users who authorize are 1 and 8 the result array will be (8,1).
The think is whit an array of 100 users I will make 100 calls, and I dont want this, is there a way to solve this in one or two querys?
A query such as this gets you the information you want:
select u.*,
(select usraction from configuration c where c.userid = u.userid and c.lid = 3 order by datetime limit 1
) as lastLid3Action
from users u
where u.userid in (1,3,5,6,8)
If you only want "accepted" values, then make this a subquery:
select t.*
from (select u.*,
(select usraction from configuration c where c.userid = u.userid and c.lid = 3 order by datetime limit 1
) as lastLid3Action
from users u
where u.userid in (1,3,5,6,8)
) t
where LastLid3Action = 'Accepted'
As I understand you have two tables in the first table, where the user information is stored; and the second table, where the user permission is stored. And you want to get information from the first table using permission from the second table, then you need this query:
SELECT a.*
FROM first-table-name AS a
RIGHT JOIN second-table-name AS b a.uid = b.lid
WHERE uid in (1,3,5,6,8) AND usraction='accepted'
ORDER BY ABS)
LIMIT 1
You question is somewhat vague, but if you are asking how to select a number of records when you have a list of ids, the answer is:
select column, list, goes, here from tablename
where id in (1,5,8,12,413);
That will get you the values of the columns you list for just the records that match your array of ids.
Related
I have two tables one is user and another is images. I gave users the option to select multiple images. I can store multiple images with same user_id in database, but when I am trying to get one image from every user I am getting all the images.
My query is something like this:
$query = "
SELECT *
FROM images i
JOIN users u
ON u.user_id = i.user_id
LIMIT 1";
When I run this query in while() loop, I only get very first image from images table.
I am really sorry if I am not able to clarify what I am try to ask.
Have you tried something like this:
SELECT * FROM users u INNER JOIN images i ON u.user_id = i.user_id GROUP BY u.user_id;
This should return you only one record from user/image tables for each user that has an image.
Don't run queries in a while loop. Instead, use one query to get all the desired records.
If you insist on running your query in a loop, then you are missing WHERE users.user_id = ? part in your query, so you can get a different result for each user in a loop.
you can do this without using join. simple select user and fetch data and on the bases of 'id' add query to get image. i hope this will help you;
Your current query:-
SELECT *
FROM images i
JOIN users u
ON u.user_id = i.user_id
LIMIT 1
uses LIMIT 1. This tells the query to bring back 1 row.
Removing the LIMIT 1 will return 1 or more records per user (who has at least 1 image), one for each image.
If you want a single user then it is possible (although not recommended) to (ab)use the GROUP BY clause:-
SELECT *
FROM images i
JOIN users u
ON u.user_id = i.user_id
GROUP BY u.user_id
This would bring back one record per user, but which image it returns is not defined. It could bring back the first image for that user, or the last one, or any other one (and which one it returns could change in the future). Further, there is no actual reason it couldn't return values from different rows for each of the columns on the images table (unlikely, but nothing specified to stop this happening).
Note that basic SQL standards specify (with a small exception) that any non aggregate field brought back in a SELECT statement must be in the GROUP BY clause. MySQL used to not enforce this restriction by default, but recently this changed and it is enforced by default. As such by default this query would no longer work as it is returning all the fields from the images and users tables while only specifying the user_id from the users table in the GROUP BY clause.
What you should do is define which image you want for each user. Assuming the first image (and that the images table uses an auto increment primary key called id):-
SELECT u.*,
i.*
FROM users u
LEFT OUTER JOIN
(
SELECT user_id
MIN(id) AS first_image_id
FROM images
GROUP BY user_id
) sub0
ON u.user_id = sub0.user_id
LEFT OUTER JOIN images i
ON sub0.user_id = i.user_id AND sub0.first_image_id = i.id
This uses a sub query to get the first image id for each user. Then that is joined to the images table to get the other details for that image from the images table.
Note I have used LEFT OUTER JOIN. This is to return a row for a user who doesn't have any images uploaded.
Note it is generally a bad idea to use SELECT *, rather than specifying the columns to be returned. I have left this in place here as I do not know the column names of your tables.
I am trying to get the users I am not following and that isn't equal to me.
So far I have got this query:
SELECT DISTINCT
u.id,
u.username,
u.profileImage,
u.fullname,
u.coverImage,
u.bio,
a.uuid,
a.type
FROM USERS u
JOIN Activity a
WHERE NOT u.id = 145
AND a.id = 145
AND type = 'follow'
145 is the current user.
I store following's in the Activity table, So I Don't want to get the users that are equal to the IdOtherUser in the row where id = 145.
When I follow someone it would be like this:
Id = 145(me)
IdOtherUser = 86(other person I follow, who I don't want to get from USERS table.)
type = 'follow'(type of action)
I am successfully getting all the users that aren't equal to me(145) but cannot seem to get the users that are equal to the people I follow!
Any ideas are much appreciated.
Thanks in advance
fiddle
I want to get the users that is not equal to 123(current user, and the people he is following user(145))
There are various ways to accomplish the expected outcome. They are all based on using a subquery to determine if a user is followed by a given user. You can have this subquery as a derived table (in the from clause), or in a not in() or not exists() operator. I'll show you an example for the not exists() operator because it does not have to pull data from the users table, it merely checks if you have a record corresponding to the where criteria
select *
from users u1
where u1.id<>145 --not me
and not exists (select 1
from activity a
where a.id=145 --users I follow
and a.IdOtherUser=u1.id
and a.type='follow')
I'm having some problems retrieving data from two tables and then listing them. I'd like to list the user's feed posts and their likes activity all in one.
Feeds - Table for users posts
Likes - Table for users likes (So when a use likes a post, a record is added to likes (Table likes contains data which contains the feeds ID of the post liked)
What I'm attempting to make: List BOTH feeds and user's Like activity in an ACTIVITY WALL.
So it should output like (ordered by timestamp desc):
"THIS IS A POST by user A"
Shows that user C liked user B's post
"THIS IS A POST by user B"
"THIS IS A POST by user L"
Shows that user A liked user F's post
"THIS IS A POST by user F"
-and it goes on-
My current SQL:
SELECT * FROM feeds,likes WHERE feeds.deleted!=0 or likes.deleted!=0 ORDER BY feeds.timestamp, likes.timestamp
However, my problem is I have no idea how to link both tables, since the IDs in my 'feeds' differ from those in 'likes'
To combine the two sets, you can use a UNION ALL set operator.
Something like this:
SELECT f.timestamp AS `timestamp`
, 'feed' AS `src`
, f.feed_id AS `id`
, f.feed_content AS `content`
FROM feeds f
WHERE f.deleted!=0
UNION ALL
SELECT l.timestamp AS `timestamp`
, 'like' AS `src`
, l.like_id AS `id`
, l.note AS `content`
FROM likes l
WHERE l.deleted!=0
ORDER BY 1 DESC
Note the the queries (on either side of the UNION ALL operator) need to match, in terms of the number of columns returned, and the datatype of each column.
To accommodate differences, such as extra columns returned from one table, but not from the other, you can add literal expressions in place of the "missing" columns.
The return of the extra src column is one way we can use to distinguish which query a row was returned by. It's not mandatory to return such a column, but it's something I often find useful. (The src column could be removed from each query, if it's not useful for your use case.)
Note that it's also possible to combine the results from more than two queries in this way, we'd just add another UNION ALL and another query.
The column names in the combined resultset are determined from the first query. The column names and aliases in the second query are ignored.
The ORDER BY applies to the entire set, and follows the last select.
Query should be linked via postID
F=feeds table, L=likes table, U1=usertable linked to owned feeds, U2=usertable linked to likes table
SELECT F.postTitle+' posted by '+ U1.username,'liked by'+U2.username
FROM likes L
LEFT JOIN feeds F on (F.postID=L.postID)
LEFT JOIN users U1 on (U1.userID=F.userID)
LEFT JOIN users U2 on (U2.userID=L.userID)
ORDER BY L.date,L.postID DESC
When you write SELECT * FROM feeds,likes... you are implicitly CROSS JOINing both tables. The engine will combine every record in each table with every record in the other. That is far from what you want.
I don't think you should be "linking" both tables, either. What you need, roughly speaking, is to get every post and every like, and then order that big set according to timestamps.
It sounds more like a UNION between two queries, and an ORDER BY applied to the whole UNION. UNIONs are never easy on the eye, by the way...
The thing with UNIONs is that both sub-queries need to return the same amount of columns. Not knowing exactly which columns you have, I'll show you one possible solution:
SELECT activity, timestamp FROM (
( SELECT CONCAT(u.name,' posted ',f.content) as activity, timestamp
FROM user u
JOIN feed f on (f.user_id=u.id)
WHERE f.deleted!=0
) UNION
( SELECT CONCAT(u.name, ' liked a post by ',u2.name) as activity, timestamp
FROM user u
JOIN likes l on (l.user_id=u.id)
JOIN feed f on (l.feed_id=f.id)
JOIN user u2 on (f.user_id=u2.id)
WHERE l.deleted!=0
)
) as whole_result
ORDER by timestamp desc
You should, of course, modify this to match your structure.
Hope this helps!
I think, it's better to use 3rd table, say, "actions", and insert to it real actions. Then just select rows from this table, joined to "posts" & "users" table.
When user posts articles, o likes an article, insert corresponding row to "actions" table.
actions table:
|id|action_name|user_id|post_id| date |
1 posted 3 3 5/7/2014
2 liked 5 3 5/7/2014
3 liked 4 3 6/7/2014
4 posted 5 6 7/7/2014
5 liked 3 6 7/7/2014
SELECT user_name a, post_title b, action_name c FROM actions c LEFT JOIN users a ON a.id=c.user_id LEFT JOIN posts b ON b.id = c.post_id ORDER BY c.date DESC LIMIT 10
Then, in loop, choose how to display this data, according to "action_name".
In such way you can expand your wall for other activities, +use indexes for better database performance.
Let me set up the situation first.
I have a "users" table with X fields, the fields dont really matter for my question except for "visibility". Visibility is a tinyint and the values mean the following (0 = visible to all, 1 = visible to friends only, and 2 = invisible).
I also have a friends table (id, user_id, target_user_id). user_id is friends with target_user_id. Easy enough so far right?
Here is where it gets sticky. Im writing a PHP API and my class method looks kinda like this:
public function getUsers($requester, $page, $num) {}
the $requester is the user id of the person requesting the users
the $page is the pagination page number
the $num is the number of items per page
What I want to do in SQL is get $num users from the users table if their visibility field is = 0 or 1. If the visibility flag is 1 however, I need to make sure the user id and the $requester are friends in the friends table and only return that user if they are friends.
I thought about using PHP to filter the visibility after I get my results back but the pagination (limit) will be screwed up if I ask for 5 records for example and one or more user has visibility set to 1 and are not friends with the requester. This pretty much has to be done entirely thru sql.
Possible??
Try creating a temp table 'temp' with same structure as users.
select * into temp From users where visibility=0 or visibility=1;
Select * from temp, friends where (temp.visibility=0) or (temp.user_id = friends.target_user_id);
Don't forget to empty the temp table.
I haven't tried the second query yest, let me know what output you got.
select * from users, friends where (users.visibility=0) or (users.visibility=1 and users.user_id = friends.target_user_id);
I think you can use LEFT JOIN for this.. something like
"SELECT *
FROM users t1
LEFT JOIN friends t2 ON t2.user_id=t1.id AND t1.visibility=1
INNER JOIN user t3 ON t3.id=t2.target_user_id
WHERE t1.visibility=0 OR t1.visibility=1
LIMIT ".($page*$num).",".$num
I have been doing this for a while now, via some php, first lets say we have two tables:
Users
user_id name email
Images
image_id user_id url
user_id and user_id from images table would be linked with a relationship.
Now what I would do is select the user by their Id, check if the user is found, if so then make another query to images table, and check for num rows and loop through the return, is there a function that I could use that would allow me to just select the user and all the images that are linked to the user without doing a joint query.
Thank you for any help
When you say "without doing a joint query" I think you mean "without doing two queries."
In fact, what you want is probably a LEFT JOIN. The idea is that you select users from the user table matching some ID, and LEFT JOIN the images table. The left join will give you null values if no images exist for the user. If you use a normal join, the fact that no matching records exist in the images table will result in no rows returned.
Here is an example:
SELECT u.name, u.email, i.url
FROM Users u
LEFT JOIN Images i ON (i.user_id = u.user_id)
WHERE u.id = #SpecificUserID;
Assuming the user id is found and there are some images for that user, you will get a result that looks like this:
name email url
----- ----- -----
John j#a.com abc.jpg
John j#a.com def.jpg
John j#a.com ghi.jpg
Now as you can see, the name and email values keep repeating. You get a unique image url for each row and the matching username and email.
If you only select one user at a time, this is simple to process in a loop. On the first iteration read all three values. On subsequent iterations just read the url, adding it to your list or array.
Here is a useful tutorial on joins: Understanding JOINs in MySQL and Other Relational Databases
This can be done in one query rather than two by using an inner join to get your result set.
$sql = "SELECT u.user_nid, i.url
FROM tbl_user u
INNER JOIN i.user_nid = u.user_nid
WHERE user_nid = ?"
With this query you will receive a list of the users images and if there are no images returned or the user does not exist, than you will have a row return of zero.
You'll have to use a join to retrieve data from multiple tables in a single query.
The foreign key relationships enforce constraints. Ex: You can't insert a record into Table A referring to a key in Table B without the record actually being in Table B.