The solution to this problem might be a simple over sight of mine.
I am trying to run a MYSQL query stored as a string in PHP. The query runs fine using DBM tool like Navicat but returns false in my PHP development enviorment. Is there something I've over looked?
SET #running_sum = 0;
SELECT
TID,
SumTotal,
T.`Freight`,
T.`Insurance`,
T.`Discount`,
CONCAT(
'$',
FORMAT(
#running_sum :=#running_sum + SumTotal + T.`Freight` + T.`Insurance` - T.`Discount`,
2
)
) AS 'Running Total'
FROM
(
SELECT
TID,
SUM(Quantity * UnitNetValue) AS SumTotal,
T.`Freight`,
T.`Insurance`,
T.`Discount`
FROM
Transactions T
JOIN `Transactions_Products` P ON T.TransactionID = P.TID
WHERE
(
T.TemplateName = ''
OR T.TemplateName IS NULL
)
AND T. STATUS = 1
GROUP BY
TransactionID
) AS T;
I am executing the query like this;
$result = mysql_query($this->query);
$this->query is a string which holds the above query, as it is displayed to you above.
The problem is mysql_query() doesn't support multiple queries. Your SET #running_sum = 0; is considered a separate query and so you'll have to execute that first:
$result1 = mysql_query("SET #running_sum = 0;");
$result2 = mysql_query($this->query); // <-- without the SET ... query
From the Manual:
mysql_query() sends a unique query (multiple queries are not supported)
Side note: The mysql_* library is deprecated, it is recommended to upgrade to a modern MySQL library such as PDO or MySQLi.
There is also possible to use multi_query method instead of query of MySQLi:
$query = "SET #running_sum = 0; SELECT ...";
$db_link->multi_query($query);
put variable like this. i guess it should work.
mysql_query("SELECT #i:=0");
mysql_query("UPDATE table_name SET id = #i:=#i+1");
Related
I have a query with a few subqueries like so
SELECT ...
FROM (SELECT ...
FROM ...
GROUP BY ...) as speedLimitCalc INNER JOIN
(SELECT ...
FROM date a INNER JOIN HOURLY_TEST b ON a.[FULL_DAY_DT] = b.DATE
WHERE (b.DATE BETWEEN '".$date_s."' AND '".$date_e."')
AND HOUR BETWEEN ".$time_s." AND ".$time_e."
AND(LKNO BETWEEN '".$lkno_s."' and '".$lkno_e."')
AND RDNO= '".$rdno."'
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (".$dayquery.")
GROUP BY RDNO, LKNO, PRESCRIBED_DIRECTION, CWAY_CODE) as origtable ON ...
,(SELECT ...
FROM [Dim_date]
WHERE (FULL_DAY_DT BETWEEN '".$date_s."' AND '".$date_e."')
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (".$dayquery.") ) as c
ORDER BY ...
where I am inserting variables in the inner query where clause.
I am trying to parametrize this query using odbc_prepare and odbc_execute, however I am running into issues of binding the variables. At present, when I use the following
$result = odbc_prepare($connection, $query);
odbc_execute($result)or die(odbc_error($connection));
to run this query, everything works fine. However, when I try to bind a variable, such as
AND RDNO= ?
...
odbc_execute($result, array($rdno))or die(odbc_error($connection));
I get the following error message.
PHP Warning: odbc_execute() [/phpmanual/function.odbc-execute.html]: SQL error: [Microsoft][ODBC SQL Server Driver]Invalid parameter number, SQL state S1093 in SQLDescribeParameter
My guess is that it's because I'm binding a variable in a subquery, since this procedure works when the Where clause is in the top Select query.
I was wondering whether anyone else has encountered this issue before, and how they solved it? Thanks
Fixed the issue by removing the need for parameters in the subquery by separating the query into multiple queries using temporary tables.
$query = "SELECT ...
INTO ##avgspeedperlink
FROM Date a INNER JOIN HOURLY_TEST ON a.[FULL_DAY_DT] = b.DATE
WHERE (b.DATE BETWEEN ? AND ?)
AND HOUR BETWEEN ? AND ?
AND(LKNO BETWEEN ? and ?)
AND RDNO= ?
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (?,?,?,?,?,?,?)
GROUP BY RDNO, LKNO, PRESCRIBED_DIRECTION, CWAY_CODE";
$result = odbc_prepare($connection, $query);
odbc_execute($result, array($date_s,$date_e,$time_s,$time_e,$lkno_s,$lkno_e,$rdno,$daysanitised[0],$daysanitised[1],$daysanitised[2],$daysanitised[3],$daysanitised[4],$daysanitised[5],$daysanitised[6]))or die(odbc_error($connection));
$query = "SELECT ...
INTO ##daysinperiod
FROM [RISSxplr].[dbo].[Dim_date]
WHERE (FULL_DAY_DT BETWEEN ? AND ?)
AND pub_hol IN (".$pubholquery.")
AND school_hol IN (".$schholquery.")
AND day_no IN (?,?,?,?,?,?,?)";
$result = odbc_prepare($connection, $query);
odbc_execute($result, array($date_s,$date_e,$daysanitised[0],$daysanitised[1],$daysanitised[2],$daysanitised[3],$daysanitised[4],$daysanitised[5],$daysanitised[6]))or die(odbc_error($connection));
$query = "SELECT ...
FROM ##avgspeedperlink, ##daysinperiod
ORDER BY LKNO, OUTBOUND
drop table ##avgspeedperlink
drop table ##daysinperiod";
Note that I had to use double ## for making the temporary tables (single # means that table is local to the query, ## means that the temporary table becomes global for multiple queries).
Kind of stumped by this one. I have been developing for about a week now, maybe two so it might be a noob mistake, but here is what I have:
<?php
$msDB = new PDO('odbc:Driver={SQL Server Native Client 11.0};Server=SOMESERVER;Trusted_Connection=yes;');
try{
//set values for query
$s="4";
$d1="'2014-10-01 00:00:00'";
$d2="'2014-10-31 23:59:59'";
//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (t1.SELECTION = :s)
AND (tN.RESPONSE_DATE BETWEEN :d1 AND :d2))";
//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->bindParam(':s',$s, PDO::PARAM_INT);
$tbe->bindParam(':d1',$d1, PDO::PARAM_STR);
$tbe->bindParam(':d2',$d2, PDO::PARAM_STR);
//execute query
$tbe->execute();
//fetch resulting data
$res = $tbe->fetchAll(PDO::FETCH_ASSOC);}
//error handling
catch (PDOException $e) {
throw new pdoDbException($e);
}
//print the resulting array
print_r($res);
//set initial count
$cnt=0;
//loop through and increment count
foreach($res as $key=>$value){
foreach($value as $v2 ){
$cnt++;
}
}
//return count value
echo "Total:<br/>".$cnt."<br/>";
?>
I am expecting this to return a result set of the number 3. And when I specify the values in the query manually, everything works as expected and it returns the number 3.
If I however use the bindParam method it returns nothing and throws no errors of any sort. It simply returns an empty array.
I can also break up the query set in $q1 and concatenate the values into it, and it also works flawlessly. I have not really used bindParam before, but as far as I can tell, I am using it correctly.
Works:
//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (t1.SELECTION = ".$s.")
AND (tN.RESPONSE_DATE BETWEEN ".$d1." AND ".$d2."))";
When I run the query in MSSQL Server Management Studio, it also returns the result set I expect.
Can anyone tell me what I am doing wrong?
The default data type passed by PDO::bindParam and PDO::bindValue is ALWAYS text. Conversion from datatype text in MSSQL is only possible to CHAR, VARCHAR, NCHAR, and NVARCHAR. It is because of the datatype issue that the value has to be converted from text into CHAR or VARCHAR and then into DATETIME from there. This is however an implicit conversion, and depending on the value passed to the query, may result in rounding errors, truncation, or simply a failed conversion.
This, does NOT work:
//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (tN.RESPONSE_DATE BETWEEN :d1 AND :d2))";
//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->bindParam(':d1',$d1, PDO::PARAM_INT);
$tbe->bindParam(':d2',$d2, PDO::PARAM_INT);
This however, does work:
$q1 = 'SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (tN.RESPONSE_DATE BETWEEN CONVERT(datetime,CONVERT(VARCHAR(MAX),?))
AND CONVERT(datetime,CONVERT(VARCHAR(MAX),?))))';
//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$tbe->bindParam(1,$d1);
$tbe->bindParam(2,$d2);
Even if I casted the bound parameters as type INT, they were still passed to MSSQL as text causing the failure.
It would be my suggestion however to simply use the original workaround of just passing in the variables directly like so and have the variables be double quoted strings:
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (t1.SELECTION = '$s')
AND (tN.RESPONSE_DATE BETWEEN '$date1' AND '$date2'))";
The quoted string is much easier to handle, and far less prone to error because it need not be converted at all and is simply passed right along to MSSQL Server without issue.
I noticed a slight performance hit with the converts because of the extra processing by MSSQL Server. The query took about half a second longer to run with the conversion than without.
Cheers to #meda for helping with the resolution!
I get this error today and take a lot of my hours.
After upgrading PHP Version to PHP7, using sqlsrv:database driver instead of dblib:dbname make this problem occurs.
To avoid this, still using dblib:dbname event PHP7 FPM already support with sqlsrv:database driver.
In my PHP file, I use this line to pull data from my mySQL database:
$query = "SET #rank=0; SELECT #rank:=#rank +1 as rank, Blah Blah...";
If I check the SELECT statement in phpMyAdmin's SQL window (without $query= ) it works fine.
But, if I use it in PHP, then I get an error. It doesn't like the "SET #rank=0;" bit. Is there a way to use "SET #rank=0;" when it's in "$query=" ? Is there a workaround?
The rest of the code is standard stuff for pulling data from a db:
public function getmyData() {
$mysql = mysql_connect(connection stuff);
$query = "SELECT #rank:=#rank +1 as rank, formatted_school_name, blah blah";
$result = mysql_query($query);
$ret = array();
while ($row = mysql_fetch_object($result)) {
$tmp = new VOmyData1();
$tmp->stuff1 = $row-> stuff1;
$tmp->stuff2 = $row->stuff2;
$ret[] = $tmp;
}
mysql_free_result($result);
return $ret;
}
Update: I'm trying to use Amerb's suggestion of using multi-query. I concatenated the query like so:
$query = "SET #rank = 0";
$query .= "SELECT #rank:=#rank +1 as rank...
I changed the result to:
$result = $mysqli_multi_query($query);
But, it's failing for some reason. I'm on a machine running PHP 5.2. Any suggestions?
This guy here seems to have a way of setting the variable in the same query to zero. I don't have MySQL set on up on this machine to try it, though.
Here's the query he suggests in his blog post:
select #rownum:=#rownum+1 ‘rank’, p.* from player p, (SELECT #rownum:=0) r order by score desc limit 10;
(Is there some homework assignment coming due somewhere having to do with computing ranks? This is the third question I've seen on this in two days.)
Are you checking for duplicate scores?
Try executing it as 2 separate successive queries.
You have to enable the use of multiple queries in one, but i forgot how do do this at the moment. It's a security feature.
Use mysql_multi_query() or rather mysqli_multi_query() instead of mysql_query()
I have a query:
$result = mysql_query("CREATE VIEW temporary(IngList) AS (
SELECT DISTINCT (r1.Ingredient)
FROM recipes r1,
recipes r2
WHERE r1.Country = '$temp'
AND r2.Country = '$temp2'
AND r1.Ingredient = r2.Ingredient)
SELECT COUNT(*) FROM temporary");
I want the query to make a view called temporary and have it return a count of the number of rows in the view temporary. I know this code works without the SELECT COUNT(*) because I checked my database and the view is created.
Yet this code throws the error:
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 'SELECT COUNT(*) FROM temporary' at line 1
I checked the syntax and it seems to be correct. What seems to be the problem because its quite frustrating.
From the mysql_query documentation:
mysql_query() sends a unique query (multiple queries are not supported)...
You can't create the view, and select from it in a single mysql_query. The view is unnecessary:
$sql = sprintf("SELECT COUNT(DISTINCT r1.Ingredient)
FROM recipes r1
WHERE r.country = '%s'
AND EXISTS(SELECT NULL
FROM recipes r2
WHERE r2.Country = '%s'
AND r1.Ingredient = r2.Ingredient)",
$temp, $temp2);
$result = mysql_query($sql);
For starters you have two statements. What you're writing looks more like a stored procedure. Even if it worked, you would need a semicolon at the end of the first statement. And another statement somewhere saying "DROP VIEW ...." when you are done.
And a temp view is a bit of a non sequitur. I can't find any reference to "CREATE VIEW temporary". Or maybe it's to create a view named temporary with an argument? Views don't take arguments.
I think you might get what you want with a semi-simple SQL statement something like:
$result = mysql_query(
"SELECT COUNT(DISTINCT r1.Ingredient)
FROM recipes r1
JOIN recipes r2 ON r1.Ingredient = r2.Ingredient
WHERE r1.Country = '$temp'
AND r2.Country = '$temp2'");
How can I count the number of rows that a MySQL query returned?
Getting total rows in a query result...
You could just iterate the result and count them. You don't say what language or client library you are using, but the API does provide a mysql_num_rows function which can tell you the number of rows in a result.
This is exposed in PHP, for example, as the mysqli_num_rows function. As you've edited the question to mention you're using PHP, here's a simple example using mysqli functions:
$link = mysqli_connect("localhost", "user", "password", "database");
$result = mysqli_query($link, "SELECT * FROM table1");
$num_rows = mysqli_num_rows($result);
echo "$num_rows Rows\n";
Getting a count of rows matching some criteria...
Just use COUNT(*) - see Counting Rows in the MySQL manual. For example:
SELECT COUNT(*) FROM foo WHERE bar= 'value';
Get total rows when LIMIT is used...
If you'd used a LIMIT clause but want to know how many rows you'd get without it, use SQL_CALC_FOUND_ROWS in your query, followed by SELECT FOUND_ROWS();
SELECT SQL_CALC_FOUND_ROWS * FROM foo
WHERE bar="value"
LIMIT 10;
SELECT FOUND_ROWS();
For very large tables, this isn't going to be particularly efficient, and you're better off running a simpler query to obtain a count and caching it before running your queries to get pages of data.
In the event you have to solve the problem with simple SQL you might use an inline view.
select count(*) from (select * from foo) as x;
If your SQL query has a LIMIT clause and you want to know how many results total are in that data set you can use SQL_CALC_FOUND_ROWS followed by SELECT FOUND_ROWS(); This returns the number of rows A LOT more efficiently than using COUNT(*)
Example (straight from MySQL docs):
mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
-> WHERE id > 100 LIMIT 10;
mysql> SELECT FOUND_ROWS();
Use 2 queries as below, One to fetch the data with limit and other to get the no of total matched rows.
Ex:
SELECT * FROM tbl_name WHERE id > 1000 LIMIT 10;
SELECT COUNT(*) FROM tbl_name WHERE id > 1000;
As described by Mysql guide , this is the most optimized way, and also SQL_CALC_FOUND_ROWS query modifier and FOUND_ROWS() function are deprecated as of MySQL 8.0.17
SELECT SQL_CALC_FOUND_ROWS *
FROM table1
WHERE ...;
SELECT FOUND_ROWS();
FOUND_ROWS() must be called immediately after the query.
If you want the result plus the number of rows returned do something like this. Using PHP.
$query = "SELECT * FROM Employee";
$result = mysql_query($query);
echo "There are ".mysql_num_rows($result)." Employee(s).";
Assuming you're using the mysql_ or mysqli_ functions, your question should already have been answered by others.
However if you're using PDO, there is no easy function to return the number of rows retrieved by a select statement, unfortunately. You have to use count() on the resultset (after assigning it to a local variable, usually).
Or if you're only interested in the number and not the data, PDOStatement::fetchColumn() on your SELECT COUNT(1)... result.
The basics
To get the number of matching rows in SQL you would usually use COUNT(*). For example:
SELECT COUNT(*) FROM some_table
To get that in value in PHP you need to fetch the value from the first column in the first row of the returned result. An example using PDO and mysqli is demonstrated below.
However, if you want to fetch the results and then still know how many records you fetched using PHP, you could use count() or avail of the pre-populated count in the result object if your DB API offers it e.g. mysqli's num_rows.
Using MySQLi
Using mysqli you can fetch the first row using fetch_row() and then access the 0 column, which should contain the value of COUNT(*).
// your connection code
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli('localhost', 'dbuser', 'yourdbpassword', 'db_name');
$mysqli->set_charset('utf8mb4');
// your SQL statement
$stmt = $mysqli->prepare('SELECT COUNT(*) FROM some_table WHERE col1=?');
$stmt->bind_param('s', $someVariable);
$stmt->execute();
$result = $stmt->get_result();
// now fetch 1st column of the 1st row
$count = $result->fetch_row()[0];
echo $count;
If you want to fetch all the rows, but still know the number of rows then you can use num_rows or count().
// your SQL statement
$stmt = $mysqli->prepare('SELECT col1, col2 FROM some_table WHERE col1=?');
$stmt->bind_param('s', $someVariable);
$stmt->execute();
$result = $stmt->get_result();
// If you want to use the results, but still know how many records were fetched
$rows = $result->fetch_all(MYSQLI_ASSOC);
echo $result->num_rows;
// or
echo count($rows);
Using PDO
Using PDO is much simpler. You can directly call fetchColumn() on the statement to get a single column value.
// your connection code
$pdo = new \PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'root', '', [
\PDO::ATTR_EMULATE_PREPARES => false,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
// your SQL statement
$stmt = $pdo->prepare('SELECT COUNT(*) FROM some_table WHERE col1=?');
$stmt->execute([
$someVariable
]);
// Fetch the first column of the first row
$count = $stmt->fetchColumn();
echo $count;
Again, if you need to fetch all the rows anyway, then you can get it using count() function.
// your SQL statement
$stmt = $pdo->prepare('SELECT col1, col2 FROM some_table WHERE col1=?');
$stmt->execute([
$someVariable
]);
// If you want to use the results, but still know how many records were fetched
$rows = $stmt->fetchAll();
echo count($rows);
PDO's statement doesn't offer pre-computed property with the number of rows fetched, but it has a method called rowCount(). This method can tell you the number of rows returned in the result, but it cannot be relied upon and it is generally not recommended to use.
If you're fetching data using Wordpress, then you can access the number of rows returned using $wpdb->num_rows:
$wpdb->get_results( $wpdb->prepare('select * from mytable where foo = %s', $searchstring));
echo $wpdb->num_rows;
If you want a specific count based on a mysql count query then you do this:
$numrows = $wpdb->get_var($wpdb->prepare('SELECT COUNT(*) FROM mytable where foo = %s', $searchstring );
echo $numrows;
If you're running updates or deletes then the count of rows affected is returned directly from the function call:
$numrowsaffected = $wpdb->query($wpdb->prepare(
'update mytable set val=%s where myid = %d', $valuetoupdate, $myid));
This applies also to $wpdb->update and $wpdb->delete.
As it is 2015, and deprecation of mysql_* functionality, this is a PDO-only visualization.
<?php
// Begin Vault (this is in a vault, not actually hard-coded)
$host="hostname";
$username="GuySmiley";
$password="thePassword";
$dbname="dbname";
// End Vault
$b='</br>';
try {
$theCategory="fruit"; // value from user, hard-coded here to get one in
$dbh = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepared statement with named placeholders
$stmt = $dbh->prepare("select id,foodName from foods where category=:theCat and perishable=1");
$stmt->bindParam(':theCat', $theCategory, PDO::PARAM_STR,20);
$stmt->execute();
echo "rowCount() returns: ".$stmt->rowCount().$b; // See comments below from the Manual, varies from driver to driver
$stmt = $dbh->prepare("select count(*) as theCount from foods where category=:theCat and perishable=1");
$stmt->bindParam(':theCat', $theCategory, PDO::PARAM_STR,20);
$stmt->execute();
$row=$stmt->fetch(); // fetches just one row, which is all we expect
echo "count(*) returns: ".$row['theCount'].$b;
$stmt = null;
// PDO closes connection at end of script
} catch (PDOException $e) {
echo 'PDO Exception: ' . $e->getMessage();
exit();
}
?>
Schema for testing
create table foods
( id int auto_increment primary key,
foodName varchar(100) not null,
category varchar(20) not null,
perishable int not null
);
insert foods (foodName,category,perishable) values
('kiwi','fruit',1),('ground hamburger','meat',1),
('canned pears','fruit',0),('concord grapes','fruit',1);
For my implementation, I get the output of 2 for both echos above. The purpose of the above 2 strategies is to determine if your driver implementation emits the rowCount, and if not, to seek a fall-back strategy.
From the Manual on PDOStatement::rowCount:
PDOStatement::rowCount() returns the number of rows affected by a
DELETE, INSERT, or UPDATE statement.
For most databases, PDOStatement::rowCount() does not return the
number of rows affected by a SELECT statement. Instead, use
PDO::query() to issue a SELECT COUNT(*) statement with the same
predicates as your intended SELECT statement, then use
PDOStatement::fetchColumn() to retrieve the number of rows that will
be returned. Your application can then perform the correct action.
This is not a direct answer to the question, but in practice I often want to have an estimate of the number of rows that will be in the result set. For most type of queries, MySQL's "EXPLAIN" delivers that.
I for example use that to refuse to run a client query if the explain looks bad enough.
Then also daily run "ANALYZE LOCAL TABLE" (outside of replication, to prevent cluster locks) on your tables, on each involved MySQL server.
> SELECT COUNT(*) AS total FROM foo WHERE bar= 'value';