PHP and MySQL query output different - php

I have the following query. When I run the query straight in MySQL I get all the information but when I run the same query in my PHP script it's missing some information. I ran the query in MySQL first to make sure that I I get everything I need and then copied the query into my php script. Can anyone please help:
$get_attendance_profile_stmt = $conn->prepare('SELECT
p_info.fname AS \'First name\',
p_info.lname AS \'Lastname\',
stud_info.t_belt_id,
t_b.short_descr,
t_b.long_descr,
stud_info.h_belt_id,
h_b.short_descr,
h_b.long_descr,
AB.*,
ROUND(
(
AB.Considered_Attended / AB.Classes_Tought * 100
),
0
) AS \'Attendance %\'
FROM
(
SELECT
student_id,
SUM(
CASE WHEN attendance_reason = 1 THEN 1 ELSE 0
END
) AS \'Sick\',
SUM(
CASE WHEN attendance_reason = 2 THEN 1 ELSE 0
END
) AS \'Injured\',
SUM(
CASE WHEN attendance_reason = 3 THEN 1 ELSE 0
END
) AS \'Work\',
SUM(
CASE WHEN attendance_reason = 4 THEN 1 ELSE 0
END
) AS \'School\',
SUM(
CASE WHEN attendance_reason = 5 THEN 1 ELSE 0
END
) AS \'Did not attend\',
SUM(
CASE WHEN attendance_reason = 6 THEN 1 ELSE 0
END
) AS \'Present\',
SUM(
CASE WHEN attendance_reason != 5 THEN 1 ELSE 0
END
) AS \'Considered_Attended\',
MAX(DateCounter) AS \'Classes_Tought\'
FROM
attendance a
JOIN(
SELECT COUNT(
DISTINCT CONVERT(creation_date, DATE)
) AS DateCounter
FROM
attendance
WHERE
creation_date <= (SELECT DATE_SUB(NOW(), INTERVAL -6 MONTH))
) DT
WHERE
creation_date <= (SELECT DATE_SUB(NOW(), INTERVAL -1 MONTH))
GROUP BY
student_id
) AB
JOIN student_info stud_info ON
stud_info.student_id = AB.student_id
JOIN users u ON
stud_info.uid = u.uid
JOIN personal_info p_info ON
u.uid = p_info.uid
LEFT JOIN t_belts t_b ON
stud_info.t_belt_id = t_b.t_belt_id
LEFT JOIN h_belts h_b ON
stud_info.h_belt_id = h_b.h_belt_id
WHERE
u.account_status = \'Active\'');
My output running the query inside MySQL is like this:
The output of the query in php looks like this:
Any help will be greatly appreciated.

PHP array's need to have unique indices. Your query returns 2 columns with the same name so the second values are what you get (they overwrite the first during assignment, simple example https://3v4l.org/sbs41 )). As can be seen in the screenshot your second columns are empty. Use an alias on the first columns (or the second) so your indices in PHP are unique. e.g.
SELECT
p_info.fname AS \'First name\',
p_info.lname AS \'Lastname\',
stud_info.t_belt_id,
t_b.short_descr,
t_b.long_descr,
stud_info.h_belt_id,
h_b.short_descr as short_descr_dontcare,
h_b.long_descr as long_descr_dontcare
or
SELECT
p_info.fname AS \'First name\',
p_info.lname AS \'Lastname\',
stud_info.t_belt_id,
t_b.short_descr as short_descr_real,
t_b.long_descr as long_descr_real,
stud_info.h_belt_id,
h_b.short_descr,
h_b.long_descr
with the latter approach you'll need to modify the indices in your PHP array with _real.

Related

Select longest streak in days from mysql database?

