How to use IF statement before FROM Clause - mysql

I have three tables:
Users and companies can add feeds. The flag columns means
0 = user
1 = company
How can I perform this SQL query correctly? Thanks in advance for your help!
SELECT
feeds.feeds_id,
feeds.title
IF feeds.flag = 0
FROM user
INNER JOIN
feeds.user_or_company = user.user_id
ELSEif feeds.flag = 1
INNER JOIN
feeds.user_or_company = company.company_id

One way to solve this is to LEFT JOIN to both user and company tables and then select the appropriate name value based on feeds.flag:
SELECT f.feeds_id, f.title,
CASE f.flag WHEN 0 THEN u.name ELSE c.name END AS name
FROM feeds f
LEFT JOIN user u ON u.user_id = f.user_or_company
LEFT JOIN company c ON c.company_id = f.user_or_company
Output (for your sample data)
feeds_id title name
2 This title added twice by user User-1
3 This title added by company Company-2
1 This title added by user User-3
Demo on dbfiddle

Related

How to speed up multiple counts query and get a result

I've got a query I'm trying to write to get counts of active users and active contacts associated with each account. I have attempted to run the counts separately and in both cases they run at under 1 sec but when I put them together as seen below I don't get a result. Please let me know if there is anything I can do it enhance the query.
select count(c.c_no) as contacts_count, count(u_no) as user_count, a.*
from accounts a
LEFT JOIN users u on u.a_no = a.a_no and u_status = 1
LEFT JOIN IDP1.contacts c on c.a_no = a.a_no and c_status = 1
where a_status = 1
group by a_no
THANK YOU!
Do not use * and aggregate functions simultaneously
Try this
select count(c.c_no) as contacts_count, count(u_no) as user_count, a_no
from accounts a
LEFT JOIN users u on u.a_no = a.a_no and u_status = 1
LEFT JOIN IDP1.contacts c on c.a_no = a.a_no and c_status = 1
where a_status = 1
group by a_no

Selecting data for 1 specific user from multiple tables

So my database is composed of 5 tables with different columns for each one. The only column that keeps them all identified is the id. I'm trying to get the data for a specific user, but I only seem to get all users of the database instead.
This is what I have tried:
SELECT
ControlAccess.UserName,
ControlAccess.Pass,
Users.First_Name,
Users.Last_Name,
UserInfo.Age,
UserInfo.Country,
UserInfo.Address,
UserInfo.ZipCode,
Sessions.Matrix1,
Sessions.Matrix2,
Sessions.Result,
Operations.Operation,
FilePath.LocationFiles
FROM
MatrixUsers.UserInfo
INNER JOIN
MatrixUsers.Users
ON
UserInfo.idUserInfo = Users.idUsers = 1
INNER JOIN
MatrixUsers.ControlAccess
ON
ControlAccess.idControlAccess = UserInfo.idUserInfo = 1
INNER JOIN
MatrixUsers.Sessions
ON
Sessions.idSessions = ControlAccess.idControlAccess = 1
INNER JOIN
MatrixUsers.FilePath
ON
FilePath.idFilePath = Sessions.idSessions = 1
INNER JOIN
MatrixUsers.Operations
ON
Operations.idOperations = FilePath.idFilePath = 1;
I tried putting 1 at the end of each id to see if they matched, but I still get all the users.
I'm new to SQL and I'm only familiar with matching rows, but not choosing specific one.
Here are the columns of each table:
ControlAccess: {idControlAccess, UserName, Pass}
Sessions: {idSessions, Matrix1, Matrix2, Result}
FilePath: {idFilePath, LocationFiles}
Operations: {idOperation, Operation}
UserInfo: {idUserInfo, Age, Country, Address, ZipCode, Phone}
Use WHERE when you want specific user. for example, select user_id from table where user_id=the_specific_user_id . Follow this basic to built you complicate statement.
Just user where after all the joins
WHERE ANY_COLUMN_REFER_TO_USER_ID = YOUR_NEEDED_ID
so your full query would be like :
SELECT
ControlAccess.UserName,
ControlAccess.Pass,
Users.First_Name,
Users.Last_Name,
UserInfo.Age,
UserInfo.Country,
UserInfo.Address,
UserInfo.ZipCode,
Sessions.Matrix1,
Sessions.Matrix2,
Sessions.Result,
Operations.Operation,
FilePath.LocationFiles
FROM MatrixUsers.UserInfo
INNER JOIN MatrixUsers.Users
ON UserInfo.idUserInfo = Users.idUsers
INNER JOIN MatrixUsers.ControlAccess
ON ControlAccess.idControlAccess = UserInfo.idUserInfo
INNER JOIN MatrixUsers.Sessions
ON Sessions.idSessions = ControlAccess.idControlAccess
INNER JOIN MatrixUsers.FilePath
ON FilePath.idFilePath = Sessions.idSessions
INNER JOIN MatrixUsers.Operations
ON Operations.idOperations = FilePath.idFilePath
WHERE UserInfo.idUserInfo = 1

Join multiple tables, keeping NULLs

