My query is originally
'SELECT top 25 "DocNum" FROM T.OHE T4 ON T0."technic" = T4."empID" where T4."firstName"!=\'ERD\' '
But I need to use parameters for T4."firstName"
which is $esi='\'ERD\''
I have a sql query prepared statement below:
$stmt = odbc_prepare($conn,'SELECT top 25 "DocNum" FROM T.OHE T4 ON T0."technic" = T4."empID" where T4."firstName"!=?');
odbc_execute($stmt, array($esi));
while ($row = odbc_fetch_array($stmt)) {
echo $row["DocNum"];
}
And this is the error I got, I assume because of the slashes
odbc_execute(): Can't open file ERD
How can I fix this?
Related
This query works fine on Sequel Pro:
SELECT t1.* FROM `erapido_messages` t1
LEFT OUTER JOIN `erapido_messages` t2 ON `t1.sender_id` = `t2.sender_id`
AND (`t1.msg_date` < `t2.msg_date` OR `t1.msg_date` = `t2.msg_date` AND `t1.sender_id` != `t2.sender_id`)
WHERE `t2.sender_id` IS NULL AND `t1.sender_id`!= `0` AND `t1.receiver_id`= 28
ORDER BY `t1.msg_date` DESC;
When I use it on my php script it returns an error. This is the complete query in php:
$query = "SELECT t1.* FROM `erapido_messages` t1
LEFT OUTER JOIN `erapido_messages` t2 ON `t1.sender_id` = `t2.sender_id`
AND (`t1.msg_date` < `t2.msg_date` OR `t1.msg_date` = `t2.msg_date` AND `t1.sender_id` != `t2.sender_id`)
WHERE `t2.sender_id` IS NULL AND `t1.sender_id`!= `0` AND `t1.receiver_id`= ?
ORDER BY `t1.msg_date` DESC";
//$sql is my connection and it works fine on other queries
$statement = $sql->prepare($query);
//bind parameters for markers: s = string, i = integer, d = double, b = blob
$statement->bind_param('i', $receiver_id);//$receiver_id is defined
//execute query
$statement->execute();
//store the results; allows to count the rows
$statement->store_result();
//bind result variables
$statement->bind_result($id, $receiver_name, $receiver_img, $receiver_email, $sender_id, $sender_name, $sender_email, $sender_img, $subject, $message, $msg_date);
This is the error:
Fatal error: Call to a member function bind_param() on boolean in /messages.php on line 53
I understand that this statement may return 'false' if the query fails:
$statement = $sql->prepare($query);
However, I can't see what is wrong in the query. Any help is welcome!
Thanks much.
Your prepare statement is returning false due to not valid query string. Change your query like the one below. Currently you are escaping your column names because they are in back-tick which results in an error while preparing it
$query = "select * from `dbname` table where `table`.column= ?
ORDER BY `table`.column DESC LIMIT 2 ";
That should fix this error.
This is common issue but I have no choice to code it like this just to get appropriate header and body in Excel file
here how it starts
When a request been made to print, I first began make a query to fetch the headers in the database
SELECT instruments.in_id, instrument_parameters.ip_id,
CASE WHEN gv_x_ipid = -1 THEN 'datetime' ELSE '' END xlabel,
CASE WHEN ip_label LIKE '%Reservoir%' THEN 0 ELSE in_order END legendIndex,
CASE WHEN in_name = 'General' THEN ip_label ELSE in_name END ylabel
FROM graph_plot
LEFT JOIN attributes gptype ON gp_type = gptype.at_id
LEFT JOIN graph_value ON gp_id = gv_gpid
LEFT JOIN instrument_parameters ON gv_y_ipid = ip_id
LEFT JOIN attributes pmunit ON ip_unit = pmunit.at_id
LEFT JOIN instrument_reading yvalue ON gv_y_ipid = iv_ipid
LEFT JOIN instruments ON iv_inid = in_id
WHERE gp_diid = :di_id AND
gp_type = :rpt_type AND
iv_status = 'Y' AND
iv_inid in (".implode(",", $coll->inid).") AND
gv_y_ipid in (".implode(",", $coll->ipid).")
GROUP BY ylabel
ORDER BY legendIndex
and this will produce numbers of headers that I will make it to be like this
DATE | Instrument1 | Instrument2 | Instrument3
The Instrument? will be dynamic based on the query above. I store this in new variable. But the original variable that holds the database results remain intact.
Later, using the same parameters, :di_id and :rpt_type, also another additional parameters, startDt and endDt to make another query just to return a long list of available dates in database. This is based on the startDt and endDt.
$sql2 = "SELECT iv_reading FROM instrument_reading WHERE iv_inid = :inid AND iv_ipid = :ipid AND iv_date = :dt AND iv_status = 'Y'";
When it finish getting the dates, I make two loop like this
foreach ($dates as $key => $dt) {
foreach ($resp as $InstNo => $InstRow) {
try {
$stmt2->execute(array(':dt' => $dt, ':inid' => $InstRow->in_id, ':ipid' => $InstRow->ip_id));
$rowDb = $stmt2->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT);
} catch(PDOException $e) {
echo '{"error":{"text":"'. $e->getMessage() .'"}}';
}
}
}
First, it starts looping the date and second it begins looping the headers (based on the query made right before getting the dates). My problem I always stuck here
$stmt2->execute(array(':dt' => $dt, ':inid' => $InstRow->in_id, ':ipid' => $InstRow->ip_id));
What do you think? Is there any better way to handle this?
For your information, I use Slim and PHPExcel. PHPExcel might have memory issue and I'm thinking to switch to Spout but the documents still about the basic stuff.
In your SQL, you may consider a limit clause to ease the memory load as follows:
$handle = fopen("file.csv", "wb");
$statement = "
SELECT instruments.in_id, instrument_parameters.ip_id,
CASE WHEN gv_x_ipid = -1 THEN 'datetime' ELSE '' END xlabel,
CASE WHEN ip_label LIKE '%Reservoir%' THEN 0 ELSE in_order END legendIndex,
CASE WHEN in_name = 'General' THEN ip_label ELSE in_name END ylabel
FROM graph_plot
LEFT JOIN attributes gptype ON gp_type = gptype.at_id
LEFT JOIN graph_value ON gp_id = gv_gpid
LEFT JOIN instrument_parameters ON gv_y_ipid = ip_id
LEFT JOIN attributes pmunit ON ip_unit = pmunit.at_id
LEFT JOIN instrument_reading yvalue ON gv_y_ipid = iv_ipid
LEFT JOIN instruments ON iv_inid = in_id
WHERE gp_diid = :di_id
AND gp_type = :rpt_type
AND iv_status = 'Y'
AND iv_inid in (".implode(",", $coll->inid).")
AND gv_y_ipid in (".implode(",", $coll->ipid).")
GROUP BY ylabel
ORDER BY legendIndex
LIMIT 250
";
$prep = $dbh->prepare($statement);
for ($i = 0; $prep -> rowCount < 250; $i+= 250) {
fputcsv(prep->fetchAll());
$prep = $dbh->prepare($statement.' OFFSET'.$i);
}
fclose($handle);
Alternatively, you could use system and call SELECT INTO, set the permissions (if necessary) and Bob's your uncle.
You have not terminated the fetch loop.
$rowDb = $stmt2->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT);
gets the "next" row or closes the 'cursor' and terminates.
Are you expecting to get exactly one row? If so, consider doing fetchAll. (Caution: the resultset may be an extra level deep in arrays.)
The PDO MySQL driver will do some buffering, which causes memory exhaustion when looping over large datasets. You can turn this off using $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); which should solve the problem.
$pdo = new PDO('mysql:localhost', $username, $password);
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->prepare('SELECT * FROM instrument...');
$stmt->execute($parameters);
while($row = $stmt->fetch()) {
// Insert logic to write the row to the destination
}
If you'd rather set the attribute for that query only, you can do that as well:
$stmt = $pdo->prepare('SELECT * FROM instrument...', [
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
]);
Keep in mind that you won't be able to run other queries until you are done with your unbuffered one. You can close the old cursor prematurely with $stmt->closeCursor() if you don't need the remaining results. I also cannot speak to the performance of this, but it solved my issue while writing a one-off script.
The setting is mentioned briefly in MySQL's documentation:
https://dev.mysql.com/doc/connectors/en/apis-php-pdo-mysql.html
I am attempting to use inner join to select the stop date of a user's subscription. Here is the code sample:
Global $_CB_framework;
$myId = $_CB_framework->myId();
$db = JFactory::getDbo();
$stopDateQuery = $db->getQuery(true);
$stopDateQuery->select($db->quoteName(array('#__cbsubs_subscriptions.user_id', '#__cbsubs_payment_items.subscription_id', '#__cbsubs_payment_items.stop_date')));
$stopDateQuery->from($db->quoteName('#__cbsubs_subscriptions'));
$stopDateQuery->innerJoin($db->quoteName('#__cbsubs_payment_items' ON '#__cbsubs_subscriptions.id'='#__cbsubs_payment_items.subscription_id'));
$stopDateQuery->where($db->quoteName('#__cbsubs_subscriptions.user_id')." = ".$db->quote($myId));
$db->setQuery($stopDateQuery);
$stopDateQueryResults = $db->loadRow();
$stopDate = $stopDateQueryResults['2'];
echo 'stop Date:'.$stopDate;
I have run the statement directly into phpMyAdmin and the table will join with no problem. I am sure that it has something to do with my formatting of the statement. Any suggestions?
The innerJoin line has syntax errors. Change to:
$stopDateQuery->innerJoin($db->quoteName('#__cbsubs_payment_items') . ' ON #__cbsubs_subscriptions.id = #__cbsubs_payment_items.subscription_id');
innerJoin() takes a string which should be in the format of an SQL join without the join type. for example:
$obj->innerJoin('table_a on table_a.id = table_b.id');
I'm new to PDO statements and so far I've managed to work with it, use prepared statements and many things, until today.
I have two querys, the first retrieve some data, store the results and then the second query uses that data to retrieve the final data. I'm working on a bad designed DB, that's why I have to do weird things.
The first query gets the year of start and the year of end of a sport league. Then, the year is passed to the second query to get data between those years (WHERE).
The problem is that bindParam seems to not work, it doesn't bind the parameter, shows a ?, and then the SQL throws the following exception:
Connection failed: SQLSTATE[42000]: Syntax error or access violation:
1064 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 ''0701' AND ?'0630' ORDER BY e.FECHA DESC' at line 5
The SQL:
$sqlQueryAuxiliar = "SELECT ano_inicio, ano_fin
FROM TEMPORADAS
ORDER BY ano_inicio DESC
LIMIT 1;";
$sqlQuery = "SELECT e.id, e.JORNADA, DATE_FORMAT(e.FECHA, '%Y-%m-%d'),
e.HORA, c1.nombre_temporada, c2.nombre_temporada
FROM ENCUENTROS AS e
JOIN CLUBS AS c1 ON (e.COD_EQUIL = c1.siglas)
JOIN CLUBS AS c2 ON (e.COD_EQUIV = c2.siglas)
WHERE e.FECHA BETWEEN :anoInicio'0701' AND :anoFinal'0630'
ORDER BY e.FECHA DESC;";
And this is the PHP code:
$this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmtAux = $this->_db->prepare($sqlQueryAuxiliar);
$stmtAux->execute();
$fetched = $stmtAux->fetchAll();
$stmtAux = null;
$stmt = $this->_db->prepare($sqlQuery);
$stmt->bindParam(':anoInicio', $fetched[0][0], PDO::PARAM_STR, 12);
$stmt->bindParam(':anoFinal', $fetched[0][1], PDO::PARAM_STR, 12);
$stmt->execute();
while ($row = $stmt->fetch()) {
$partidos[] = $row;
}
$stmt = null;
You cannot concatenate strings in your query this way. Change your query to
SELECT e.id, e.JORNADA, DATE_FORMAT(e.FECHA, '%Y-%m-%d'), e.HORA, c1.nombre_temporada, c2.nombre_temporada
FROM ENCUENTROS AS e
JOIN CLUBS AS c1 ON (e.COD_EQUIL = c1.siglas)
JOIN CLUBS AS c2 ON (e.COD_EQUIV = c2.siglas)
WHERE e.FECHA BETWEEN :anoInicio AND :anoFinal
ORDER BY e.FECHA DESC
and the bindParams to
$stmt->bindValue(':anoInicio', $fetched[0][0] . '0701', PDO::PARAM_STR);
$stmt->bindValue(':anoFinal', $fetched[0][1] . '0630', PDO::PARAM_STR);
Stands to reason, you're building invalid sql:
WHERE e.FECHA BETWEEN :anoInicio'0701' AND :anoFinal'0630'
would be built as basically
WHERE e.FETCHA BETWEEN foobar'0701' AND barbaz'0630'
which is a syntax error.
You probably want
WHERE e.FETCH BETWEEN concat(:anoInicio, '0701') AND concat(:anoFinal, '0630')
instead.
If you are using bound parameters you should not also be passing in a hard-coded value in your query..
"SELECT e.id, e.JORNADA, DATE_FORMAT(e.FECHA, '%Y-%m-%d'), e.HORA, c1.nombre_temporada, c2.nombre_temporada
FROM ENCUENTROS AS e
JOIN CLUBS AS c1 ON (e.COD_EQUIL = c1.siglas)
JOIN CLUBS AS c2 ON (e.COD_EQUIV = c2.siglas)
WHERE e.FECHA BETWEEN :anoInicio AND :anoFinal
ORDER BY e.FECHA DESC;";
I need to count the number of rows from different(!) tables and save the results for some kind of statistic. The script is quite simple and working as expected, but I'm wondering if it's better to use a single query with (in this case) 8 subqueries, or if I should use separate 8 queries or if there's even a better, faster and more advanced solution...
I'm using MySQLi with prepared statements, so the single query could look like this:
$sql = 'SELECT
(SELECT COUNT(cat1_id) FROM `cat1`),
(SELECT COUNT(cat2_id) FROM `cat2`),
(SELECT COUNT(cat2_id) FROM `cat2` WHERE `date` >= DATE(NOW())),
(SELECT COUNT(cat3_id) FROM `cat3`),
(SELECT COUNT(cat4_id) FROM `cat4`),
(SELECT COUNT(cat5_id) FROM `cat5`),
(SELECT COUNT(cat6_id) FROM `cat6`),
(SELECT COUNT(cat7_id) FROM `cat7`)';
$stmt = $db->prepare($sql);
$stmt->execute();
$stmt->bind_result($var1, $var2, $var3, $var4, $var5, $var6, $var7, $var8);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
while the seperate queries would look like this (x 8):
$sql = 'SELECT
COUNT(cat1_id)
FROM
`cat1`';
$stmt = $db->prepare($sql);
$stmt->execute();
$stmt->bind_result($var1);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
so, which would be faster or "better style" related to this kind of query (e.g. statistics, counter..)
My inclination is to put queries into the FROM rather than the SELECT, where possible. In this example, it requires a cross join between the tables:
select c1.val, c2.val . . .
from (select count(cat1_id) as val from cat1) c1 cross join
(select count(cat2_id as val from cat2) c2 cross join
. . .
The performance should be the same. However, the advantage appears with your cat2 table:
select c1.val, c2.val, c2.valnow, . . .
from (select count(cat1_id) as val from cat1) c1 cross join
(select count(cat2_id) as val
count(case when date >= date(now()) then cat2_id end)
from cat2
) c2 cross join
. . .
You get a real savings here by not having to scan the table twice to get two values. This also helps when you realize that you might want to modify queries to return more than one value.
I believe the cross join and select-within-select would have the same performance characteristics. The only way to really be sure is to test different versions.
The better way, is use just one query, because is only one conecction with database, instead of, if you use many queries, then are many conecctions with database, this process involves: coneccting and disconeccting, and this is more slower.
Just to follow up your comment, here is an example using one of my DBs. Using a prepared statement here buys you nothing. This multiple query in fact only executes one RPC to the D/B engine. All of the other calls are local to the PHP runtime system.
$db = new mysqli('localhost', 'user', 'password', 'blog');
$table = explode( ' ', 'articles banned comments config language members messages photo_albums photos');
foreach( $table as $t ) {
$sql[] = "select count(*) as count from blog_$t";
}
if ($db->multi_query( implode(';',$sql) )) {
foreach( $table as $t ) {
if ( ($rs = $db->store_result() ) &&
($row = $rs->fetch_row() ) ) {
$result[$t] = $row[0];
$rs->free();
$db->next_result(); // you must execute one per result set
}
}
}
$db->close();
var_dump( $result );
Just out of interest, I did an strace on this and the relevant four lines are
16:54:09.894296 write(4, "\211\1\0\0\3select count(*) as count fr"..., 397) = 397
16:54:09.895264 read(4, "\1\0\0\1\1\33\0\0\2\3def\0\0\0\5count\0\f?\0\25\0\0\0\10\201"..., 16384) = 544
16:54:09.896090 write(4, "\1\0\0\0\1", 5) = 5
16:54:09.896192 shutdown(4, 2 /* send and receive */) = 0
There was ~1 mSec between the query and the response to and from the MySQLd process (this is because this was on localhost, and the results were in its query cache, BTW).. and 0.8 mSec later the DB close was executed. And that's on my 4-yr old laptop.
Regarding to TerryE's example and the advice to use multi_query(!), I checked the manual and changed the script to fit my needs.. finally I got a solution that looks like this:
$sql = 'SELECT COUNT(cat1_id) as `cat1` FROM `cat1`;';
$sql .= 'SELECT COUNT(cat2_id) as `cat2` FROM `cat2`;';
$sql .= 'SELECT COUNT(cat2_id) as `cat2_b` FROM `cat2` WHERE `date` >= DATE(NOW());';
$sql .= 'SELECT COUNT(cat3_id) as `cat3` FROM `cat3`;';
$sql .= 'SELECT COUNT(cat4_id) as `cat4` FROM `cat4`;';
$sql .= 'SELECT COUNT(cat5_id) as `cat5` FROM `cat5`;';
$sql .= 'SELECT COUNT(cat6_id) as `cat6` FROM `cat6`;';
$sql .= 'SELECT COUNT(cat7_id) as `cat7` FROM `cat7`;';
if ($db->multi_query($sql))
{
do
{
if ($stmt = $db->store_result())
{
while ($row = $stmt->fetch_assoc())
{
foreach ($row as $key => $value)
{
$count[$key] = $value;
}
}
$stmt->free_result();
}
} while ($db->more_results() && $db->next_result());
}
There are some differences to TerryE's example, but the result is the same. I'm aware that there are 7 line at the beginning that are almost identical, but as soon as I need a WHERE clause or something else, I prefer this solution to a foreach loop where I'd need to add queries manually or use exceptions with if { ... } ...
As far as I can see, there should be no problem with my solution, or did I miss something?