PHP PDO statement with Sum and other column fails - php

I'm trying to run an SQL query with PDO
This works
$result = $dbo->query("SELECT sum(c) as scfus
FROM tbl
WHERE
YEAR(ondate)=YEAR('".$_POST['startdate']."')
AND MONTH(ondate)=MONTH('".$_POST['startdate']."')
AND DAY(ondate)=$i");
but this does not
$result = $dbo->query("SELECT a,b,sum(c) as scfus
FROM tbl
WHERE
YEAR(ondate)=YEAR('".$_POST['startdate']."')
AND MONTH(ondate)=MONTH('".$_POST['startdate']."')
AND DAY(ondate)=$i");
The only difference is the addition of the a,b column names to the query.
I can run this query (both of them) directly into mysql and get a single record back, as expected, but PDO does not seem to like column names AND sum in the same query?
I can't see a reason, or solution. New to PDO, so was never an issue for me before.
Thanks.
UPDATE - OK, I still think this should work fine, but as a workaround, I've run 2 sql statements, almost exactly the same. One with SELECT SUM(x), one with SELECT a,b, but without the sum. Works fine, but I really should be able to do it in one statement, unless I'm into some PDO limitation I'm not aware of yet.

you might need to GROUP BY c (or whatever column you may want to group domain aggregate function SUM() by) in order to obtain the desired result-set... and maybe take the suggestion above into account.

Try it this way for your query, worked for me for what you want to achieve :
$result = $dbo->query("SELECT a,b,(SELECT sum(c) as whateverFROM tbl),
as scfus
FROM tbl
WHERE
YEAR(ondate)=YEAR('".$_POST['startdate']."')
AND MONTH(ondate)=MONTH('".$_POST['startdate']."')
AND DAY(ondate)=$i");
SUM returns only one line so you'll never get all your results and only the ones of the first matching WHERE criterias (it registers first record found, then only count what it needs).
It will work
Oh, btw, make a timestamp of the date, make a string of the date post in the date sql format and check
WHERE date = $_POST['date']

will work
SELECT a, b , (SELECT SUM(ID)*30 FROM table) FROM table WHERE ID = SOME(SELECT ID FROM tables WHERE users_ID = idYouWant);

Related

PHP mysqli query returning result "1" on joins

I have been trying to pull out some values from php-mysql, and it's returning a strange result "1". It comprises of an inner join with a where clause, everything works fine, but the result is strangely "1" when I try to echo out the ID, but I am assured that the ID is not 1. When I run the same query on the MySQL CLI, it returns exactly what I need but in the php, it doesn't even say there's an error.
Interestingly, only the ID is returning "1", everything else is returning the correct values. The ID on the CLI is- "V8FBaMJT6bqPbpRutJgkRdc44S3Gz3H8VjW5iu5E4yhBlLA1/D8o+EcGMUY62LZLrxb2SSkaxBoUwaiQXQv+3OsoDTuheYTy4ibPsy91X8JhNGFjOWM2MWQyMWMxMTBmMTU5YjU5NzU2NGM3OTc1YQ==", so there's no chance that it is equal to "1".
$showPosts = "SELECT * FROM box
INNER JOIN interactions
ON box.u_id=interactions.actorid
WHERE interactions.actorid=?
AND interactions.type IN ('1','5')
ORDER BY box.time_created";
if ($stmt = $conn->prepare($showPosts)) {
/* bind parameters for markers */
$b = "V8FBaMJT6bqPbpRutJgkRdc44S3Gz3H8VjW5iu5E4yhBlLA1/D8o+EcGMUY62LZLrxb2SSkaxBoUwaiQXQv+3OsoDTuheYTy4ibPsy91X8JhNGFjOWM2MWQyMWMxMTBmMTU5YjU5NzU2NGM3OTc1YQ==";
$stmt->bind_param("s", $b);
/* execute query */
$stmt->execute();
/* bind result variables */
$metaResults = $stmt->result_metadata();
$fields = $metaResults->fetch_fields();
$statementParams = '';
//build the bind_results statement dynamically so I can get the results in an array
foreach($fields as $field){
if(empty($statementParams)){
$statementParams .= "\$post['".$field->name."']";
} else {
$statementParams .= ", \$post['".$field->name."']";
}
}
$statment = "\$stmt->bind_result($statementParams);";
eval($statment);
while($stmt->fetch()){
echo $post['id'];
echo $post['time_created'];
}
}
Now, in the result- the first is the strange "1" and the second is the timestamp.
Also, if I remove the INNER join part, and do a simple SELECT * FROM box, it returns the ID perfectly. And I have also tried doing a stmt->num_rows, and it returns '0'. Maybe I am missing something obvious.
I am new to using joins in php mysql and it has been a big headache for me for the last 2 hours, any help is appreciated.
Thank you.
The problem is that you use SELECT * FROM ... which returns every column from any table you are using. This is not what you want. Always write the columns you want to read from the query.
In this case you have more than one Id column in your result set, one from the table box, the other one from the table interactions. The value of $post['id'] will contain the value of the interactions table. So, change the SELECT query by writing:
SELECT box.id, box.time_created FROM ...
Also, do not use the eval() function, ever. You might want to switch to PDO which has a more clear API (the PDOStatement::fetch function returns the next row as an array)
After hours of research, I have come to an working example and it works just fine.
Someone else might face the same problems in the future and make mistakes, so I am posting an answer to the problem here:
Problems:
Having same column names in two joined tables
The first problem was the the table interactions had the same column name id as that of the table box. Since I used SELECT * FROM box along an inner join with interactions, it resulted in the return of the results based on the second id which was of interactions rather than box.
Not storing the results before showing record count
Secondly, the problem was the results were not being stored as in http://php.net/manual/en/mysqli-stmt.num-rows.php, which was a silly mistake.
Solutions:
Addressing the column repition
So, firstly I decided to change the column name of the table interactions for id, and I changed it to inter_id to avoid further conflicts. Though not a very smart step, it will avoid such silly mistakes in the future. Then as pointed out by the previous answer, I had to specify the column names of the results I wanted to output rather than using a SELECT *, so I changed it to
SELECT box.id, box.time_created FROM box
INNER JOIN interactions
ON box.u_id=interactions.actorid
WHERE interactions.actorid=?
AND interactions.type IN ('1','5')
ORDER BY box.time_created";
That pretty much solved the first problem.
Counting the number of results
The second one was just about adding the $stmt->store_result(); to the code and it worked flawlessly just before I did a echo $stmt->num_rows; and it showed the results perfectly.
Thank you, again.

Mysql query very slow (group by)

mysql query very slow but i use "group by" function...
i remove group by query and query very fast.
How can I solve this problem?
my query code:
$myquery1 = mysql_query("SELECT * FROM konucuklar
WHERE status=''
and category='football'
GROUP BY matchhour
ORDER BY id asc");
while($myquery1record = mysql_fetch_array($myquery1)){
$myquery2 = mysql_query("SELECT * FROM konucuklar
WHERE mactarihi='$bugunt'
and statu=''
and kategori='futbol'
and macsaati='$myquery1record[matchhour]'
ORDER BY id asc");
$toplams=#mysql_num_rows($myquery2);
while ($myquery2record=mysql_fetch_array($myquery2)) {
// code
}
}
}
Your first query does not comply with SQL standards and will be processed by mysql only if strict sql mode is not enabled.
You are issuing the 2nd query in a loop based on the results returned by the 1st query. So, if the 1st query returns 10 rows, then you will execute the 2nd query 10 times. This is very slow. You should rewrite the 2 queries as one, since both queries query the same table and have almost the same where criteria.
No idea what the 2nd while loop does, as I can't see where $listele is defined.
The slow down might not be related to the GROUP BY clause. Try adding an index on columns you need to .
Link to understand index : http://www.tutorialspoint.com/sql/sql-indexes.htm
MySQL Profiling might also help you in your endeavour
Your queries are not optimized and probably could be done better in other way incluiding using only one composed query (JOIN) to fetch all data at once.
Also if your tables have lots of items is good practice to create INDEXES to the fields uses in the common queries for the filter to make the search faster.
Example, your firs select has this complexity (and probably is not well formed)
SELECT * FROM konucuklar WHERE status=''
and category='football'
GROUP BY matchhour
ORDER BY id asc
But is used only to get the matchhour for the second query. The minimal optimization is to use a query to fetch only the required field.
SELECT DISTINCT matchhour FROM konucuklar WHERE status='' and category='football'

Mysql query takes a lot of time to execute

I am working on an timesheet application, and writing a PHP code to fetch all the timesheets till date. This is the query that I have written to fetch the timesheets -
SELECT a.accnt_name, u.username, DATE_FORMAT(t.in_time, '%H:%i') inTime, DATE_FORMAT(t.out_time, '%H:%i') outTime, DATE_FORMAT(t.work_time, '%H:%i') workTime, w.wrktyp_name, t.remarks, DATE_FORMAT(t.tmsht_date, '%d-%b-%Y') tmshtDate, wl.loctn_name, s.serv_name, t.status_code, t.conv_kms convkms, t.conv_amount convamount FROM timesheets t, accounts a, services s, worktypes w, work_location wl, users WHERE a.accnt_code=t.accnt_code and w.wrktyp_code=t.wrktyp_code and wl.loctn_code=t.loctn_code and s.serv_code=t.serv_code and t.usr_code = u. ORDER BY tmsht_date desc
The where clause contains the clauses to get the actual values of respective codes from respective tables.
The issue is that this query is taking a lot of time to execute and the application crashes at the end of few minutes.
I ran this query in the phpmyadmin, there it works without any issues.
Need help in understanding what might be the cause behind the slowness in the execution.
Use EXPLAIN to see the execution plan for the query. Make sure MySQL has suitable indexes available, and is using those indexes.
The query text seems to be missing the name of a column here...
t.usr_code = u. ORDER
^^^
We can "guess" that's supposed to be u.usr_code, but that's just a guess.
How many rows are supposed to be returned? How large is the resultset?
Is your client attempting to "store" all of the rows in memory, and crashing because it runs out of memory?
If so, I recommend you avoid doing that, and fetch the rows as you need them.
Or, consider adding some additional predicates in the WHERE clause to return just the rows you need, rather than all the rows in the table.
It's 2015. Time to ditch the old-school comma syntax for join operation, and use JOIN keyword instead, and move join predicates from the WHERE clause to the ON clause. And format it. The database doesn't care, but it will make it easier on the poor soul that needs to decipher your SQL statement.
SELECT a.accnt_name
, u.username
, DATE_FORMAT(t.in_time ,'%H:%i') AS inTime
, DATE_FORMAT(t.out_time ,'%H:%i') AS outTime
, DATE_FORMAT(t.work_time,'%H:%i') AS workTime
, w.wrktyp_name
, t.remarks
, DATE_FORMAT(t.tmsht_date, '%d-%b-%Y') AS tmshtDate
, wl.loctn_name
, s.serv_name
, t.status_code
, t.conv_kms AS convkms
, t.conv_amount AS convamount
FROM timesheets t
JOIN accounts a
ON a.accnt_code = t.accnt_code
JOIN services s
ON s.serv_code = t.serv_code
JOIN worktypes w
ON w.wrktyp_code = t.wrktyp_code
JOIN work_location wl
ON wl.loctn_code = t.loctn_code
JOIN users
ON u.usr_code = t.usr_code
ORDER BY t.tmsht_date DESC
Ordering on the formatted date column is very odd. Much more likely you want results returned in "date" order, not in the string order with month and day before the year. (Do you really want to sort on the day value first, before the year?)
FOLLOWUP
If this same exact query complete quickly, with the entire resultset (of approx 720 rows) from a different client (same database, same user), then the issue is likely something other than this SQL statement.
We would not expect the execution of the SQL statement to cause PHP to "crash".
If you are storing the entire resultset (for example, using mysqli store_result), you need to have sufficient memory for that. But the thirteen expressions in the select list all look relatively short (formatted dates, names and codes), and we wouldn't expect "remarks" would be over a couple of KB.
For debugging this, as others have suggested, try adding a LIMIT clause on the query, e.g. LIMIT 1 and observe the behavior.
Alternatively, use a dummy query for testing; use a query that is guaranteed to return specific values and a specific number of rows.
SELECT 'morpheus' AS accnt_name
, 'trinity' AS username
, '01:23' AS inTime
, '04:56' AS outTime
, '00:45' AS workTime
, 'neo' AS wrktyp_name
, 'yada yada yada' AS remarks
, '27-May-2015' AS tmshtDate
, 'zion' AS loctn_name
, 'nebuchadnezzar' AS serv_name
, '' AS status_code
, '123' AS convkms
, '5678' AS convamount
I suspect that the query is not the root cause of the behavior you are observing. I suspect The problem is somewhere else in the code.
How to debug small programs http://ericlippert.com/2014/03/05/how-to-debug-small-programs/
phpadmin automatically adds LIMIT to the query, that's why you got fast results.
Check how many rows are in table
Run your query with limit
First of all: modify you query so that it looks like the one given by Spencer
Do you get an error message when your application 'crashes' or does it just stop?
You could try:
ini_set('max_execution_time', 0);
in your php code. This sets the maximum execution time to unlimited. So if there are no errors, your script should execute to the end. So you can see if your query gets the desired results.
Also just as a test end your query with
LIMIT 10
This should greatly speed up your query as it will only take the first ten results.
You can later change this value to one better suited for your needs. Unless you absolutely need the complete result set, I suggest you always use LIMIT in your queries.

Why does mysql_num_rows return 1 for a SELECT on an empty table?

The code:
$review = mysql_query("SELECT conceptID, MIN(nextReview) FROM userconcepts WHERE userID='$userID'");
$nrows = mysql_num_rows($review);
echo "$nrows<br />\n";
The query works when the table has such entries and returns the correct column values. However, when the table is empty, as I can confirm right now in HeidiSQL, mysql_num_rows still returns 1, but the column values are empty. (The problem still remains if the table has other values for different userIDs).
I expect this query to return the empty set sometimes during normal operations, and I want to take action based on the existence of a result, but I also want to use the result if it exists. Any idea why this code is not working as I expect it to work (I expect it to return 0 if the table is empty)?
First of all, the query has a very simple problem: you're showing the conceptID field, but not grouping by it. If you want to show a field on a SELECT that uses aggregate functions, you should show it; not doing so is an error, and will make many engines not execute your query.
That aside, whenever you have an aggregate function, and you don't group by anything (i.e., don't add a GROUP BY clause), the result is one row. Regardless of the amount of rows in the table.
The reason why is because when a SQL engine executes a query with only aggregation functions, then it returns one row. So:
select count(*)
from table
where 1 = 2
is going to return 1 row with the value 0. This is the way that all SQL engines work.
Your query is a little different:
select conceptID, MIN(nextReview)
FROM userconcepts
WHERE userID='$userID'"
In most SQL dialects, you would get an error of the from "conceptID not in group by clause" or something like that. That is, the query would have a syntax error.
MySQL supports this. It will return the minimum value of nextReview (from the rows that meet the where condition) along with an arbitrary value of conceptID (from those same rows). In this case, there are no rows, so the values will be set to NULL.
Perhaps, you want one row per conceptId. That query would be:
select conceptID, MIN(nextReview)
FROM userconcepts
WHERE userID='$userID'
group by conceptId

MySQL Query problem in CodeIgniter

So I'm using the following:
$r = new Record();
$r->select('ip, count(*) as ipcount');
$r->group_by('ip');
$r->order_by('ipcount', 'desc');
$r->limit(5);
$r->get();
foreach($r->all as $record)
{
echo($record->ip." ");
echo($record->ipcount." <br />");
}
Standard:
SELECT `ip`, count(*) as ipcount FROM (`soapi`) GROUP BY `ip` ORDER BY `ipcount` desc LIMIT 5;
And I only get the last (fifth) record echo'ed out and no ipcount echoed.
Is there a different way to go around this? I'm working on learning DataMapper (hence the questions) and need to figure some of this out. I haven't quite wrapped my head around the whole ORM thing.
Is there a way to set the count(*) as ipcount without the funny select() statement? I don't think it's triggering for some reason. This could also be a bug in DataMapper, but I'm less certain of that.
Also I found that even if I use the $r->query() method it doesn't return anything except the last entry if I use something like SELECTipFROMsoapiWHERE 1;. It will however return everything (like it should) if I say SELECT * FROM soapi WHERE 1;. If it doesn't have the * it only returns the last line.
Just verified with the new query, anything except selecting all columns (*) only returns the last record. Any help with this would be great. You can craft a statement like select *, count(*) as ipcount but then you still don't have access to it via $record->ipcount.
For your case, once you use COUNT() function in MySQL, it will only return 1 value. Hence you ip result data would not display out.
I suggest you just split this 2 queries.
1. for COUNT(*)
2. for ip
Hope this help.

Categories