I have 4 tables user, posts, follows, notifications. The posts table has a field called privacy in which a value of 1 means "anyone can see" and 2 means "only friends can see".
My notifications table looks like this:
id user_id tonotify_id notification post_id
1 2 3 --- 1
2 3 2 --- 2
3 2 4 --- 3
And my follows table looks like this:
id user_id tofollow_id status fstatus
1 1 2 1 1
2 1 3 1 1
The field fstatus value of 1 means that they are also friends.
Now I am trying to get all notifications sent out by people who a certain user is following (lets say a user with id 1). Assuming 1 is following user 2 and 3, I need to get all notifications from the above table. However, before this I need to make sure that the post (posted by the users in the tonotify_id column) is available. That is, I need to check the privacy setting. I have the following code:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
ORDER BY n.id DESC
It seems to be working except for one glitch. Since user 1 is not following user 4 all notifications aimed at 4, even if the posts are public don't show up. This my guess has to do with JOIN follows fr ON (n.tonotify_id = fr.tofollow_id) because, since the user 1 hasn't followed 4, there are no rows matching this join. Any suggestions to solving this?
I did try [the outer join], but the output is the same.
When you use an outer join, and then use one of the "outer" columns in an equality check in the WHERE clause, you convert your outer join to an inner join. This is because your condition that checks post's privacy requires the post to be there:
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
When an outer join is about to produce a row that corresponds to a notification without a post, it would check the above condition. Since the post is not there, p.privacy would evaluate to NULL, "contaminating" both sides of the OR, and eventually making the whole condition evaluate to false.
Moving this condition into the ON condition of the join will fix the problem:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
AND (p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
ORDER BY n.id DESC
Another way to fix this would be adding an IS NULL condition to your OR, like this:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
AND (p.privacy IS NULL OR p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
ORDER BY n.id DESC
You need to use an outer join such as LEFT JOIN instead of an inner join using just JOIN. An outer join will always return rows from one "side" (which is why it is called LEFT [OUTER] JOIN and RIGHT [OUTER] JOIN) even if the other "side" does not match anything.

SQL Query filtering advice

I'm not sure what I'm trying to do is possible but I've been trying to get different methods to a solution I need but so far I've come up empty handed.
Lets say I have 2 tables (just an example, in my case theres a hell of a lot more + alot more data)
One called clients and the other called form_data.
We have multiple clients in the clients table and in the form_data table we have multiple rows for each company present in the clients table. In form_data we store the serialized data from different forms. (id and data)
I'm currently pulling all records from the form_data table and I am trying to use a regexp on the data column to filter for instance that the value 'motor oil' is found in them.
I would like a way to do this filter but filter the company and not the forms .. so I want to find the forms that have 'motor oil' in them and the remove all entries for COMPANIES that don't have this match, but I want to keep all the forms showing for the companies that match.
I can post my query but it is rather long and i think if we can solve the above it should be sufficient for me to implement into the actual query.
Regards
EDIT:
SELECT f.form_question_has_answer_id AS f__form_question_has_answer_id, f.form_question_has_answer_request AS f__form_question_has_answer_request,
f.form_question_has_answer_form_id AS f__form_question_has_answer_form_id, f.form_question_has_answer_user_id AS f__form_question_has_answer_user_id,
p.project_company_has_user_id AS p__project_company_has_user_id, p.project_company_has_user_project_id AS p__project_company_has_user_project_id,
p.project_company_has_user_user_id AS p__project_company_has_user_user_id, c.company_id AS c__company_id, c.company_hall_no AS c__company_hall_no,
c.company_type AS c__company_type, c.company_company_name AS c__company_company_name, c.company_country AS c__company_country,
c.company_stand_number AS c__company_stand_number, c.company_image_file_1 AS c__company_image_file_1, p2.project_id AS p2__project_id,
p2.project_name AS p2__project_name, u.user_id AS u__user_id, u.user_username AS u__user_username, f2.form_id AS f2__form_id
FROM form_question_has_answer f
INNER JOIN project_company_has_user p ON f.form_question_has_answer_user_id = p.project_company_has_user_user_id
INNER JOIN company c ON p.project_company_has_user_company_id = c.company_id
INNER JOIN project p2 ON p.project_company_has_user_project_id = p2.project_id
INNER JOIN user u ON p.project_company_has_user_user_id = u.user_id
INNER JOIN form f2 ON p.project_company_has_user_project_id = f2.form_project_id
WHERE f.form_question_has_answer_id IN ('19262', '21560', '23088', '22660', '14772', '18495', '18720', '21625', '19957', '20943')
AND ((f2.form_template_name = "custom" AND p.project_company_has_user_garbage_collection = 0 AND p.project_company_has_user_project_id = 29) AND f.form_question_has_answer_request REGEXP 'item-cadcae')
ORDER BY company_company_name asc
The query is from a doctrine query.
EDIT:
If i have a company with 10 forms in the form_data table if i filter by 'motor oil' all forms for that company that don't have motor oil are removed.. so if only 1 of the 10 forms for company id 144 has the word motor oil then the other 9 forms are lost in the query.. I want to keep them. What I want is any company that didn't find any forms with that match (motor oil) to have all their forms removed from the search.
All form data for all customers who have at least one form that matches the search:
SELECT * FROM `form_data`
WHERE `clientid` IN (
SELECT DISTINCT `clientid` FROM `form_data`
WHERE `data` RLIKE '[[:<:]]motor oil[[:>:]]'
);
SELECT
c.*
FROM
clients as c
INNER JOIN (
select
*
from
forms
where
sometext like '%motor oil%'
) as f
ON f.client = c.id
http://sqlfiddle.com/#!3/5b616/1
in this part:
select
*
from
forms
where
sometext like '%motor oil%'
you can put any query that selects the relevant rows from your forms table with the appropriate filters.
you can do the inverse too with a left outer join where null technique.. though in this case modifying the subquery to return a list of distinct clients will probably give you more like the results you expect:
SELECT
c.*
FROM
clients as c
LEFT OUTER JOIN (
select
distinct
client
from
forms
where
sometext like '%motor oil%'
) as f
ON f.client = c.id
where f.client is null
http://sqlfiddle.com/#!3/5b616/4
so with your query something like:
SELECT
c.*
FROM
company AS c
INNER JOIN (
SELECT
DISTINCT c.company_id
FROM
form_question_has_answer f
INNER JOIN project_company_has_user p
ON f.form_question_has_answer_user_id = p.project_company_has_user_user_id
INNER JOIN company c
ON p.project_company_has_user_company_id = c.company_id
INNER JOIN project p2
ON p.project_company_has_user_project_id = p2.project_id
INNER JOIN user u
ON p.project_company_has_user_user_id = u.user_id
INNER JOIN form f2
ON p.project_company_has_user_project_id = f2.form_project_id
WHERE
f.form_question_has_answer_id IN ('19262', '21560', '23088', '22660', '14772', '18495', '18720', '21625', '19957', '20943')
AND ((f2.form_template_name = "custom"
AND p.project_company_has_user_garbage_collection = 0
AND p.project_company_has_user_project_id = 29)
AND f.form_question_has_answer_request REGEXP 'item-cadcae')
ORDER BY company_company_name asc
) as f
ON f.company_id= c.id
Not sure What do you mean by keeping all the forms showing for the companies that match?
Aren't just getting at this...
select * from clients inner join form_data on clients.id = form_data.id where form_data.[data] like '%motor oil%'
This will return all forms with 'motor oil' in them filled for the companies which also have 'motor oil' in their name:
SELECT *
FROM clients c
JOIN form_data fd
ON fd.client = c.id
WHERE fd.data RLIKE '[[:<:]]motor oil[[:>:]]'
AND c.name RLIKE '[[:<:]]motor oil[[:>:]]'

How to use MYSQL's "AS" returned value inside WHERE clause?

I have a query like below...
SELECT
contents.id, contents.title, contents.createdBy,
(SELECT userGroup FROM suser_profile WHERE userId =
(SELECT users.id
FROM
users
WHERE
login = contents.createdBy)
) as userGroupID
FROM
contents
WHERE
contents.id > 0
AND contents.contentType = 'News'
**AND userGroupID = 3**
LIMIT 0, 10
When I try to assign the userGroupID inside WHERE clause the SQL fires an error saying SQL Error(1054):Unknown column "userGroupID" in "where clause"
meantime, if I make little changes like below,,
SELECT
contents.id, contents.title, contents.createdBy
FROM
smart_cms_contents
WHERE
contents.id > 0
AND contents.contentType = 'News'
**AND (SELECT userGroup FROM user_profile WHERE userId =
(SELECT users.id
FROM
users
WHERE
users.login = contents.createdBy)
) = 3**
LIMIT 0, 10
then the query works fine.
I have to use multiple userGroupID checking so that, 2nd style will make the query big, I have to have an style like first one, any help appreciated.
*NOTE : Table names are not original name what I am using in my project. You may ignore it if there are mistakes in table name. My main concern is on using the values assign to a variable by AS inside the WHERE clause.
Ignore the STARS in query*
use HAVING. example:
WHERE
contents.id > 0
AND
contents.contentType = 'News'
HAVING
userGroupID = 3
LIMIT 0, 10
If I'm understanding your initial query properly, then I believe what you want to do is a join:
SELECT DISTINCT
contents.id, contents.title, contents.createdBy
FROM
contents INNER JOIN users
ON contents.createdBy = users.login
INNER JOIN user_profile
ON user_profile.userId = users.id
WHERE
contents.id > 0
AND contents.contentType = 'News'
AND user_profile.userGroupID = 3
LIMIT 0, 10
Totally not the answer to the question you asked, but...
SELECT DISTINCT c.id, c.title, c.createdBy, s.userGroup AS userGroupID
FROM contents AS c
INNER JOIN users AS u
ON c.createdBy = u.login
INNER JOIN suser_profile AS s
ON s.userId = u.id
WHERE c.id > 0
AND c.contentType = 'News'
AND s.userGroup = 3