PHP/MYSQL: Obtain two items from table in join using different criteria - ios

I am doing a join between tables to get a user pic from a user table about someone who comments on an article. However, I need to get a separate picture from the user table for a different user, the person who wrote the article at the same time. (There is a strong reason to do this in one query, as it's actually only one part of a more complex request).
Can anyone suggest how I could get two user pics from the users table during the join? This code gives me the first user pic, the commenter's pic or upic. But how do I also get the second user pic?
commments
id|comment|articleid|userid
1|great article|1|2
article
id|article|userid
1|Restaurant Openings|1
users
id|pic
1|mary.png
2|joe.png
$sql = "SELECT c.comment,c.articleid,c.userid,u.id, u.pic as upic,a.id,
FROM `comments` c
LEFT JOIN `articles` a
ON c.articleid = a.id
LEFT JOIN `users` u
ON c.userid= u.id
WHERE c.id=1";
A separate query to get the author's pic for would be:
$sqlauthorpic = "SELECT u.pic,u.id from `users` u
WHERE u.id = 1";
Thanks for any suggestions.

Join users again this time with article table, since you are looking for a user that wrote the article:
SELECT c.comment,c.articleid,c.userid,u.id, u.pic as upic,a.id, w.pic as wpic
FROM `comments` c
LEFT JOIN `articles` a ON c.articleid = a.id
LEFT JOIN `users` u ON c.userid= u.id
JOIN `users` w ON w.id = a.userid
You can also get rid of LEFT joins because, i think there could be no comments with out an article (articleid) and no comment without userid.

Related

How to write sub query in active record?

I have two tables users and posts and they have association of has_many. I want to fetch details of both users and posts in a single query. I'm able to manage the sql query but I don't want to use the raw query in the code (using execute method) as i think it is kind of simple thing and can be written using active record.
Here is the sql query
SELECT a.id, a.name, a.timestamp, b.id, b.user_id, b.title
FROM users a
INNER JOIN (SELECT id, user_id, title, from, to FROM posts) b on b.user_id = a.id
where id IN ( 1, 2, 3);
I think includes does not help here because i'm dealing with large data.
Can any one help me ?
If you just want those specific columns and nothing else then this will work
User.joins(:post)
.where(id: [1,2,3])
.select("users.id, users.name, users.timestamp,
posts.id as post_id, posts.user_id as post_user_id,
posts.title as post_title")
This will return an ActiveRecord::Relation of User objects with virtual attributes for post_id, post_user_id (Not sure why you need this one since you already selected users.id), and post_title.
The query produced will be
SELECT users.id,
users.name,
users.timestamp,
posts.id as post_id,
posts.user_id as post_user_id,
posts.title as post_title
FROM users
INNER JOIN posts on posts.user_id = users.id
where users.id IN ( 1, 2, 3);
Please note you may have multiple User objects, one for each Post, just as the SQL query does.
You can execute your exact query using the string version of joins e.g.
User.joins("INNER JOIN (SELECT id, user_id, title, from, to FROM posts) b on b.user_id = users.id")
.where(id: [1,2,3])
.select("users.id, users.name, users.timestamp,
b.id as post_id, b.user_id as post_user_id,
b.title as post_title")
Additionally to avoid some of the overhead you can use arel instead e.g.
users_table = User.arel_table
posts_table = Post.arel_table
query = users_table.project(Arel.star)
.join(posts_table)
.on(posts_table[:user_id].eq(users_table[:id]))
.where(users_table[:id].in([1,2,3]))
ActiveRecord::Base.connection.exec_query(query.to_sql)
This will return an ActiveRecord::Result with 2 useful methods columns (the columns selected) and rows. You can convert this to a Hash(#to_hash) but note that any columns with duplicate names (id for instance) will overwrite one another.
You could fix this by specifying the colums you want selected in the project portion. e.g. your current query would be:
query = users_table.project(
users_table[:id],
users_table[:name],
users_table[:timestamp],
posts_table[:id].as('post_id'),
posts_table[:user_id].as('post_user_id'),
posts_table[:title].as('post_title')
).join(posts_table)
.on(posts_table[:user_id].eq(users_table[:id]))
.where(users_table[:id].in([1,2,3]))
ActiveRecord::Base.connection.exec_query(query.to_sql).to_hash
Since none of the names collide now it can be structured into a nice Hash where the keys are the column names and the values or the row value for that record.
users = User.joins(:posts).includes(:posts).where(id: [1, 2, 3])
Will give you all the users with theirs posts.
then you can do whatever you want with them, but to access posts data for first retrieved user
first_user_posts = users.first.posts # this will not make additional DB queries as you used includes and data is already added
We use joins to have INNER JOIN statement in the SQL
We use includes to load all posts in the memory
I have two tables users and posts and they have association of
has_many. I want to fetch details of both users and posts in a single
query.
can be done with includes like
users = User.includes(:posts).where({posts: {user_id: [1,2,3]}})
other is eager_load and preload you can use as per your requirements, for more https://blog.arkency.com/2013/12/rails4-preloading/

SQL server join query to get all subjects

I have the three tables:
TBL_SUBJECT, TBL_SEMESTER and TBL_SUBJECT_SEMESTER_MAPPING
I am having subjectId with me say '1', I want to get All the subjects of the semester to which my subject belongs. i.e subject having Id '1'.
How is the query with joins in SQL server.
Your question is not as clear as it could be. Please post schemas to get a better answer.
Answers will be something like this:
SELECT
SEMESTER_NAME
FROM
TBL_SEMESTER
INNER JOIN
TBL_SUBJECT_SEMESTER_MAPPING ON TBL_SUBJECT_SEMESTER_MAPPING.SUBJECTID = TBL_SEMESTER.SUBJECTID
INNER JOIN
TBL_SUBJECT TBL ON TBL_SUBJECT.SUBJECTID = TBL_SUBJECT_SEMESTER_MAPPING.SUBJECTID
WHERE
SUBJECTNAME LIKE YOURSUBJECT
I have done it like this
SELECT * from tbl_subject S
INNER JOIN tbl_subject_semester_mapping SSP ON SSP.subId = S.subId
INNER JOIN tbl_semester SEM ON SEM.semId = SSP.semId
WHERE SEM.semId = (select semId from tbl_subject_semester_mapping TSSM where TSSM.subId = 1 )

How do I get Rails ActiveRecord to generate optimized SQL?

Let's say that I have 4 models which are related in the following ways:
Schedule has foreign key to Project
Schedule has foreign key to User
Project has foreign key to Client
In my Schedule#index view I want the most optimized SQL so that I can display links to the Schedule's associated Project, Client, and User. So, I should not pull all of the columns for the Project, Client, and User; only their IDs and Name.
If I were to manually write the SQL it might look like this:
select
s.id,
s.schedule_name,
s.schedule_type,
s.project_id,
p.name project_name,
p.client_id client_id,
c.name client_name,
s.user_id,
u.login user_login,
s.created_at,
s.updated_at,
s.data_count
from
Users u inner join
Clients c inner join
Schedules s inner join
Projects p
on p.id = s.project_id
on c.id = p.client_id
on u.id = s.user_id
order by
s.created_at desc
My question is: What would the ActiveRecord code look like to get Rails 3 to generate that SQL? For example, somthing like:
#schedules = Schedule. # ?
I already have the associations setup in the models (i.e. has_many / belongs_to).
I think this will build (or at least help) you get what you're looking for:
Schedule.select("schedules.id, schedules.schedule_name, projects.name as project_name").joins(:user, :project=>:client).order("schedules.created_at DESC")
should yield:
SELECT schedules.id, schedules.schedule_name, projects.name as project_name FROM `schedules` INNER JOIN `users` ON `users`.`id` = `schedules`.`user_id` INNER JOIN `projects` ON `projects`.`id` = `schedules`.`project_id` INNER JOIN `clients` ON `clients`.`id` = `projects`.`client_id`
The main problem I see in your approach is that you're looking for schedule objects but basing your initial "FROM" clause on "User" and your associations given are also on Schedule, so I built this solution based on the plain assumption that you want schedules!
I also didn't include all of your selects to save some typing, but you get the idea. You will simply have to add each one qualified with its full table name.

Left outer join query (i think)

I have two tables that look like this:
Products: id category name description active
Sales_sheets: id product_id link
product_id is a foreign key from the products id table
I wrote a prepared statement JOIN like this which works:
SELECT p.name, p.description, s.link FROM products AS p
INNER JOIN sales_sheets AS s ON p.id = s.product_id WHERE active=1 AND category=?
Basically a product can have a link to a PDF, but not every product will have a sales sheet. So if i try to bring up a product which doesn't have a sales sheet attached to it then it always returns no rows.
So i thought I'd have to use a LEFT OUTER JOIN in place of the INNER JOIN, but that returns no rows too, am I naming the tables in the wrong order? I've never had to use an OUTER join before?
SELECT p.name, p.description, s.link FROM products p
LEFT JOIN sales_sheets s ON p.id = s.product_id
WHERE active = 1 && category = ?

Sphinx indexer custom query for sql_attr_multi

I managed to have a query for getting all the friends and friends of friends of a particular user. I have a users table and a friendships join table. For simplicity, lets just say that the users table only has a primary key. The friendships table has the user_id and friend_id columns. The query is as follows:
"SELECT DISTINCT friends.user_id, friends.friend_id, users.*
FROM FRIENDSHIPS friends, USERS
WHERE USERS.id = friends.friend_id AND friends.user_id = #{u.id}
UNION
SELECT DISTINCT fof.user_id, fof.friend_id, users.*
FROM FRIENDSHIPS friends, FRIENDSHIPS fof, USERS
WHERE USERS.id = fof.friend_id AND friends.friend_id = fof.user_id AND friends.user_id = #{u.id}"
u.id is the id of the user whom I wish to get all the friends and friends of friends.
This query works very well however I would like to convert this to a query usable by sphinx's sql_attr_multi. I tried directly placing it like so:
sql_attr_multi = uint fwfof from query; \
SELECT DISTINCT `friends`.`user_id`, `friends`.`friend_id`, `users`.`id` \
FROM `friendships` friends, `users` \
WHERE `users`.`id` = `friends`.`friend_id` AND `friends`.`user_id` = $id \
UNION \
SELECT DISTINCT `fof`.`user_id`, `fof`.`friend_id`, `users`.`id` \
FROM `friendships` `friends`, `friendships` `fof`, `users` \
WHERE `users`.`id` = `fof`.`friend_id` AND `friends`.`friend_id` = `fof`.`user_id` AND `friends`.`user_id` = $id
but that obviously failed.
How do I make this query usable by sphinx's indexer?
Thanks in advance for anything that will point me in the right direction.
I don't know enough about your data structure to say that this will 100% work, but I see one obvious problem:
WHEREusers.id=fof.friend_idANDfriends.friend_id=fof.user_idANDfriends.user_id= $id
The last part, WHERE user_id = $id is wrong. That syntax works when adding a sql_query_info attribute to a sphinx index, but not to sql_attr_multi.
Your query for the sql_attr_multi should select the id as the first column that matches the document id in your main sql_query.
The second column of the sql_attr_multi is the col you want to group together in the attr.

Resources