How to join with unknown condition like pivot in mysql - php

I have the following code to
public function get_posted_questions($data) {
include dirname(__FILE__) . "/database.php";
$user_db_name = $dbconfig[$data['college_id']]['database'];
if (isset($data['start'])) {
$start = $data['start'];
} else {
$start = 0;
}
if (isset($data['end']) and ! empty($data['end'])) {
$end = $data['end'];
} else {
$end = 30;
}
/*
* multiple college database funda here goes
*/
$max_college_id = "
SELECT DISTINCT college_id
FROM just_ask_question
WHERE
status = '1'
AND isDeleted = '0'
AND college_id !='0'
ORDER BY id DESC
LIMIT $start, $end
";
$max_college_id_run = mysql_query($max_college_id);
$question_data = array();
$question_query = "
SELECT
Q.id,
Q.title,
Q.description,
Q.user_id,
Q.college_id,
Q.datetime,
IFNULL(GROUP_CONCAT(DISTINCT T.name),'') AS tags,
IFNULL(CONCAT_WS(' ',U.firstName,U.lastName),'') AS user_name
IFNULL(U.image,'') AS image,
IFNULL(V.id,'') AS no_of_view,
IFNULL(Vote.upvote,'') AS up_vote,
IFNULL(answer.id,0) AS no_of_answer,
IFNULL(is_upvote,0) AS upvote_status,
category_name
FROM just_ask_question AS Q
LEFT JOIN just_ask_question_tag Qt
ON Qt.question_id = Q.id
LEFT JOIN just_ask_tag T
ON T.id = Qt.tag_id
LEFT JOIN just_ask_category
ON just_ask_category.id = Q.category_id
LEFT JOIN
(
SELECT COUNT(id) as id, question_id FROM just_ask_answer
) AS answer ON answer.question_id = Q.id
";
while ( $row = mysql_fetch_assoc($max_college_id_run) ) {
$user_db_name = $dbconfig[$row['college_id']]['database'];
$question_query .= "
CASE WHEN Q.college_id = '".$row['college_id']."'
THEN LEFT JOIN $user_db_name.users U ON U.id = Q.user_id
";
}
$question_query .= "
LEFT JOIN
(
SELECT count(id) AS id, question_id FROM just_ask_view
) AS V ON V.question_id = Q.id
LEFT JOIN
(
SELECT
COUNT(upvote) as upvote,
question_id
FROM just_ask_upvote_downvote
WHERE upvote = '1' AND is_question = '1'
GROUP BY question_id
) AS Vote
ON Vote.question_id = Q.id
LEFT JOIN
(
SELECT
IF(COUNT(id) > 0,1,0) AS is_upvote,
question_id
FROM just_ask_upvote_downvote
WHERE
upvote = '1'
AND college_id = '" . $data['college_id'] . "'
AND user_id = '" . $data['user_id'] . "'
AND is_question = '1'
) AS Is_Vote
ON Is_Vote.question_id = Q.id
WHERE
Q.status = '1'
AND Q.isDeleted = '0'
AND CASE
WHEN Q.visibility = 0 AND Q.college_id != 0 THEN Q.college_id = '" . $data['college_id'] . "'
ELSE true
END
";
if (!empty($data['search_text'])) {
$search_text = $data['search_text'];
$question_query .= " and (Q.title like '%$search_text%' or Q.description like '%$search_text%' or T.name like '%$search_text%')";
}
$question_query .= " group by Q.id order by Q.id desc limit $start,$end";
$question_query_run = mysql_query($question_query);
/* get weather question exist */
$check_num_rows = mysql_num_rows($question_query_run);
if ($check_num_rows > 0) {
while ($row = mysql_fetch_assoc($question_query_run)) {
if ($row['image'] != '') {
$row['thumbnail'] = USER_THUMBNAIL_URL . $row['image'];
$row['image'] = IMAGE_URL . $row['image'];
} else
$row['thumbnail'] = '';
$question_data[] = $row;
}
$status['statuscode'] = "1";
$status['statusmessage'] = "ok";
$status['question_data'] = $question_data;
$response['response'] = $status;
echo json_encode($response);
die();
}else {
$status['statuscode'] = "2";
$status['statusmessage'] = "There is no record found";
$response['response'] = $status;
echo json_encode($response);
die();
}
}
AND the db config file like which contain the database name information
like
$dbconfig['1'] = array(
'host' => 'localhost',
'user_name' => 'root',
'password' => 'test123*',
'database' => 'staging_myuniversity'
);
$dbconfig['2'] = array(
'host' => 'localhost',
'user_name' => 'root',
'password' => 'test123*',
'database' => 'staging_myuniversity_dias'
);
the database are reside on same server and with full permission.
the query generate like this
select Q.id,Q.title,Q.description,Q.user_id,Q.college_id,
Q.datetime,
ifnull(group_concat(distinct T.name),'') as tags,
ifnull(CONCAT_WS(' ',
U.firstName,U.lastName),'') as user_name,
ifnull(U.image,
'') as image,ifnull(V.id,'') as no_of_view,
ifnull(Vote.upvote,
'') as up_vote,
ifnull(answer.id,0) as no_of_answer,
ifnull(is_upvote,
0
) as upvote_status,
category_name
from just_ask_question as Q
left join just_ask_question_tag Qt on Qt.question_id = Q.id
left join just_ask_tag T on T.id = Qt.tag_id
left join just_ask_category on just_ask_category.id = Q.category_id
left join
( SELECT count(id) as id,question_id
from just_ask_answer
) as answer on answer.question_id = Q.id case when Q.college_id = '1' then
left join staging_myuniversity.users U on U.id = Q.user_id case when Q.college_id = '12'then
left join campify_solutions_mathura.users U on U.id = Q.user_id case when Q.college_id = '4' then
left join staging_myuniversity_nit_kkr.users U on U.id = Q.user_id case when Q.college_id = '2' then
left join staging_myuniversity_dias.users U on U.id = Q.user_id
left join
( SELECT count(id) as id,question_id
from just_ask_view
) as V on V.question_id = Q.id
left join
( SELECT count(upvote) as upvote,question_id
from just_ask_upvote_downvote
where upvote = '1'
and is_question = '1'
group by question_id
) as Vote on Vote.question_id = Q.id
left join
( SELECT if(count(id) > 0,1,0) as is_upvote,question_id
from just_ask_upvote_downvote
where upvote = '1'
and college_id = '1'
and user_id = '1'
and is_question = '1'
) as Is_Vote on Is_Vote.question_id = Q.id
where Q.status = '1'
and Q.isDeleted = '0'
and case when Q.visibility = 0
and Q.college_id != 0 then Q.college_id = '1' else true end
group by Q.id
order by Q.id desc
limit 0,30
I need to make the join on different databases based on college id
first i fetch the distinct college id from the question then make a loop
for college id and try to make join condition but i am getting error there is any suggestion and help