First off, I have found quite a few similar questions on both Google and Stackoverflow but I can't seem to grasp how to do this correctly.
I have a table that looks like this:
id ms_date
------------------
1 2018-11-18
2 2018-11-18
3 2018-11-20
4 2018-11-22
5 2018-11-25
6 2018-11-26
7 2018-11-26
8 2018-11-27
9 2018-11-28
10 2018-11-29
What i need to do is to get the longest streak in Days from that table.
So in the above example, the longest streak is 4 days.
I found this: https://dzone.com/articles/how-to-find-the-longest-consecutive-series-of-even
and it explains what he's trying to do which is SIMILAR to what I am trying to achieve but then it is so badly explained/written that I cannot make sense of it.
I also need to find the GAP between those dates and start counting the streak again. So again in the example above, because there's a gap between the dates, the Current Streak should be 3 Days.
I've tried to used the code from the link above but that is based on SQL and also it has some strange WITH words in the code which doesn't make sense at all.
Is there an easy way to achieve this using PHP and Mysql ?
Could someone please advice on this issue?
Thanks in advance.
EDIT:
I can't seem to find the software version in my PHPMYADMIN but this is what i can see under the Database server section:
Server: Localhost via UNIX socket
Server type: MariaDB
Server connection: SSL is not being used Documentation
Server version: 10.0.37-MariaDB-0+deb8u1 - (Debian)
Protocol version: 10
User: freemind#localhost
Server charset: UTF-8 Unicode (utf8)
Second EDIT:
Tried the following based on the below answer and I get nothing at all:
$sql_COUNT = "SELECT COUNT(*) max_streak
FROM
( SELECT x.*
, CASE WHEN #prev = val - 1 THEN #i:=#i ELSE #i:=#i+1 END i
, #prev:=val
FROM
( SELECT DISTINCT ms_date FROM MY_TABLE ) x
JOIN
( SELECT #prev:=null,#i:=0 ) vars
ORDER
BY ms_date
) a
GROUP
BY i
ORDER
BY max_streak DESC LIMIT 1";
$query_COUNT = mysqli_query($db_conx, $sql_COUNT);
$productCount_COUNT = mysqli_num_rows($query_COUNT); // count the output amount
echo $productCount_COUNT;
Third Edit:
The following code echo's 1 on my page BUT based on what I have in MYSQL database, it should echo 4:
$sql_COUNT = "SELECT COUNT(*) AS max_streak
FROM
( SELECT x.*
, CASE WHEN #prev = ms_date - 1 THEN #i:=#i ELSE #i:=#i+1 END i
, #prev:=ms_date
FROM
( SELECT DISTINCT ms_date FROM MY_TABLE ) x
JOIN
( SELECT #prev:=null,#i:=0 ) vars
ORDER
BY ms_date
) a
GROUP
BY i
ORDER
BY max_streak DESC LIMIT 1";
$query_COUNT = mysqli_query($db_conx, $sql_COUNT);
$productCount_COUNT = mysqli_num_rows($query_COUNT); // count the output amount
echo $productCount_COUNT;
Fourth EDIT:
I'm not sure if the answers below was tested but it doesn't work for me.
i tried the folowings and even though I get no errors, I only see a blank page which means the code is not working:
$sql_COUNT = "SELECT COUNT(*) max_streak
FROM
( SELECT x.*
, CASE WHEN #prev = ms_date - INTERVAL 1 DAY THEN #i:=#i ELSE #i:=#i+1 END i
, #prev:=ms_date
FROM
( SELECT DISTINCT ms_date FROM MY_TABLE ORDER BY ms_date ) x
JOIN
( SELECT #prev:=null,#i:=0 ) vars
) a
GROUP
BY i
ORDER
BY max_streak DESC";
$query_COUNT = mysqli_query($db_conx, $sql_COUNT);
$count = mysqli_fetch_array($query_COUNT);
echo $count[0];
Consider the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,val INT NOT NULL
);
INSERT INTO my_table VALUES
(1 , 11),
(2 , 11),
(3 , 12),
(4 , 13),
(5 , 14),
(6 , 17),
(7 , 18),
(8 , 20),
(9 , 21),
(10 , 22);
SELECT COUNT(*) max_streak
FROM
( SELECT x.*
, CASE WHEN #prev = val - 1 THEN #i:=#i ELSE #i:=#i+1 END i
, #prev:=val
FROM
( SELECT DISTINCT val FROM my_table ) x
JOIN
( SELECT #prev:=null,#i:=0 ) vars
ORDER
BY val
) a
GROUP
BY i
ORDER
BY max_streak DESC LIMIT 1;
+------------+
| max_streak |
+------------+
| 4 |
+------------+
1 row in set (0.01 sec)
EDIT:
If you're using dates, then the logic is the same, but you just have to substitute a bit of date arithmetic...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,val DATE NOT NULL
);
INSERT INTO my_table VALUES
(1 , '2018-11-11'),
(2 , '2018-11-11'),
(3 , '2018-11-12'),
(4 , '2018-11-13'),
(5 , '2018-11-14'),
(6 , '2018-11-17'),
(7 , '2018-11-18'),
(8 , '2018-11-20'),
(9 , '2018-11-21'),
(10 , '2018-11-22');
SELECT COUNT(*) max_streak
FROM
( SELECT x.*
, CASE WHEN #prev = val - INTERVAL 1 DAY THEN #i:=#i ELSE #i:=#i+1 END i
, #prev:=val
FROM
( SELECT DISTINCT val FROM my_table ) x
JOIN
( SELECT #prev:=null,#i:=0 ) vars
ORDER
BY val
) a
GROUP
BY i
ORDER
BY max_streak DESC LIMIT 1;
+------------+
| max_streak |
+------------+
| 4 |
+------------+
Purists would argue (correctly) that I'm using #variable assignments in an incorrect manner - but it's just a bad habit I picked up. That said, I think a correct assignment method is as follows, but no doubt someone will let me know if I'm mistaken...
SELECT COUNT(*) max_streak
FROM
( SELECT x.*
, CASE WHEN #prev = val - INTERVAL 1 DAY THEN #i:=#i ELSE #i:=#i+1 END i
, #prev:=val
FROM
( SELECT DISTINCT val FROM my_table ORDER BY val ) x
JOIN
( SELECT #prev:=null,#i:=0 ) vars
) a
GROUP
BY i
ORDER
BY max_streak DESC LIMIT 1;
If you want to bundle this up inside some PHP, I guess it might look like this (although it should be obvious from what follows that application code is not really my forte)...
<?php
require('path/to/connection/stateme.nts');
$query = "
SELECT COUNT(*) max_streak
FROM
( SELECT x.*
, CASE WHEN #prev = val - INTERVAL 1 DAY THEN #i:=#i ELSE #i:=#i+1 END i
, #prev:=val
FROM
( SELECT DISTINCT val FROM MY_TABLE ORDER BY val ) x
JOIN
( SELECT #prev:=null,#i:=0 ) vars
) a
GROUP
BY i
ORDER
BY max_streak DESC
LIMIT 1;
";
$result = mysqli_query($conn, $query) or die(mysqli_error($conn));
$row = mysqli_fetch_assoc($result);
print_r($row);
?>
-- outputs
Array ( [max_streak] => 4 )

Single query that allows alias with it's own limit

I would like to better optimize my code. I'd like to have a single query that allows an alias name to have it's own limit and also include a result with no limit.
Currently I'm using two queries like this:
// ALL TIME //
$mikep = mysqli_query($link, "SELECT tasks.EID, reports.how_did_gig_go FROM tasks INNER JOIN reports ON tasks.EID=reports.eid WHERE `priority` IS NOT NULL AND `partners_name` IS NOT NULL AND mike IS NOT NULL GROUP BY EID ORDER BY tasks.show_date DESC;");
$num_rows_mikep = mysqli_num_rows($mikep);
$rating_sum_mikep = 0;
while ($row = mysqli_fetch_assoc($mikep)) {
$rating_mikep = $row['how_did_gig_go'];
$rating_sum_mikep += $rating_mikep;
}
$average_mikep = $rating_sum_mikep/$num_rows_mikep;
// AND NOW WITH A LIMIT 10 //
$mikep_limit = mysqli_query($link, "SELECT tasks.EID, reports.how_did_gig_go FROM tasks INNER JOIN reports ON tasks.EID=reports.eid WHERE `priority` IS NOT NULL AND `partners_name` IS NOT NULL AND mike IS NOT NULL GROUP BY EID ORDER BY tasks.show_date DESC LIMIT 10;");
$num_rows_mikep_limit = mysqli_num_rows($mikep_limit);
$rating_sum_mikep_limit = 0;
while ($row = mysqli_fetch_assoc($mikep_limit)) {
$rating_mikep_limit = $row['how_did_gig_go'];
$rating_sum_mikep_limit += $rating_mikep_limit;
}
$average_mikep_limit = $rating_sum_mikep_limit/$num_rows_mikep_limit;
This allows me to show an all-time average and also an average over the last 10 reviews. Is it really necessary for me to set up two queries?
Also, I understand I could get the sum in the query, but not all the values are numbers, so I've actually converted them in PHP, but left out that code in order to try and simplify what is displayed in the code.
All-time average and average over the last 10 reviews
In the best case scenario, where your column how_did_gig_go was 100% numeric, a single query like this could work like so:
SELECT
AVG(how_did_gig_go) AS avg_how_did_gig_go
, SUM(CASE
WHEN rn <= 10 THEN how_did_gig_go
ELSE 0
END) / 10 AS latest10_avg
FROM (
SELECT
#num + 1 AS rn
, tasks.show_date
, reports.how_did_gig_go
FROM tasks
INNER JOIN reports ON tasks.EID = reports.eid
CROSS JOIN ( SELECT #num := 0 AS n ) AS v
WHERE priority IS NOT NULL
AND partners_name IS NOT NULL
AND mike IS NOT NULL
ORDER BY tasks.show_date DESC
) AS d
But; Unless all the "numbers" are in fact numeric you are doomed to sending every row back from the server for php to process unless you can clean-up the data in MySQL somehow.
You might avoid sending all that data twice if you establish a way for your php to use only the top 10 from the whole list. There are probably way of doing that in PHP.
If you wanted assistance in SQL to do that, then maybe having 2 columns would help, it would reduce the number of table scans.
SELECT
EID
, how_did_gig_go
, CASE
WHEN rn <= 10 THEN how_did_gig_go
ELSE 0
END AS latest10_how_did_gig_go
FROM (
SELECT
#num + 1 AS rn
, tasks.EID
, reports.how_did_gig_go
FROM tasks
INNER JOIN reports ON tasks.EID = reports.eid
CROSS JOIN ( SELECT #num := 0 AS n ) AS v
WHERE priority IS NOT NULL
AND partners_name IS NOT NULL
AND mike IS NOT NULL
ORDER BY tasks.show_date DESC
) AS d
In future (MySQL 8.x) ROW_NUMBER() OVER(order by tasks.show_date DESC) would be a better method than the "roll your own" row numbering (using #num+1) shown before.

MySQL - SELECT WHERE condition based on value of another SELECT

Hello I have two MySQL Querys where I am trying to use count and results from first select in condition for the second select.
Here is my code:
$sql = "SELECT m.name, m.id
FROM members m
WHERE m.online_status = 1 {$dep} ORDER BY m.name ASC";
$sql_second = "SELECT time_management.clientid, clients.client,
SUM( CASE WHEN MONTH(`date`) = 1 AND taskid <> 1 AND YEAR(date)='$year' THEN TIME_TO_SEC( `time` ) AND user = (result from previouse slect) ELSE 0 END) AS (user_1)
FROM time_management
LEFT JOIN clients ON time_management.clientid = clients.id
WHERE {$dep_where} = {$department_var}
GROUP BY clientid";
So first select is selecting all users which are unknown value. Name and ID
In the second query what I need is to Select for example:
let's say the first query returns
id:1 name: Jon
id:2 name: Mike
id:3 name: Dave
Total results: 3
so in this case in the second query the following line have to be repeaded 3 times for each user:
SUM( CASE WHEN MONTH(`date`) = 1 AND taskid <> 1 AND YEAR(date)='$year' THEN TIME_TO_SEC( `time` ) AND user = (result from previouse slect) ELSE 0 END) AS (user_1)
where user will be = to 1,2,3 for each line and (user_1) willbe (user_2), (user_3)
Is there a way this operation to be realized directly inside MySQL ? if now how it should be solved ?

SQL search Result, Group by ID number

I'm having some issues with trying to fix this SQL Query
This is a custom search query which is searching for the word 'weddings' on all pages on this CMS system.
At the moment I am getting the same page appear on the first 5 rows because the word 'weddings' appears 5 times. What I want to do is combine the rows with the same ID number into 1 row so it doesn't appear multiple times.
I thought doing a group by at the end of this statement would do this but I keep getting an SQL syntax error
GROUP BY `documents`.`id`
I have attached the full SQL bellow with an image of the output i currently get.... Any idea?
SELECT `documents`.*,
`documenttypes`.`name` as `doctype`,
`articles`.`id` as `article_id`,
`articles`.`language_id`,
`articles`.`title`,
`articles`.`template`,
`articles`.`slug`,
`articles`.`path`,
`articles`.`slug_title`,
MATCH ( elements.textvalue )AGAINST ( 'weddings' ) AS score,
elements.textvalue AS matching,
LOWER(`articles`.`title`)
LIKE '%weddings%' as 'like_title',
( MATCH ( elements.textvalue )
AGAINST ( 'weddings' ) ) + IF(( LOWER(`articles`.`title`)
LIKE '%weddings%'),1, 0) + IF((LOWER(`elements`.`textvalue`)
LIKE '%weddings%'),1, 0) as total FROM (`documents`)
LEFT JOIN `articles` ON `articles`.`document_id` = `documents`.`id`
LEFT JOIN `documenttypes` ON `documents`.`documenttype_id` = `documenttypes`.`id`
LEFT JOIN `documents_users` AS du ON `documents`.`id` = du.`document_id`
LEFT JOIN `documents_usergroups` AS dug ON `documents`.`id` = dug.`document_id`
LEFT JOIN elements ON `elements`.`article_id` = `articles`.`id`
WHERE `documents`.`trashed` = 0
AND `documents`.`published` = 1
AND `articles`.`status_id` = 1
AND `articles`.`language_id` = 1
AND (`documents`.`no_search` = '0'
OR `documents`.`no_search` IS NULL)
AND ( (dug.usergroup_id IS NULL)
AND (du.user_id IS NULL) )
AND (`documents`.`startdate` < NOW()
OR `documents`.`startdate` = '0000-00-00 00:00:00' OR `documents`.`startdate` IS NULL)
AND (`documents`.`enddate` > NOW()
OR `documents`.`enddate` = '0000-00-00 00:00:00'
OR `documents`.`enddate` IS NULL)
HAVING (total > 0)
ORDER BY label ASC,
total DESC LIMIT 0,10
You can try to use the statement DISTINCT:
SELECT DISTINCT 'documents'.*,
'documenttypes'.'name' as 'doctype',
'articles'.'id' as 'article_id',
...
GROUP BY lets you use aggregate functions, like AVG, MAX, MIN, SUM, and COUNT which apparently you don't use.

Is there any way to find the value of a query?

I recently made a system that ranks each players depending on their points. Well the way the system gets the points is rather confusing. After using this system for over 24 hours, I have found out that it is not organizing it according to the points. But then it suddenly occurred to me, that I could be calculating the points wrong in a way that does not represent the SQL query. Here is my SQL query that my rankings uses:
SELECT * , playeruid AS player_id, (
(
SELECT COALESCE(sum(player1points),0)
FROM `mybb_matches`
WHERE player1uid = player_id AND gid = $id AND timestamp < $time AND winneruid is NOT NULL AND dispute != 3 )
+
(
SELECT COALESCE(sum(player2points),0)
FROM `mybb_matches`
WHERE player2uid = player_id AND gid = $id AND timestamp < $time AND winneruid is NOT NULL AND dispute != 3 )
+
(
SELECT SUM( rank )
FROM `mybb_matchesgame`
WHERE playeruid = player_id AND gid = $id )
)
AS points
FROM mybb_matchesgame WHERE gid = $id
ORDER BY points DESC
Now that this is shown, I was wondering if there's any way to grab the value of "points" and display it somehow so I can verify the number. Is this possible?
There are no group by statements in the queries, so the SUM is most likely not over the expected set. Also COALESCE can be replaced with IFNULL, which might be a bit more efficient.
SELECT q.* , playeruid AS player_id, a.points+b.points+c.points AS points
FROM mybb_matchesgame q
LEFT JOIN (
SELECT IFNULL(SUM(player1points),0) as points,player_id
FROM `mybb_matches`
WHERE timestamp < $time AND winneruid is NOT NULL AND dispute != 3
GROUP BY player_id) a ON player1uid = a.player_id
LEFT JOIN (
SELECT IFNULL(sum(player2points),0) as points,player_id
FROM `mybb_matches`
WHERE timestamp < $time AND winneruid is NOT NULL AND dispute != 3
GROUP BY player_id) b ON player2uid = b.player_id
LEFT JOIN (
SELECT IFNULL(SUM( rank ),0) as points,player_id
FROM `mybb_matchesgame`
GROUP BY player_id) c ON playeruid = c.player_id
WHERE gid = $id
ORDER BY a.points+b.points+c.points DESC;

Categories