Problems displaying two seperate values from the same mysql column - php

I have a mysql table called custom_values where in the table exists two columns, One called "custome_field_id" and one called "value".
The "value" column holds two different values that I need to pull and display on my page. One value is an "order number" value and the other is a "date" value. The "custom_field_id" column shows a custom_field_id of 33 for the "Date" value and 237 for the "order" value
What I would like to do is structure my php query so that in one select statement, I can display both of these values.
for example end up with an $actual_date and $Order variable that I can use.
Here is my current select statement that at this moment retrieves the "order" value. But I need to show both... I tried using Alias in in my select statement but it didnt work for me...
$stmt = $con->prepare("SELECT custom_values.value, issues.subject, issue_statuses.name,
issues.due_date, issues.id as issuesid,
users.firstname, users.lastname
FROM redmine.issues join redmine.projects on issues.project_id=projects.id
left join redmine.users on issues.assigned_to_id=users.id
left join redmine.custom_values ON issues.id=custom_values.customized_id
left join issue_statuses on issues.status_id=issue_statuses.id
where projects.id='".$_SESSION['id']."'
and custom_values.custom_field_id=237 ORDER BY $order ASC");
$stmt->execute();
Any help is appreciated!

SELECT v_order.value my_order
, v_date.value date
, i.subject
, s.name
, i.due_date
, i.id issuesid
, u.firstname
, u.lastname
FROM issues i
JOIN projects p
ON p.id = i.project_id
LEFT
JOIN users u
ON u.id = i.assigned_to_id
LEFT
JOIN custom_values v_order
ON v_order.customized_id = i.id
AND v_order.custom_field_id = 237
LEFT
JOIN custom_values v_date
ON v_date.customized_id = i.id
AND v_date.custom_field_id = 33
LEFT
JOIN issue_statuses s
ON s.id = i.status_id
WHERE p.id = "_SESSION['id']"
ORDER
BY $order ASC

I'd strongly advise to build this in Ruby as a Redmine plugin then. Dealing with the database at this level is error-prone; working with the CustomField and CustomValue classes in Redmine however, will do all the abstraction for you.
You could even use the Redmine API [1] to access the data using HTTP.
[1] http://www.redmine.org/projects/redmine/wiki/Rest_api

If the following is right:
In the same database, you have 2 columns first contains 2 different numbers in case of two different values in the second column; therefore you have 2 rows per item to pull out
Please correct me if I missunderstood.
Try the following:
... AND ( custom_values.custom_field_id=value_1 OR custom_values.custom_field_id=value_2 ) ORDER ...

Related

mysql join where for 1 table

I have 2 tables, student and grades
student table contains id, name and date_of_birth
grades table contains id, student_id, grade and course
Actual table contain more data.
I have a query like
SELECT s.*, AVG(g.grade) as average_grade
FROM student s LEFT JOIN grade g ON s,id = g.student_id
WHERE g.course = 'mathematics' and s.id = 1
With this I could get the data i needed which are student details and the average grade, then come the problem where when the course = "mathematics" is not found in the grades table, the query will return NULL. My question is, is there a way for me to get the s.id = 1 details together with NULL average instead of all NULL value?
I would prefer if it is able to do it with 1 query, as because in my current I am using subquery and it takes very long to get the data. My main objective is to get more faster speed if you have better way instead of using 1 query feel free to comment your idea. In addition I have tried multiple query and sub query to get all the data but it all take too long.
Move your filter criteria for g.course = 'mathematics' in joining part
SELECT s.*, AVG(g.grade) as average_grade
FROM student s
LEFT JOIN grade g ON s.id = g.student_id AND g.course = 'mathematics'
WHERE s.id = 1
Your query produces result as inner join not left because putting g.course = 'mathematics in where clause turns your left join to inner join, Moving this part in on clause will still return data from student table if there were no rows found from grade table with course = 'mathematics'
If the course is not 'mathematics' you would still get the student data if you put it like this.
SELECT s.*, AVG(g.grade) as average_grade
FROM student s LEFT JOIN grade g ON s,id = g.student_id
WHERE (g.course = 'mathematics' AND s.id = 1) OR s.id = 1

Optimizing mysql IN query having large values

I have a mysql query like
SELECT `tbl_ticket`.`id`, `tbl_ticket`.`hd_user_username`,
`tbl_ticket`.`hd_user_email`, `tbl_ticket`.`ticket_title`,
`tbl_complain_type`.`complains` FROM `tbl_ticket` LEFT JOIN
`tbl_ticket_complain` ON tbl_ticket_complain.ticket_id=tbl_ticket.id
LEFT JOIN `tbl_complain_type` ON tbl_complain_type.id=tbl_ticket_complain.complain_id
LEFT JOIN `tbl_assignment` ON tbl_assignment.ticket_id=tbl_ticket.id
WHERE ((((`hd_user_username` LIKE '%searchterm%')
AND (`tbl_assignment`.`id` IN ($array)))
OR (`hd_user_email`='searchterm'))
OR (`ticket_title`='searchterm')) OR (`tbl_complain_type`.`complains`='searchterm')
$array contains around 7000 values like `$array=array(1,2,3,..)`
This query takes around 8 seconds to execute. Is there any alternative solution for this query ?
The value of $array is got from another query
select max(id) from tbl_assignment group by ticket_id
The slowness of query is due to multiple joins between tables
If the values in the array use in you IN clause come from a select you could use the fact that
An IN clause is equivalent to an inner join so you could use a inner join between your_table_with_id and the table.column you need for match eg:
SELECT `
tbl_ticket`.`id`
, `tbl_ticket`.`hd_user_username`
, `tbl_ticket`.`hd_user_email`
, `tbl_ticket`.`ticket_title`
, `tbl_complain_type`.`complains`
FROM `tbl_ticket`
LEFT JOIN `tbl_ticket_complain` ON tbl_ticket_complain.ticket_id=tbl_ticket.id
LEFT JOIN `tbl_complain_type` ON tbl_complain_type.id=tbl_ticket_complain.complain_id
LEFT JOIN `tbl_assignment` ON tbl_assignment.ticket_id=tbl_ticket.id
INNER JOIN your_table_with_id ON `tbl_assignment`.`id` = JOIN your_table_with_id.id
WHERE ((((`hd_user_username` LIKE '%searchterm%')
OR (`hd_user_email`='searchterm'))
OR (`ticket_title`='searchterm')) OR (`tbl_complain_type`.`complains`='searchterm')
Remeber also that the content of values use IN clause is limited and fail when the limit is exceeded
and in your case
SELECT `
tbl_ticket`.`id`
, `tbl_ticket`.`hd_user_username`
, `tbl_ticket`.`hd_user_email`
, `tbl_ticket`.`ticket_title`
, `tbl_complain_type`.`complains`
FROM `tbl_ticket`
LEFT JOIN `tbl_ticket_complain` ON tbl_ticket_complain.ticket_id=tbl_ticket.id
LEFT JOIN `tbl_complain_type` ON tbl_complain_type.id=tbl_ticket_complain.complain_id
LEFT JOIN `tbl_assignment` ON tbl_assignment.ticket_id=tbl_ticket.id
INNER JOIN (
select max(id) as id
from tbl_assignment
group by ticket_id
) t ON `tbl_assignment`.`id` = t.id
WHERE ((((`hd_user_username` LIKE '%searchterm%')
OR (`hd_user_email`='searchterm'))
OR (`ticket_title`='searchterm')) OR (`tbl_complain_type`.`complains`='searchterm'))
This is basically your query:
SELECT . . .
FROM tbl_ticket t LEFT JOIN
tbl_ticket_complain tc
ON tc.ticket_id = t.id LEFT JOIN
tbl_complain_type tct
ON tct.id = tc.complain_id LEFT JOIN
tbl_assignment a
ON a.ticket_id = t.id
WHERE (((hd_user_username LIKE '%searchterm%' AND
a.id IN ($array)
) OR
`hd_user_email`='searchterm'
) OR
ticket_title = 'searchterm'
) OR
tct.complain` = 'searchterm';
The issue with performance has nothing to do with IN. In fact, MySQL optimizes IN, as explained in the documentation:
If all values are constants, they are evaluated according to the type
of expr and sorted. The search for the item then is done using a
binary search. This means IN is very quick if the IN value list
consists entirely of constants.
You are not going to get faster than an IN list with constants.
The problem with your query is the string of ORs. These make is almost impossible for the optimizer to use indexes -- so the full result set has to be created and then filtered down.
It is hard for me to see how to improve this in your query. Sometimes, splitting a query into simpler chunks and connecting them using union or union all does the trick. Your conditions are a bit hard to follow, making that approach difficult for an outsider.

MYSQL/PHP: Concat returning to many fields on LEFT JOIN

I had a SELECT query with a LEFT JOIN working as desired. I then added one more table via a smilar LEFT JOIN and now I am getting a wierd result. Basically, for a group_concat where I was getting one item for every record, I am getting eight records. I don't see why this is happening because the join to the new table is analagous to several other joins that do not have this problem (that I have omitted from the example for clarity).
Here is the query that is fine:
$sql = "SELECT t.*,
group_concat(tf.todoid) as `tftodoid`,
group_concat(tf.id) as `tfid`,
group_concat(tf.filedescript) as `tffiledescript`,
group_concat(tf.filename) as `tffilename`,
group_concat(tf.founderid) as `tffounderid`,
group_concat(tf.ext) as `tfext`,
group_concat(tf.lasttouched) as `tilt`
FROM titles `t`
LEFT JOIN titlefiles `tf`
ON (tf.todoid = t.id AND tf.founderid = '$userid')
WHERE t.userid='$userid'
GROUP BY t.id";
And here is the query with the extra join that is now spilling out the multiple copies of the items:
$sql = "SELECT t.*,
group_concat(tf.todoid) as `tftodoid`,
group_concat(tf.id) as `tfid`,
group_concat(tf.filedescript) as `tffiledescript`,
group_concat(tf.filename) as `tffilename`,
group_concat(tf.founderid) as `tffounderid`,
group_concat(tf.ext) as `tfext`,
group_concat(tf.lasttouched) as `tilt`,
group_concat(s.id) as `stepid`,
group_concat(s.step) as `steps`
FROM titles `t`
LEFT JOIN titlefiles `tf`
ON (tf.titleid = t.id AND tf.founderid = '$userid')
LEFT JOIN steps `s`
ON s.titleid = t.id
WHERE t.userid='$userid'
GROUP BY t.id";
Here is an example of output in JSON showing the difference:
First query:
"tfid":"56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81"
Second query:
"tfid":"56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81,56,57,58,59,60,61,62,63,64,65,66,67,68,75,76,81",
I suspect the problem has something to do with the JOIN or with the Group By statements but I can't see how to fix.
How can I ensure that I get only one fileid per file as opposed to eight?
Alter the line as follows:
group_concat(DISTINCT tf.id) as `tfid`,
This then only gets you the unique ids.
If you want them ordered add:
group_concat(DISTINCT tf.id ORDER BY tf.id ASC) as `tfid`,

How do I set the value of a column be a result of a SQL query using one of the columns of the same table

I have two tables
Table 1 : Users
Has columns id,Name,institution
Institution is a sting showing institution name.
Table 2: Institutions.
Has columns id,institution,count
I need the count column to be recording the number of rows in table 1 where institution is same as the institution in each row of Table 2. This should happen for all the rows of Table 2.
Please help me get the right MySQL queries or table relations to achieve this.
Join both the tables on instutions and get the count like below
select i.institution,
X.ins_count
from Institutions i
left join
(
select institution,
count(*) as ins_count
from Users
group by institution
) X on i.institutions = X.institutions
this question doesn't have a lot of detail but from what I understand you just want to do this.
UPDATE TABLE institutions,
(SELECT
i.id,
COUNT(u.id) as user_count
FROM Users u
JOIN Institutions i on i.institution = u.institution
GROUP BY i.institution) as temp
SET institutions.count = temp.user_count
WHERE temp.id = institutions.id;
I'd do something like this:
UPDATE institutions i
LEFT
JOIN ( SELECT u.institution
, COUNT(1) AS user_cnt
FROM users u
GROUP BY u.institution
) c
ON c.institution = i.institution
SET i.count = IFNULL(c.user_cnt,0)
The inline view (aliased as c) gets a count of users for each "institution". This result is outer joined to institutions. (We reference the result from that inline view query like it was a table; MySQL actually refers to the inline view as a "derived table".
We assign the value derived user_cnt value to the count column, and substituting 0 for NULL (which will happen if there are no users in a given "institution".)
To see this in action BEFORE you run the update, you can run a similar SELECT (remove the SET clause and change the UPDATE keyword to be SELECT <expression_list> FROM, optionally add an ORDER BY clause.
SELECT i.institution
, i.count AS old_count
, IFNULL(c.user_cnt,0) AS new_count
FROM institutions i
LEFT
JOIN ( SELECT u.institution
, COUNT(1) AS user_cnt
FROM users u
GROUP BY u.institution
) c
ON c.institution = i.institution
ORDER BY i.institution
As another possible approach to achieve the same result, but with (likely) less efficiency (if this is actually valid), would be to use a correlated subquery to return the value:
UPDATE institutions i
SET i.count = ( SELECT COUNT(1)
FROM users u
WHERE u.institution = i.institution
)
I know that approach "works" in a SELECT statement. I expect it to work in an UPDATE statement, but I haven't tested that. Equivalent SELECT would be:
SELECT i.institution
, i.count AS old_count
, ( SELECT COUNT(1)
FROM users u
WHERE u.institution = i.institution
) AS new_count
FROM institutions i
Absent any compelling reason to use a correlated subquery, I'd avoid that and go with the JOIN operation instead.

get count of posts based on count(*)

i am trying to get number of posts that i have
Here is my query
$Query="
SELECT t.*,u.*,c.*
FROM posts as t
LEFT JOIN relations as r on r.post_id = t.post_id
LEFT JOIN users as u on t.auther_id = u.auther_id
LEFT JOIN categories as c on c.cate_id = r.cate_id
GROUP BY t.post_id
";
$Query=mysql_query($Query);
$numberOfPosts=mysql_num_rows($Query);
This query is works very well
but i am trying to convert it, i want make it faster
i want use count(*) instead of t.*
because when i use t.*, it gets the full data of posts and categories
but i want to get count only, So i decided to use count(*) but i don't know how to use it with query like this
Edit
i've replaced SELECT t.*,u.*,c.* with SELECT count(t.*)
But i got mysql Error Warning: mysql_fetch_assoc(): supplied argument
Edit 2:
i am trying SELECT count(t.post_title)
I Got this results
Array ( [count(t.post_id)] => 10 )
But i have only 2 posts!
$Query="
SELECT t.*,u.*,c.*
FROM posts as t
LEFT JOIN relations as r on r.post_id = t.post_id
LEFT JOIN users as u on t.auther_id = u.auther_id
LEFT JOIN categories as c on c.cate_id = r.cate_id
GROUP BY t.post_id
";
$Query=mysql_query($Query);
$numberOfPosts=mysql_num_rows($Query);
Let's take a step back and analyze this query for a moment.
You're selecting everything from three out of four tables used in the query. The joins create some logic to limit what you select to the proper categories, authors, etc. At the end of the day you are getting a lot of data from the database, then in PHP simply asking it how many rows were returned (mysql_num_rows). Instead, what #Dagon is trying to suggest in comments, is that you have MySQL simply count the results, and return that.
Let's refactor your query:
$query = "
SELECT COUNT(t.post_id) AS qty
FROM posts as t
LEFT JOIN relations AS r ON r.post_id = t.post_id
LEFT JOIN users AS u ON t.auther_id = u.auther_id
LEFT JOIN categories AS c ON c.cate_id = r.cate_id
GROUP BY t.post_id
";
$result = mysql_query($query);
$result_row = mysql_fetch_assoc($result);
$numberOfPosts = $result_row['qty'];
(You could also use Barattlo's custom execute_scalar function to make it more readable.)
I would need to see your table structures to be of more help on how to optimize the query and get the desired results.
try doing this:
$Query="
SELECT count(t.*) as count_all
FROM posts as t
LEFT JOIN relations as r on r.post_id = t.post_id
LEFT JOIN users as u on t.auther_id = u.auther_id
LEFT JOIN categories as c on c.cate_id = r.cate_id
GROUP BY t.post_id
";
$Query=mysql_query($Query);
$numberOfPosts=mysql_num_rows($Query);
You want to do
SELECT count(t.id) AS count FROM ....
//do query with PDO or whatever you are using
$rows = mysql_fetch_assoc();
$num_rows = $rows['count'];
You should probably simply use
SELECT count(*) as postingcount FROM posts
Why?
Because you do not have a WHERE clause, so there are no restrictions. Your JOINS do not ADD more rows to the resultset, and in the end your GROUP BY merges every duplicate occurance of a post_id that might have occurred because of joining back into one row. The result should only be counted, so assuming that the real number you want to know is the number of data sets inside the table posts, you do not need any join, and doing count(*) really is a very fast operation on tables in MySQL.
Remember to check if mysql_query returns false, because then you have to check mysql_error() and see why your query has an error.

Categories