I won't help you with entire query (I'll just list some concerns), but this "case-join" might be solved with UNION ALL subquery this way:
INNER JOIN (
SELECT 1 AS college_id, id, firstName, lastName, image
FROM staging_myuniversity.users
UNION ALL
SELECT 12 AS college_id, id, firstName, lastName, image
FROM campify_solutions_mathura.users
UNION ALL
...
) AS U ON U.college_id = Q.college_id AND U.id = Q.user_id
When you join counters with subqueries like SELECT count(), some_id use GROUP_BY some_id as well. Otherwise you'll count all rows in table and join this result for one (first/random) id only (if it passes without error).
It looks like You use LEFT JOIN too much. It means attach to the result on left regardless if any row on the right matches (joins null columns then). It's slow, gives large data sets and results with nulls for most of these columns seems useless.
Join subquery with GROUP BY clause to get concatenated tags
If large portion of this data will be repeated across the rows (see: N+1 problem) splitting queries (and merging subsets to common "header") might be a good idea.
Build your query one step at a time. Test subqueries if you're not sure of its results. Start with resource consuming parts - it might get slow at some point and you'll end up splitting it anyway.

... case when Q.college_id = '1' then left join ...
does not make sense. What are you trying to do?
Performance tip: Don't use LEFT JOIN ( SELECT ... ) Instead of that and IFNULL(...), simply do
SELECT ...,
IFNULL(( SELECT ... ), '') AS upvotes,
As for pivoting, I must say simply, and strongly, that some tasks are better left to your application code, not SQL.

