mysqli::query() expects parameter 1 to be string, object given - php

I had saved the required steps for a parameterized string match query that outputs the subsequent rows. I had lost my files when transferring to a faulty drive. So... I'm trying to mash things together and this isn't working.
$stmt = $link->prepare("SELECT id,entry,date from table WHERE string=? ORDER by Id DESC");
$stmt->bind_param('s',$string);
$stmt->execute();
$stmt->bind_result($id_db,$entry_db,$date_db);
if (($result = $link->query($stmt)) {
while ($row = $result->fetch_row()){
}
}
I can already tell that this is wrong, I don't use the parameterized results and I'm trying to use array indexes such as $row[0].
Going to get yelled at for this one I know.
The end result I want is for example:
string1 has rows: bob, mack, chris
string2 has rows: alice, claire, lara
If $string=string1 then the output should be:
chris
mack
bob
I believe my problem is I am mixing statement types

Assuming that "$link" is an instance of PHP's "mysqli" class, and that "id" and "Id" are two diffrent columns in your table (if it's not the case, please try replacing "Id" with "id" in the segment ".. ORDER BY Id.."), here is, based on your example, what I suggest that you try:
// Declare your "prepare" statement (make sure to change "Id" for "id" if both are used
// in reference to the same column in your table)
$stmt = $link->prepare('SELECT id, entry, date FROM table WHERE string = ? ORDER BY Id DESC');
// Bind the $string variable
$stmt->bind_param('s',$string);
// Execute the statement
$stmt->execute();
// Store the result (this is sometimes useful, depending on the data types in your table)
$stmt->store_result();
// Check whether at least one row in table matches the query, if not, stop here...
if ($stmt->num_rows === 0) exit('No matching rows'); // or do something else...
// Declare a container (i.e. storage) for each row (this is optional and depends on what
// you are trying to achieve)
$data = [];
// Loop through results (this is just an example; this could be achieved in a number
// of different ways)
for ($i = 0; $i < $stmt->num_rows; $i++)
{
// Add a new array cell to $data, at index $i
$data[$i] = [];
// Bind result for row $i
$stmt->bind_result($data[$i]['id'],$data[$i]['entry'],$data[$i]['date']);
// Fetch $i^{th} row
$stmt->fetch();
}
// Check if it worked (temporary)
var_dump($data);

Related

Mysql Query to Select data where, WHERE clause contains both comma separated and individual values

