I am having a small issue with MYSQL relations.
There is for every 1 value in table 1, there can be a multitude of values (0+) in table 2.
I am able to get all the data correctly, however, the issue comes when some values in table 2 differ, specifically the "taken up" field.
$sql = "
SELECT
accounts.name AS business,
accounts.industry AS style,
accounts_cstm.renewaldate_c AS ren_date,
accounts_cstm.nolongercontact_c AS NLC,
accounts_cstm.contactname_c AS person,
campaigns.name AS campaign,
users.first_name AS exec_fn,
users.last_name AS exec_sn,
email_addr_bean_rel.bean_id AS bean_id,
email_addresses.email_address AS email,
qs_quotationinformation.takenup AS takeup,
email_addr_bean_rel.email_address_id AS email_id
FROM
accounts
LEFT JOIN
campaigns ON accounts.campaign_id = campaigns.id
LEFT JOIN
users ON accounts.assigned_user_id = users.id
INNER JOIN
accounts_cstm ON accounts.id = accounts_cstm.id_c
LEFT JOIN
email_addr_bean_rel ON accounts.id = email_addr_bean_rel.bean_id
LEFT JOIN
email_addresses ON email_addr_bean_rel.email_address_id = email_addresses.id
LEFT JOIN
qs_quotamation_accounts_c ON accounts.id = qs_quotamation_accounts_c.qs_quot108funts_ida
LEFT JOIN
qs_quotationinformation ON qs_quotamation_accounts_c.qs_quotdb81tion_idb = qs_quotationinformation.id
WHERE
accounts.deleted = 0";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
if($row["NLC"] == 1 || $row["takeup"] == 1){$NLC = "No";}else{$NLC = "Yes";}
echo '<tr><td>'.$row['business'].'</td><td>'.$row["style"].'</td><td>'.$row["ren_date"].'</td><td>'.$NLC.'</td><td>'.$row["person"].'</td><td>'.$row["campaign"].'</td><td>'.$row["exec_fn"].' '.$row["exec_sn"].'</td><td>'.$row["email"].'</td><td>'.$row["takeup"].'</tr>';
}
} else {
echo "0 results";
}
In this case Table 1 is "accounts" and Table 2 is "qs_quotationinformation".
There are some accounts in Table 1 which have multiple records in Table 2, and some of the "takenup" records in Table 2 (relating to the same account) can be 1 and some be 0.
So what I need to do is have it so that if any of the records in Table 2 = 1, then all of the variables of $NLC need to = "No".
I don't know if this is possible, or if there is a better way to get this information. The html table is missing data that gets pulled, but that's because the table is just a visual representation of the most important data to the user.
EDIT Tables (excluding personal data):
Table 1:
+----+---------+---------+
| id | name | deleted |
+----+---------+---------+
| 1 | example | 0 |
+----+---------+---------+
Table 2:
+----+---------+
| id | takenup |
+----+---------+
| 1 | 0 |
+----+---------+
| 2 | 1 |
+----+---------+
| 3 | 0 |
+----+---------+
All of the rows in Table 2 relate to the row in Table 1. But because there is a row with takenup = 1 $NLC needs to return "No" and not "Yes" (which it currently does because the last related row is 0)
So, if you understand you correctly, if you have an account, that has a corresponding qs_quotationinformation.takenup value of 1, then the query should return "No" for accounts_cstm.nolongercontact_c AS NLC for all records with the same account id, regardless of the value of qs_quotationinformation.takenup field in the other records.
In this case you need to get the list of accounts that have qs_quotationinformation.takenup=1 and you can use a subquery to return this information, which can be left joined to the main query. accounts_cstm.nolongercontact_c AS NLC would be changed to a case expression to return the "No" value based on the subquery.
SELECT
accounts.name AS business,
accounts.industry AS style,
accounts_cstm.renewaldate_c AS ren_date,
case
when no_nlc.qs_quot108funts_ida is null then accounts_cstm.nolongercontact_c
else 'No'
end AS NLC,
accounts_cstm.contactname_c AS person,
campaigns.name AS campaign,
users.first_name AS exec_fn,
users.last_name AS exec_sn,
email_addr_bean_rel.bean_id AS bean_id,
email_addresses.email_address AS email,
qs_quotationinformation.takenup AS takeup,
email_addr_bean_rel.email_address_id AS email_id
FROM
accounts
LEFT JOIN
campaigns ON accounts.campaign_id = campaigns.id
LEFT JOIN
users ON accounts.assigned_user_id = users.id
INNER JOIN
accounts_cstm ON accounts.id = accounts_cstm.id_c
LEFT JOIN
email_addr_bean_rel ON accounts.id = email_addr_bean_rel.bean_id
LEFT JOIN
email_addresses ON email_addr_bean_rel.email_address_id = email_addresses.id
LEFT JOIN
qs_quotamation_accounts_c ON accounts.id = qs_quotamation_accounts_c.qs_quot108funts_ida
LEFT JOIN
qs_quotationinformation ON qs_quotamation_accounts_c.qs_quotdb81tion_idb = qs_quotationinformation.id
LEFT JOIN
(SELECT
qs_quot108funts_ida
FROM
qs_quotamation_accounts_c
INNER JOIN
qs_quotationinformation ON qs_quotamation_accounts_c.qs_quotdb81tion_idb = qs_quotationinformation.id
WHERE
qs_quotationinformation.takenup = 1) no_nlc ON accounts.id = no_nlc.qs_quot108funts_ida
WHERE
accounts.deleted = 0
The case expression assumes that accounts_cstm.nolongercontact_c field is of a string type (char, varchar, etc). If this is not the case, then you need to cast the value of accounts_cstm.nolongercontact_c field to char using the cast() function.
Related
I have a messaging app that I want to display messages like facebook, it should get the last send message by either the sender or recipient, my table layout is like this:
messages_tbl
__________________________________________________________________________
|id | user1Fk| user2Fk |subject | user1Delete | user2Delete | dateCreated |
and my user_tbl
_______________________________________
| id | first_name | last_name | image |
my Query
SELECT `id` , `user1Fk` as sender_id,
(SELECT concat(first_name,\" \",last_name)
FROM user_tbl
WHERE user_tbl.id = sender_id
) as senderName,
`user2Fk` as recipient_id ,
(SELECT concat(first_name,\" \",last_name)
FROM user_tbl
WHERE user_tbl.id = recipient_id
) as recipientName,
(SELECT image
FROM user_tbl
WHERE user_tbl.id = sender_id
) as senderImage,
(SELECT image
FROM user_tbl
WHERE user_tbl.id = recipient_id
) as recipientImage,
`subject`, `message`, `user1Delete`, `user2Delete`,
`dateCreated`
FROM `message_tbl`as m1
WHERE dateCreated = (SELECT MAX(m2.dateCreated)
from message_tbl as m2
WHERE (m1.user1Fk = m2.user1Fk
AND m1.user2Fk = m2.user2Fk
OR m1.user1Fk = m2.user2Fk
AND m1.user2Fk = m2.user1Fk
)
) AND ? IN (m1.user1Fk, m1.user2Fk)
ORDER BY dateCreated DESC
This query is working for the most part but its lacking, I want it to check, if the given id by the ? matches user1Fk it should then check if user1Delete is a 0 or 1, if its a 1 then do not display the message user 1 deleted it, the same with user 2 but I cannot think of the logic, can anyone help me?
I'm assuming that the question mark is there because this is a prepared query and the question mark should be replaced with a user id.
Your query is a little bit over complicated because there are a lot of subselects. I tried to improve it a bit for better performance and to be able to extend it easier. With SQL you can join tables instead of using subqueries, this is better for performance, and it makes it easier to add conditions to the joined tables.
In the example below I added a condition for both the user1 and user2 delete fields to be 0. I set the limit to 1, which means only the first row will be returned. Together with the descending order of the date, this means that only the newest message will be returned. I also changed the question mark to :user_id because in this example it is used twice and this way you'll only have to add it once.
SELECT
m.id,
u1.id AS sender_id,
CONCAT(u1.first_name, ' ', u1.last_name) AS senderName,
u2.id AS recipient_id,
CONCAT(u2.first_name, ' ', u2.last_name) AS recipientName,
u1.image AS senderImage,
u2.image AS recipientImage,
m.subject,
m.message,
m.user1Delete,
m.user2Delete,
m.dateCreated
FROM messages_tbl m
INNER JOIN user_tbl u1 ON m.user1Fk = u1.id
INNER JOIN user_tbl u2 ON m.user2Fk = u2.id
WHERE (m.user1Delete = 0 AND u1.id = :user_id)
OR (m.user2Delete = 0 AND u2.id = :user_id)
ORDER BY m.dateCreated DESC
LIMIT 1
I haven't been able to test it but I hope this is what you were looking for.
I have 3 table: user , company and deal.
One user may own several companies. Deal is made between the 2 companies. I need a list of deals, which involved my company.
Deals must contain the following fields: partner_company_id,my_company_id,partner_photo,partner_name,deal_about.
Language code: PHP.
Database: Mysql.
1.List of my company I can get by user ID.
user_id = 22;
companyList = query('SELECT company_id FROM company WHERE user_id = ?', user_id);
2. Then i get deal list where my_company_id is company_first_id
list1 = query('SELECT u.name AS partner_name, u.photo AS partner_photo, d.first_company_id AS
my_company_id , d.second_company_id AS partner_company_id,d.about AS deal_about FROM deal AS d
INNER JOIN company AS c ON c.company_id = d.second_company_id
INNER JOIN user AS u ON u.user_ud = c.user_id
WHERE d.company_first_id IN (?)', companyList);
3. Then i get deal list where my_company_id is company_second_id
list2 = query('SELECT u.name AS partner_name, u.photo AS partner_photo, d.first_company_id AS
partner_company_id , d.second_company_id AS my_company_id,d.about AS deal_about FROM deal AS d
INNER JOIN company AS c ON c.company_id = d.first_company_id
INNER JOIN user AS u ON u.user_ud = c.user_id
WHERE d.company_second_id IN (?)', companyList);
4. then i marge to array and set limit list
list = array_marge(list1,list2);
result = array_slice (list ,0 , 10);
HELP please optimize this queries.
THANKS.
DATABASE SCHEME
user | company | deal |
--------------------------------------------------
user_d | company_id | deal_id
photo | user_id |first_company_id
name | about |second_company_id
| |description
Are your queries so slow? They don't look slow (provided you have indexes on all IDs of course).
However, you can save one database access by combining the two deal queries. Either you simply select query1 UNION ALL query1 or you do it in one pass:
select
u.name AS partner_name,
u.photo AS partner_photo,
d.my_company_id,
d.partner_company_id,
d.about AS deal_about
from
(
select
about,
case when company_first_id in (?) then
company_first_id
else
company_second_id
end as my_company_id,
case when company_first_id in (?) then
company_second_id
else
company_first_id
end as partner_company_id
from deal
where company_first_id in (?) OR d.company_second_id in (?)
) as d
inner join company as c on c.company_id = d.partner_company_id
inner join user as u on u.user_ud = c.user_id
I have the table news_feed in which all of my different types of activities data will be stored like admin activities, user activities, company activities etc. The table format looks like:
news_id | type | admin_id | user_id | company_id
1 | admin | 2 | 3 | 0
2 | user | 3 | 4 | 1
3 | company | 0 | 1 | 2
Suppose a user with an id 1 has liked the company which has id 2 then the record will be inserted like
4 user 0 1 2
And I'm listing them in my module and the listing is perfect. But suppose if the company id 2 doesn't exist or if it is inactive, then the news_feed block in listing getting empty. What I want to do is:
If the type is company then JOIN the company table while select listing with condition for status as active
If the type is user then JOIN the user table while select listing with condition for status as active
Well you can use UNION for this issue
SELECT t.column1, t.column2, t.column3
FROM my_table t INNER JOIN company_table c
ON t.company_id = c.id
WHERE c.active=1 AND t.type = "company"
UNION
SELECT column1, column2, column3
FROM my_table t INNER JOIN user_table u
ON t.user_id = u.id
WHERE c.active=1 AND t.type = "user"
Just to add, to increase the efiiciency use UNION ALL rather than UNION (or UNION DISTINCT) as UNION requires internal temporary table with index (to skip duplicate rows) while UNION ALL will create table without such index, but keep in mind it will skip the repeated data.
But more optimized way to do a Conditional Join in MySQL by using a INNER JOIN
SELECT t.column1, t.column2, t.column3
FROM my_table t
INNER JOIN company_table c
ON (t.company_id = c.id AND t.type = "company" AND c.active=1)
INNER JOIN user_table u
ON (t.user_id = u.id AND t.type = "user" AND u.active=1);
I have 3 tables.
myMembers
------------------------------------
id | username | privacy
------------------------------------
1 | userA | 0
2 | userB | 1
3 | userC | 0
4 | userD | 1
following
--------------------------------
id | user_id | follower_id
--------------------------------
1 | 2 | 1
posts
-------------------------------------
id | userID | username | statusMsg
--------------------------------------
1 | 4 | userD | Issac Newton is genius
2 | 2 | userB | Newton Saw apple
3 | 3 | userC | Newtonian Physics
4 | 1 | userA | Calculus came from Sir Newton
There is a search field. When a logged in user searches for 'keyword' in table 'posts', I want to omit results from those users who has set his privacy to '1' and WHERE searcher is not following user B.
The query should logically do this.
SELECT * from posts WHERE (match the keyword)
AND (
if (poster's privacy (which is set in myMembers)==1){
if (seacher is following poster){
select this post
}
}
else { select this post
}
)
LIMIT results to 5 rows
So for a keyword "Newton",
if userA is searching, rows 2,3,4 from 'posts' should be returned.
if userD is searching, only rows 1, 3 and 4 from 'posts' should be returned,
based on privacy and following
Edit: Tagging for future searches: IF condition within WHERE Clause in mySql
Please, try this query (also on SQL Fiddle):
SELECT p.id, p.user_id, m.username, m.privacy,
searcher.username "Searcher", p.status_msg
FROM posts p
JOIN members m ON m.id = p.user_id
LEFT JOIN following f ON p.user_id = f.user_id
JOIN members searcher ON searcher.username = 'userA'
WHERE (m.privacy = 0 OR (m.privacy = 1 AND f.follower_id = searcher.id)
OR m.id = searcher.id)
AND p.status_msg LIKE '%New%'
ORDER BY p.id
LIMIT 5;
I removed username field from posts table, as it is redundant. Also, I named tables and columns slightly different, so query might need cosmetic changes for your schema.
The first line in the WHERE clause is the one that you're looking for, it selects posts in the following order:
First posts from members without privacy;
Then posts from members that are followed by the current searcher;
Finally, posts of the member himself.
EDIT:
This query is using original identifiers:
SELECT p.id, p.`userID`, m.username, m.privacy,
searcher.username "Searcher", p.`statusMsg`
FROM posts p
JOIN `myMembers` m ON m.id = p.`userID`
LEFT JOIN following f ON p.`userID` = f.user_id
JOIN `myMembers` searcher ON searcher.username = 'userD'
WHERE (m.privacy = 0 OR f.follower_id = searcher.id OR m.id = searcher.id)
AND p.`statusMsg` LIKE '%New%'
ORDER BY p.id
LIMIT 5;
EDIT 2:
To avoid duplicates in case there're several followers for the user from the posts table, join and filtering conditions should be changed the following way (on SQL Fiddle):
SELECT p.id, p.user_id, m.username, m.privacy,
searcher.username "Searcher", p.status_msg
FROM posts p
JOIN members m ON m.id = p.user_id
JOIN members searcher ON searcher.username = 'userC'
LEFT JOIN following f ON p.user_id = f.user_id
AND follower_id = searcher.id
WHERE (m.privacy = 0 OR (m.privacy = 1 AND f.id IS NOT NULL)
OR m.id = searcher.id)
ORDER BY p.id
LIMIT 5;
Try the following:
SET #my_user_id= 1;
SELECT * FROM posts p
INNER JOIN myMembers m ON p.user_id= m.id
WHERE statusMsg LIKE '%'
AND privacy=0
AND user_id IN (SELECT follower_id FROM following f WHERE f.user_id=#my_user_id)
LIMIT 5
try this:
SELECT a.*
FROM posts a
LEFT JOIN (SELECT user_id
FROM following a1
INNER JOIN myMembers b1
ON a1.follower_id = b1.id
WHERE a1.follower_id = 1 AND
b1.privacy = 1
) b
ON a.userID = b.user_id AND
WHERE a.statusMsg LIKE '%search%' AND
b.user_id IS NULL
LIMIT 5;
or better approach without subquery:
SELECT a.*
FROM posts a
LEFT JOIN myMembers b
ON a.userID = b.id AND
b.privacy = 1
LEFT JOIN following c
ON a.userID = c.user_id AND
c.follower_id = 1
WHERE a.statusMsg LIKE '%search%' AND
b.id IS NULL AND
c.user_id IS NULL
LIMIT 5;
See: A Visual Explanation of SQL Joins
I have multiple tables in my database. Let's say the table users looks like this:
Users:
|id|name|gender|access|id_ext|
|1 | a | m | 1 | 32 |
|3 | b | m | 3 | 33 |
|4 | c | m | 1 | 34 |
|5 | d | f | 1 | 35 |
I would like to select the user with for example id_ext = 32 and then run another select statement using that selected users fields.
I can solve this by first getting the user with a query and then create another query with users info, but there must be a way to do this in the same query?
This is the query i use now:
SELECT * FROM users NATURAL JOIN
(SELECT id FROM ages WHERE age BETWEEN
(SELECT limit_age_l FROM users WHERE id=17)
AND (SELECT limit_age_h FROM users WHERE id=17)) as a
WHERE NOT id = 17
AND locale = 'en_US'
AND limit_gender = 1
AND visible = 0
AND NOT EXISTS (SELECT view_id FROM matches WHERE user_id = 17 AND view_id = a.id)
LIMIT 1
Problem is that the values id=17, limit_gender=1 and locale = 'en_US' in the query are not known. These are taken from the user with id_ext = '32'.
SELECT * FROM Users WHERE id in (SELECT id FROM Users WHERE id_ext='32');
Yes - assuming your subsequnt query is of the form:
select field1, field2, ...
from Table1
join Table2 on ...
where ...
and Table1.id = N /* previously selected id from users */
Then either by using the first query as a subquery:
select field1, field2, ...
from Table1
join Table2 on ...
where ...
and Table1.id = (select id from users where id_ext ='32')
/* replace = with IN if more than one id will be returned */
Or by joining to the results of the first query as part of the subsequent query:
select field1, field2, ...
from users
join Table1 on Table1.id = users.id
join Table2 on ...
where ...
and users.id_ext ='32'
(Note that both of these forms assume that users is not already being joined in the existing query - if it is, just add the users.id_ext ='32' condition to the existing query.)
EDIT: If I have understood the requirements correctly, the required query could be written as:
SELECT u.*
FROM users u
join ages a on u.id = a.id and
u.age between limit_age_l and limit_age_h
join users ul on ul.id = 17 and
ul.id <> u.id and
ul.locale = u.locale and
ul.limit_gender = u.limit_gender and
ul.visible = u.visible
AND NOT EXISTS (SELECT NULL
FROM matches m
WHERE m.user_id = ul.user_id AND m.view_id = a.id)
LIMIT 1
SELECT * FROM users WHERE id = (SELECT id FROM users WHERE id_ext = '32');
Select * from users as user inner join userinfo as usinfo on usinfo.id=user.id_ext where user.id_ext='32'