Related

how to write a left join for make loop

I want to write this code in one query with left join statement. Currently I use php for loop this query but its not good and is too slow
It's app that have like and dislike option. I want number of every user's like
public function getUserLikedCount($id) {
$query = $this->db->query(
"SELECT * FROM `users`, post, `like`
WHERE users.id = post.post_user_id
AND like.like_post_id = post.post_id
AND users.id = ?
AND post.post_is_active = 1", array($id)
);
return $query->num_rows();
}
thanks
Try like it ( I don't know your table like structure):
$sql = 'SELECT u.id AS `user_id`
COUNT(p.post_id) AS `liked_cnt` <-- or like.id ( if this field exists)
FROM `post` AS p
LEFT JOIN `users` AS u
ON ( u.id = p.post_user_id )
LEFT JOIN `like` AS l
ON ( l.like_post_id = p.post_id )
WHERE p.post_is_active = 1
AND l.status = 1 <-- "liked"
GROUP BY u.id ';
Try this :
$query = $this->db->query(
"SELECT * FROM `users` u
LEFT JOIN post p ON u.id = p.post_user_id AND u.id =?
LEFT JOIN like l ON l.like_post_id = p.post_id AND p.post_is_active = 1
", array($id)

Laravel / MySQL console different results

I am using laravel and I have this method inside one model.
When I run the query in PhpMyAdmin or in the MySQL console I get the expected result.
When running it in Laravel, I always get the same row which doesn't even fulfill the "where" statements in the query. Same luck when using ORDER BY RAND()
public static function getPotentialMatch($id, $genderId = NULL)
{
$query = "SELECT
student.id AS id,
(SELECT COUNT(*) FROM matches AS m WHERE m.local_student_id = student.id) AS matches
FROM
users AS user
JOIN students AS student
ON user.id = student.user_id
LEFT OUTER JOIN languages_student AS ls
ON student.id = ls.student_id
LEFT OUTER JOIN languages AS language
ON ls.language_id = language.id
LEFT OUTER JOIN courses AS course
ON student.course_id = course.id
WHERE ls.language_id IN
(
SELECT ls.language_id AS languageId
FROM languages_student AS ls
JOIN students AS student1
ON ls.student_id = student1.id
JOIN users AS user1
ON student1.user_id = user1.id
WHERE student1.id = " . $id . "
)
AND student.course_id IN
(
SELECT courseR.id AS affinityId
FROM courses AS course
JOIN course_affinities
ON course.id = course_affinities.course1_id
OR course.id = course_affinities.course2_id
JOIN courses AS courseR
ON (courseR.id = course_affinities.course1_id
AND courseR.id <> course.id)
OR (courseR.id = course_affinities.course2_id
AND courseR.id <> course.id)
WHERE course.id IN
(
SELECT student.course_id
FROM students AS student
WHERE student.id = " . $id . "
)
)
AND student.incoming = 0
AND student.active = 1
AND (
SELECT COUNT(*)
FROM matches AS m
WHERE m.local_student_id = student.id
) < 3
";
if ($genderId != NULL) {
$query .= " AND student.gender_id = " . $genderId;
}
$query .= " ORDER BY (SELECT COUNT(*) FROM matches AS m WHERE m.local_student_id = student.id)
LIMIT 1";
return DB::select(DB::raw($query));
}
Any ideas?

Issue with an mySQL sentence including two temporary table creation

I have a mySQL sentence that works like a charm if I execute it in my phpMyAdmin:
CREATE TEMPORARY TABLE hash1
SELECT * FROM
(
(
SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '1' AND feature_value = 'No frost total'
) UNION
(
SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '3' AND feature_value = '43'
)) AS q;
CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;
SELECT
p.id AS id,
p.main_image AS main_image,
p.type AS taxonomy,
p.name AS model,
p.sku AS sku,
p.price AS price,
b.brand_name AS brand_name,
b.brand_image AS brand_logo,
pf.feature_value AS feature_value,
f.feature AS feature_label,
f.id AS feature_id
FROM
(
SELECT a.*
FROM gf_product AS a
INNER JOIN
(
SELECT product_id
FROM
(
SELECT a.product_id , count(*) AS commons
FROM gf_product_features AS a
INNER JOIN hash1 AS b
ON a.feature_id = b.fl
AND a.feature_value = b.fv
GROUP BY a.product_id
) AS features
WHERE commons = (SELECT count(*) AS count FROM hash2)
) b1 ON a.id = b1.product_id
) AS p
INNER JOIN gf_brands AS b
ON p.brand_id = b.id
INNER JOIN gf_product_features AS pf
ON pf.product_id = p.id
INNER JOIN gf_features AS f
ON pf.feature_id = f.id
ORDER BY price ASC,
feature_id ASC
I want to execute a php function through Ajax request, that constructs dinamically the sql sentence above, but I'm always getting this error in my browser's console:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;
SELECT
' at line 12
And thus, the following error too:
Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /www/htdocs/example/inc/functions.php on line 538
Which corresponds to this line of my php code:
while ($row = mysqli_fetch_assoc($result))
Maybe clone hash2 table from hash1 table
CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;
sounds weird, but if I don't do this in that way, in my phpMyAdmin I get this error:
#1137 - Can't reopen table: 'b'
I can't realize why my sql sentence works fine in my phpMyadmin but, when I construct it on my php file it doesn't works. Can anybody help me, please?
For further information, this is my PHP code:
function getProductsFromFilteredQuery($connection, $filters, &$html)
{
$sql = '';
$m = count($filters); // $filters are an array of values like this: ['value1A, value2A', 'value1B, value2B', ...]
$sql = 'CREATE TEMPORARY TABLE hash1
SELECT * FROM
(';
for ($n = 0; $n < $m; $n++)
{
$string = explode(', ', $filters[$n]);
$feature_id = $string[0];
$feature_value = $string[1];
$sql .= "
(
SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '" . $feature_id . "' AND feature_value = '" . $feature_value . "'
)";
if ($n < ($m - 1))
{
$sql .= ' UNION ';
}
}
$sql .= ') AS q;
CREATE TEMPORARY TABLE hash2 -- In this line I get an error
SELECT * FROM hash1;
SELECT
p.id AS id,
p.main_image AS main_image,
p.type AS taxonomy,
p.name AS model,
p.sku AS sku,
p.price AS price,
b.brand_name AS brand_name,
b.brand_image AS brand_logo,
pf.feature_value AS feature_value,
f.feature AS feature_label,
f.id AS feature_id
FROM
(
SELECT a.*
FROM gf_product AS a
INNER JOIN
(
SELECT product_id
FROM
(
SELECT a.product_id , count(*) AS commons
FROM gf_product_features AS a
INNER JOIN hash1 AS b
ON a.feature_id = b.fl
AND a.feature_value = b.fv
GROUP BY a.product_id
) AS features
WHERE commons = (SELECT count(*) AS count FROM hash2)
) b1 ON a.id = b1.product_id
) AS p
INNER JOIN gf_brands AS b
ON p.brand_id = b.id
INNER JOIN gf_product_features AS pf
ON pf.product_id = p.id
INNER JOIN gf_features AS f
ON pf.feature_id = f.id
ORDER BY price ASC,
feature_id ASC';
$result = mysqli_query($connection, $sql);
while ($row = mysqli_fetch_assoc($result)) // In this line I get an error too
{
// Do some stuff... and at last, return the resulting $html
}
};
I finally could find the error. In my phpMyAdmin it worked as well because someone can execute several queries in the SQL console. There is no problem with it.
However, when coding an mySQL query through PHP you only can run one mySQL sentence at once. Well, there is an exception: You can use mysqli_multi_query + mysqli_more_results, or something like these. But as I was coded it, you can't.
So there is two options: rewrite the PHP code like described in the pages of the two links above, or doing several mysqli_query within the PHP function.
I decided to do it through the second option, so the working code is the following (Notice the comments after each mysqli_query):
function getProductsFromFilteredQuery($mysqli, $filters, &$html) {
$sql = '';
$m = count($filters);
$sql = 'DROP TEMPORARY TABLE IF EXISTS hash1;';
$result = mysqli_query($mysqli, $sql); // A single query
$sql = 'DROP TEMPORARY TABLE IF EXISTS hash2;';
$result = mysqli_query($mysqli, $sql); // Another single query
$sql = 'CREATE TEMPORARY TABLE hash1
SELECT * FROM
(';
for ($n = 0; $n < $m; $n++)
{
$string = explode(', ', $filters[$n]);
$feature_id = $string[0];
$feature_value = $string[1];
$sql .= "
(SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '" . $feature_id . "' AND feature_value = '" . $feature_value . "')";
if ($n < ($m - 1))
{
$sql .= ' UNION ';
}
}
$sql .= ') AS q1';
$result = mysqli_query($mysqli, $sql); // Another single query
$sql = 'CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;';
$result = mysqli_query($mysqli, $sql); // Another single query
$sql = 'SELECT
p.id AS id,
p.main_image AS main_image,
p.type AS taxonomy,
p.name AS model,
p.sku AS sku,
p.price AS price,
b.brand_name AS brand_name,
b.brand_image AS brand_logo,
pf.feature_value AS feature_value,
f.feature AS feature_label,
f.id AS feature_id
FROM
(
SELECT a.*
FROM gf_product AS a
INNER JOIN
(
SELECT product_id
FROM
(
SELECT a.product_id , count(*) AS commons
FROM gf_product_features AS a
INNER JOIN hash1 AS b
ON a.feature_id = b.fl
AND a.feature_value = b.fv
GROUP BY a.product_id
) AS features
WHERE commons = (SELECT count(*) AS count FROM hash2)
) b1 ON a.id = b1.product_id
) AS p
INNER JOIN gf_brands AS b
ON p.brand_id = b.id
INNER JOIN gf_product_features AS pf
ON pf.product_id = p.id
INNER JOIN gf_features AS f
ON pf.feature_id = f.id
ORDER BY price ASC,
feature_id ASC';
$result = mysqli_query($mysqli, $sql); // Another single query. The last one.
while ($row = mysqli_fetch_assoc($result))
{
// My stuff here...
}
}; // #END of function

Why is my member id column returning null?

For some reason the member id field(auto inc.) in my huge query is returning null.I've tried every which way of selecting it... m.member_id AS member_id, etc.I cannot figure out why it is returning null when there is a value for that field in the table.
<?php
public function get_info($criteria = 0){
if(is_numeric($criteria)){
$where = "WHERE m.member_id = ".$criteria;
} else {
$where = "WHERE email_address = '".$criteria."'";
}
$query_member = "
SELECT
m.member_id AS member_id, m.display_name, m.email_address, m.group_id, m.status, m.activation_code, UNIX_TIMESTAMP(m.date_joined) AS date_joined,
m.gender, m.location, m.biography, m.mantra, m.birth_date, m.results_per_page, m.admin_emails, m.member_emails, m.last_active, m.avatar_id,
m.banner_id, m.signature, m.newsletter_subscription, m.recruiting_status, m.facebook_username, m.website, m.steam_username, m.xboxlive_gamertag, m.psn_id,
g.group_id, g.title, g.description,
a.attachment_id, a.file_name,
f.message_id, f.author_id, COUNT(f.message_id) AS forum_count,
b.attachment_id AS banner_id, b.file_name AS banner_file,
mr.request_id, mr.author_id, mr.recipient_id, mr.status, COUNT(mr.request_id) AS total_friends,
tm.team_member_id, tm.member_id, tm.team_id
FROM members AS m
LEFT JOIN member_groups AS g ON (m.group_id = g.group_id)
LEFT JOIN attachments AS a ON (m.avatar_id = a.attachment_id)
LEFT JOIN forum_messages AS f ON (m.member_id = f.author_id)
LEFT JOIN attachments AS b ON (m.banner_id = b.attachment_id)
LEFT JOIN member_requests AS mr ON (m.member_id = mr.author_id OR m.member_id = mr.recipient_id) AND mr.status = 1
LEFT JOIN team_members AS tm ON (m.member_id = tm.member_id) AND date_left = ''
".$where."
GROUP BY m.member_id
LIMIT 1";
//show_error($query_member);
if($query_member = $this->db->query($query_member)){
if($query_member->num_rows() > 0){
var_dump($query_member->row_array());
Because you select two fields with the same name. So MySQL will return result of last one. Add aliases:
SELECT m.member_id AS member_id_1, tm.member_id AS member_id_2 ...

How do i sort by users with profile pictures at the top?

So i'm filling in for our developer at the moment (be for-warned i'm a beginner) but I"m trying to simply sort my search results by profiles that have a profile picture included (i.e, i don't want blank profile pictures to show up at the top of the results...they should all be at the end of the results)...Note that there are a couple user types which is why there is so much code...
I'm pretty sure where i'm going wrong is the 2 lines...
ORDER BY $order u.picture ISNULL DESC"; (which relates to ordering by profile pictures). Would really appreciate any and all help...thx!
The code is as follows:
if ($user_type == 1) {
$sql = "SELECT a.*, u.*,
(SELECT COUNT(DISTINCT userId) FROM LF_usertype_A WHERE usertype_BId = u.userId AND status = 1) as i_cnt,
(SELECT COUNT(productId) FROM LF_products WHERE userId = u.userId AND status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeBId
AND userId != usertypeAId) AS cnt
FROM LF_Users u
JOIN LF_products a ON a.userId = u.userId
LEFT JOIN LF_Transactions t ON t.productId = a.productId
WHERE a.status = 1
AND u.status = 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200";
} elseif ($filter != "recent" && $user_type == 2) {
$sql = "SELECT u.*,
(SELECT COUNT(a.productId) FROM LF_usertypeA a INNER JOIN LF_products ON a.productId = m.productId INNER JOIN LF_Users uu ON uu.userId = a.usertypeAId WHERE a.userId = u.userId AND uu.status = 1 AND a.status = 1 AND m.status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeAId
AND userId != usertypeBId) AS cnt
FROM LF_Users u
LEFT JOIN LF_Transactions t ON t.usertypeBId = u.userId
WHERE u.status = 1
AND u.userId != 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200
ORDER BY $order u.picture ISNULL DESC";
} else {
$sql = "SELECT u.*,
(SELECT COUNT(a.productId) FROM LF_usertype_A a INNER JOIN LF_products m ON a.productId = m.productId INNER JOIN LF_Users uu ON uu.userId = a.usertypeAId WHERE a.userId = u.userId AND uu.status = 1 AND a.status = 1 AND m.status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeAId
AND userId != usertypeBId) AS cnt
FROM LF_Users u
WHERE u.status = 1
AND u.userId != 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200
ORDER BY $order u.picture ISNULL DESC";
}
You would have to put the isnull condition before your regular sort order if you want it to take precedence:
ORDER BY ISNULL(u.picture), $order

Categories