I have a mysql field which may contain single center_id values like AB or csv values like AB,AJ etc..
Currently i do the following in php:
$usercenter = $_SESSION['usercenter'];
$searchForValue = ',';
if( strpos($usercenter, $searchForValue) !== false ) {
$centerid = explode(',', $usercenter);
}
else {
$centerid = $usercenter;
}
and in sql query i do:
SELECT id,node
FROM followup
WHERE center_id IN('".implode("','",$centerid)."')
If there are csv values, it works correctly. How can I write the query to check for both csv values and single value ??
Requesting help..
Given your schema the only solution I can think of is using LIKE.
SELECT id, node FROM followup WHERE center_id LIKE "%AD%";
But this will also select rows with CAD, ADA etc. and can only used to check a single option per condition (so you would have to use AND/OR with multiple LIKE statements.)
Also your solution is kind of an antipattern. Normally you would use a one-to-many relation for this.
You should use FIND_IN_SET() function returns the position of a string within a list of strings. it is working both comma separated and individual values. try the following query
SELECT id,node
FROM followup
WHERE FIND_IN_SET('center_id','".implode("','",$centerid)."')
While it doesn't use indexed values (so for huge datasets it can be rather slow), you can use the MySQL function FIND_IN_SET(). This can search for a single value in a comma-separated list.
While this can't search for multiple values at once, from what I understand in the question, you're just looking for a single value at a time.
The function takes the value to search for (case-sensitive!), and then the column to search in.
SELECT id,node
FROM followup
WHERE FIND_IN_SET('AB', center_id)
DB fiddle
If its the other way around, and you're looking to use all those values in a WHERE IN (..), then you can just explode() it regardless if it is one or not - the returnvalue will be an array which you can use, it doesn't matter if its 1 or greater length. You should however, use a prepared statement in doing so. You can achieve that by generating a dynamic query based on the length of the array.
MySQLi:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // Set MySQLi to throw exceptions - this allows you to automagically check for errors
// Create connection, $mysqli = new mysqli(...);
$parts = explode(',', $usercenter); // Split the comma-separated values
if (empty($parts)) {
// Handle it
}
// Generate dynamic SQL, execute and fetch
$stmt = $mysqli->prepare("SELECT id, node
FROM followup
WHERE center_id IN (".implode(',', array_fill(0, count($parts ), '?')).")");
$stmt->bind_param(str_repeat("s", count($parts)), ...$parts);
$stmt->execute();
$stmt->bind_result($id, $node);
while ($stmt->fetch()) {
// Use $id and $node for each row
}
$stmt->close();
PDO:
// Create connection, $pdo = new PDO(...);
// You should set PDO to throw exceptions on errors
$parts = explode(',', $usercenter); // Split the comma-separated values
if (empty($parts)) {
// Handle it
}
$stmt = $pdo->prepare("SELECT id, node
FROM followup
WHERE center_id IN (".implode(',', array_fill(0, count($parts ), '?')).")");
$stmt->execute([...$parts]);
while ($row = $stmt->fetch()) {
// Use $row['id'] and $row['node'] for each row
}
You might also want to look into filtering out empty values after exploding.

PHP PDO sqlsrv large result set inconsistency

I am using PDO to execute a query for which I am expecting ~500K results. This is my query:
SELECT Email FROM mytable WHERE flag = 1
When I run the query in Microsoft SQL Server management Studio I consistently get 544838 results. I wanted to write a small script in PHP that would fetch these results for me. My original implementation used fetchAll(), but this was exhausting the memory available to php, so I decided to fetch the results one at a time like so:
$q = <<<QUERY
SELECT Email FROM mytable WHERE flag = 1
QUERY;
$stmt = $conn->prepare($q);
$stmt->execute();
$c = 0;
while ($email = $stmt->fetch()[0]) {
echo $email." $c\n";
$c++;
}
but each time I run the query, I get a different number of results! Typical results are:
445664
445836
445979
The number of results seems to be short 100K +/- 200 ish. Any help would be greatly appreciated.
fetch() method fetches one row at a time from current result set. $stmt->fetch()[0] is the first column of the current row.
Your sql query has no ordering and can have some null or empty values (probably).
Since you are controlling this column value in while loop, if the current row's first value is null, it will exit from the loop.
Therefore, you should control only fetch(), not fetch()[0] or something like that.
Also, inside the while loop, use sqlsrv_get_field() to access the columns by index.
$c = 0;
while ($stmt->fetch()) { // You may want to control errors
$email = sqlsrv_get_field($stmt, 0); // get first column value
// $email can be false on errors
echo $email . " $c\n";
$c++;
}
sqlsrv_fetch

Mysql returns duplicate results with numbered key

I did a SELECT query on MySQL and get this as result.
The problem is how can I remove the 2nd duplicated results at for instance we use the 1st item in the list. "0":"1" is a duplicate for "id":"1" I would rather use "id" instead of "0" as the key later on the the app. How could I remove this to simplify the results. I do notice that the "0" means the 1st column as the successive columns does add up by 1.
Here's the $query I run.
SELECT id FROM clubsinformation WHERE :comparisonTime < updateTime
This is caused by most likely the fetching mode, you need to fetch it by associative indices only because right now you're including both associative and numeric index fetching:
No matter what DB API you got, MySQLi or PDO, just set it to associative.
So that it turn it doesn't include the numeric indices, only the column names as keys:
So this would roughly look like in code (from looking at your query placeholders, it seems PDO, so I'll draft a PDO example):
$data = array(); // container
$query = 'SELECT * FROM clubsinformation WHERE :comparisonTime < updateTime';
$select = $db->prepare($query);
$select->bindValue(':comparisonTime', $comparisonTime);
$select->execute();
while($row = $select->fetch(PDO::FETCH_ASSOC)) { // associative
$data[] = $row; // only includes column names
}
// then finally, encode
echo json_encode($data);
// OR SIMPLY
// $data = $select->fetchAll(PDO::FETCH_ASSOC); // associative
// echo json_encode($data);
That fetching is by way of PDO API. If you're using MySQLi you can still use the basic idea.

Issue with value being returned from PDO query

I am experiencing an issue with the values being returned from my PDO statement.
This is my code:
//Execute test
$this->checkConnect();
$stmt = $this->dbh->prepare("SELECT p_id FROM People WHERE lastName = :param1 AND firstName = :param2");
$stmt->bindParam(':param1', $this->lName);
$stmt->bindParam(':param2', $this->fName);
$stmt->execute();
$count = $stmt->rowCount();
//Determine value of test
if($count == FALSE)
{
return FALSE;
}
else
{
$dummyvar = $stmt->fetch();
$this->p_id = implode($dummyvar);
}
When I was going through my database records, I noticed that a certain value was off from what I had input. When I execute a query, it is supposed to grab the value of p_id from the tablePeople. Simple enough. However, what happens is that the number is appended twice to itself. For instance, say p_id is equal to 1. this->p_id will be equal to 11. Or is p_id is equal to 2, the output will be 22. I've executed this query within MySQL and the value is correct. I'm not sure what is happening in my php code. Perhaps something to do with implode? I'm not sure.
Any insight will be appreciated.
Addition: I should also state that p_id is unique, thus only one value can be returned.
First, your fetch statement isn't returning what you think it is. The default output array will have both column name keys, and numeric keys, something like this:
array(
0 => 1,
'pid' => 1,
)
You probably want to get just a numerically-indexed array. Use PDO::FETCH_NUM like this:
$dummyvar = $stmt->fetch(PDO::FETCH_NUM);
Second, if you are going to output more than one field (not in this case obviously) then you have to fix your implode statement. You have to tell it what character to put between the different array values.
$this->p_id = implode(' ', $dummyvar);
For example:
echo implode( ', ', array('a', 'b', 'c') );
> 'a, b, c'
References:
PDOStatement::fetch
implode

how to identify the source table of fields from a mysql query

I have two dynamic tables (tabx and taby) which are created and maintained through a php interface where columns can be added, deleted, renamed etc.
I want to read all columns simulataneously from the two tables like so;-
select * from tabx,taby where ... ;
I want to be able to tell from the result of the query whether each column came from either tabx or taby - is there a way to force mysql to return fully qualified column names e.g. tabx.col1, tabx.col2, taby.coln etc?
In PHP, you can get the field information from the result, like so (stolen from a project I wrote long ago):
/*
Similar to mysql_fetch_assoc(), this function returns an associative array
given a mysql resource, but prepends the table name (or table alias, if
used in the query) to the column name, effectively namespacing the column
names and allowing SELECTS for column names that would otherwise have collided
when building a row's associative array.
*/
function mysql_fetch_assoc_with_table_names($resource) {
// get a numerically indexed row, which includes all fields, even if their names collide
$row = mysql_fetch_row($resource);
if( ! $row)
return $row;
$result = array();
$size = count($row);
for($i = 0; $i < $size; $i++) {
// now fetch the field information
$info = mysql_fetch_field($resource, $i);
$table = $info->table;
$name = $info->name;
// and make an associative array, where the key is $table.$name
$result["$table.$name"] = $row[$i]; // e.g. $result["user.name"] = "Joe Schmoe";
}
return $result;
}
Then you can use it like this:
$resource = mysql_query("SELECT * FROM user JOIN question USING (user_id)");
while($row = mysql_fetch_assoc_with_table_names($resource)) {
echo $row['question.title'] . ' Asked by ' . $row['user.name'] . "\n";
}
So to answer your question directly, the table name data is always sent by MySQL -- It's up to the client to tell you where each column came from. If you really want MySQL to return each column name unambiguously, you will need to modify your queries to do the aliasing explicitly, like #Shabbyrobe suggested.
select * from tabx tx, taby ty where ... ;
Does:
SELECT tabx.*, taby.* FROM tabx, taby WHERE ...
work?
I'm left wondering what you are trying to accomplish. First of all, adding and removing columns from a table is a strange practice; it implies that the schema of your data is changing at run-time.
Furthermore, to query from the two tables at the same time, there should be some kind of relationship between them. Rows in one table should be correlated in some way with rows of the other table. If this is not the case, you're better off doing two separate SELECT queries.
The answer to your question has already been given: SELECT tablename.* to retrieve all the columns from the given table. This may or may not work correctly if there are columns with the same name in both tables; you should look that up in the documentation.
Could you give us more information on the problem you're trying to solve? I think there's a good chance you're going about this the wrong way.
Leaving aside any questions about why you might want to do this, and why you would want to do a cross join here at all, here's the best way I can come up with off the top of my head.
You could try doing an EXPLAIN on each table and build the select statement programatically from the result. Here's a poor example of a script which will give you a dynamically generated field list with aliases. This will increase the number of queries you perform though as each table in the dynamically generated query will cause an EXPLAIN query to be fired (although this could be mitigated with caching fairly easily).
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
function aliasFields($pdo, $table, $delim='__') {
$fields = array();
// gotta sanitise the table name - can't do it with prepared statement
$table = preg_replace('/[^A-z0-9_]/', "", $table);
foreach ($pdo->query("EXPLAIN `".$table."`") as $row) {
$fields[] = $table.'.'.$row['Field'].' as '.$table.$delim.$row['Field'];
}
return $fields;
}
$fieldAliases = array_merge(aliasFields($pdo, 'artist'), aliasFields($pdo, 'event'));
$query = 'SELECT '.implode(', ', $fieldAliases).' FROM artist, event';
echo $query;
The result is a query that looks like this, with the table and column name separated by two underscores (or whatever delimeter you like, see the third parameter to aliasFields()):
// ABOVE PROGRAM'S OUTPUT (assuming database exists)
SELECT artist__artist_id, artist__event_id, artist__artist_name, event__event_id, event__event_name FROM artist, event
From there, when you iterate over the results, you can just do an explode on each field name with the same delimeter to get the table name and field name.
John Douthat's answer is much better than the above. It would only be useful if the field metadata was not returned by the database, as PDO threatens may be the case with some drivers.
Here is a simple snippet for how to do what John suggetsted using PDO instead of mysql_*():
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
$query = 'SELECT artist.*, eventartist.* FROM artist, eventartist LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch()) {
foreach ($row as $key=>$value) {
if (is_int($key)) {
$meta = $stmt->getColumnMeta($key);
echo $meta['table'].".".$meta['name']."<br />";
}
}
}

Categories