I'm trying to get a certain data from mysql with fetchAll.
I currently have this:
$sql1= $dbh->query("SELECT * FROM information");
$comments= $dbh->prepare("SELECT * FROM comments WHERE idinformation= ?");
if($retail){
while($row = $retail -> fetch(PDO::FETCH_ASSOC)){
$comments->execute(array($row['idproducts']));
$json['data'][] = array(
'id'=>$row['idproducts'],
"headline"=>$row['headline'],
'price'=> array ("full_price" => $row['full_price']),
'description'=>$row['description'],
"comments" => $comments->fetchAll(PDO::FETCH_ASSOC)
);
}
$json_encode = json_encode($json);
$obj = json_decode($json_encode,true);
}
My comments is output all the columns in my database. What if I only want comments,time,id,etc... how would I distinguish this in this syntax?
Thanks in advance!
When querying a SQL database, SELECT statements should also include a list of columns you want returned. This not only saves time because the SQL database doesn't have to retrieve a list of columns on each query, but it requires you to think about what you need. In your case, if you only want: comments, time, id then you should specify it:
$comments= $dbh->prepare("SELECT id, time FROM comments WHERE idinformation= ?");
Change the line
$comments= $dbh->prepare("SELECT * FROM comments WHERE idinformation= ?");
to
$comments= $dbh->prepare("SELECT comments,time,id FROM comments WHERE idinformation= ?");
Edit:
Alternatively use group_concat(comments time id, ', ') in a single SQL query. You could do this as a single "JOIN"ed query, and group_concat the comments if you can get the separator you need. Everything is then done SQL-side = faster.
Documentation: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
Related
Here's my usual way of counting rows...
$query = "SELECT * FROM users";
$stmt = $db->prepare($query);
$stmt->execute();
$count = $stmt->rowCount();
This will count all rows, even if I use a WHERE clause, it'll still count every row that meets that condition. However, let's say I have a table, we'll call it tokensEarned (that's my actual table name). I have the following data...
user_id = 1,2,4,5,8,8,2,4,3,7,6,2 (those are actual rows in my table - clearly, user 1 has 1 entry, 2 has three entries, etc.) In all, I have 12 entries. But I don't want my query to count 12. I want my query to count each user_id one time. In this example, my count should display 8.
Any help on this? I can further explain if you have any specific questions or clarification you need. I would appreciate it. Thank You.
The following query will yield the distinct user count:
$query = "SELECT COUNT(DISTINCT user_id) AS cnt FROM users";
$stmt = $db->prepare($query);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo "distinct user count: " . $row['cnt'];
It isn't possible to get all records and the distinct count in a single query.
Whether you use the query above or you return all the actual distinct rows really depends on whether you need the full records. If all you need are the counts, then it is wasteful to return the data in the records, and what I gave above is probably the best option. If you do need the data, then selecting all distinct rows might make more sense.
You can use distinct in mysql to select only unique fields in your table.
$query = "SELECT distinct user_id FROM users";
$stmt = $db->prepare($query);
$stmt->execute();
$count = $stmt->rowCount();
Change your query to the following, this way you only shows the unique user_id:
$query = "SELECT DISTINCT user_id FROM users";
i am doing a mini project of social networking , i am having a doubt about table .
let see , i need to provide post in their page. to do this,should i have to create table for each user or just create one table and use it for multiple users (data can be fetched by selecting particular user name and display it in their page ).
which is the best way?
my php code:
<?php
$query="select * from table_name where user=$username order by time desc;";
?>
To answer your question
It's best to just use 1 table of users and have a separate able for your posts. Your users table should have all the information for each specific users with 1 unique value that is automatically generated by the MySQL database. (Use auto-increment) And in the posts table you should have all the data for each post with a user_id column that holds the unique value from the users table, this way you know who posted it.
Here is a mockup table structure:
Users table:
uid | name | email
Posts table:
uid | user_id | message
user_id in the posts table should always be equal to some uid in the users table.
Every single table should always have some unique value that is assigned its primary value
My real concern
I am very concerned with the security of your application. Prepared statements are WAY easier to use, and WAY more secure.
In the code snippet that you shared:
<?php
$query="select * from table_name where user=$username order by time desc;";
?>
this query is very insecure, as Bobby Tables would tell you. I'm not sure why type of database connection you are using, but I suggest PDO. I wrote a function that makes this very very easy, here is the snippet for that:
This is a file I usually call connection.php that you can import on any page you need to use your database.
<?php
$host = 'localhost';
$db = '';
$user = '';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host={$host};dbname={$db};charset={$charset}";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
function pdoQuery($query, $values = []) {
global $pdo;
if(!empty($values)) {
$stmt = $con->prepare($query);
$stmt->execute($values);
} else {
$stmt = $con->query($query);
}
return $stmt;
}
?>
This function allows you to EASILY use prepared statements by just
including the connection.php page and writing queries in a way that is
readable, clean, and secure. As I'm sure a lot of people reading this are not used to Prepared Statements or know how they
work, the rest of this post will explain that.
One of the biggest differences here is that instead of using String
Interpolation in
your query, you will set variables as question marks ?, so your
query looks like this: UPDATE table SET user=? instead of UPDATE
table SET user='$user' - and the variables will be sent later for
safety, so this prevents SQL Injection.
This it the way your query would look now:
pdoQuery("SELECT * FROM `table_name` WHERE user=? ORDER BY `time` DESC", [$username]);
This is basically how it works:
pdoQuery(string $query, array $variables)
If you pass no variables, it automatically uses the query() function, if you do pass variables it automatically binds and executes the statements. No matter what query you do, the function always returns the query as an object, so you can act on it using any method you can normally use on a PDO query after the execute.
If you know how these work, you can stop reading here :) I put some
exmaples below of some of the ways you can manipulate the return data
to do what you need to do.
This function returns the object of the query you requested, so if you wanted to loop through all of the results of your query you use it like this:
$stmt = pdoQuery("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username])->fetchAll();
foreach($stmt as $row) {
$row['name']."<br>";
}
Or if you just wanted to get a single column from a specific row, you could use it like this:
$username = pdoQuery("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid])->fetchColumn();
Which will return the username from user where uid=$uid as a string
or if you wanted several values from 1 specific row, you could do
$user = pdoQuery("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid])->fetch();
Which will return to $user as an array that has the username, name, and email of the user.
You can also use this function to INSERT, UPDATE, or basically any type of query you can think of. This is how you insert:
pdoQuery("INSERT INTO `table_name` (`name`,`col2`, `col3`) VALUES (?,?,?)", [$name, $col1, $col2]);
My PDO Class
Since writing this post, I have created a new database wrapper class called GrumpyPDO (Hosted on Github).
This class method returns the object of the query you requested, so if you wanted to loop through all of the results of your query you use it like this:
Fetch All
GrumpyPDO Long Syntax
$stmt = $db->run("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username])->fetchAll();
GrumpyPDO Short Syntax
$stmt = $db->all("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username]);
Loop:
foreach($stmt as $row) {
$row['name']."<br>";
}
Single Column Return
Or if you just wanted to get a single column from a specific row, you could use it like this:
//Long Syntax
$username = $db->run("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid])->fetchColumn();
//Short
$username = $db->cell("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid]);
Which will return the username from user where uid=$uid as a string
Entire Row Return
or if you wanted several values from 1 specific row, you could do
//Long Syntax
$user = $db->run("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid])->fetch();
//Short Syntax
$user = $db->row("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid]);
Which will return to $user as an array that has the username, name, and email of the user.
DML Queries
You can also use this function to INSERT, UPDATE, or basically any type of query you can think of. This is how you insert (All DML's are similar):
$db->run("INSERT INTO `table_name` (`name`,`col2`, `col3`) VALUES (?,?,?)", [$name, $col1, $col2]);
I've been using this command to retrieve the number of the fields which have same email address:
$query = $db->query("SELECT COUNT(`user_id`) FROM `users` WHERE `email`='$email'") or die($db-error);
There are 3 records in users table with the same email address. The problem is when I put * instead of COUNT(user_id) it returns correctly: $query->num_rows gives 3 but when I use COUNT(user_id) then $query->num_rows returns 1 all the time. how can I correct this or where is my problem?
When you use $query->num_rows with that query it will return 1 row only, because there is only one count to return.
The actual number of rows will be contained in that query. If you want the result as an object, or associative array give the count a name:
$query = $db->query("SELECT COUNT(`user_id`) AS total FROM `users` WHERE `email`='$email'") or die($db-error);
And in the returned query total should be 3, while $query->num_rows will still be 1. If you just want the value a quick way would be using $total = $query->fetchColumn();.
As others have said though, be careful with NULL user ids, because COUNT() will ignore them.
Emails have to be uinque in users table. Thus, you need no count at all.
You ought to use prepared statements.
You shouldn't post a code that will never run.
Here goes the only correct way to run such a query:
$sql = "SELECT * FROM `users` WHERE `email`=?";
$stm = $db->prepare($sql);
$stm->execute([$email]);
$user = $stm-fetch();
(the code was written due to erroneous tagging. For mysqli you will need another code, but guidelines remains the same.)
Something like this
$sql = "SELECT * FROM `users` WHERE `email`=?";
$stm = $db->prepare($sql);
$stm->bind_param('s',$email);
$stm->execute();
$res = $stm->get_result()
$user = $res->fetch_assoc();
in $user variable you will have either userdata you will need in the following code or false which means no user found. Thus $user can be used in if() statement all right without the need of any counts.
In case when you really need to count the rows, then you use this count() approach you tried. You can use a function from this answer for this:
$count = getVar("SELECT COUNT(1) FROM users WHERE salary > ?", $salary);
That's the correct behaviour: If you use the COUNT function, the result of your select query will be just one row with one column containing the number of data sets.
So, you can retrieve the number of users with the given E-mail address like this:
$query = $db->query("SELECT COUNT(`user_id`) FROM `users` WHERE `email`='$email'") or die($db-error);
$row = $query->fetch_row();
$count = $row[0];
Note that this is faster than querying all data using SELECT * and checking $query->num_rows because it does not need to actually fetch the data.
I am converting old mysql_query code to PDO parameterized queries. Here's what I have so far. It doesn't seem to return anything. I have tried the same query in phpmyadmin, and in the old code with the same input, and the query returns rows those ways.
public function searchArticle($input)
{
$db = new PDO("mysql:host=localhost;dbname=thecorrectdbname", "root", "supersecretpassword");
$statement = $db->prepare("SELECT * FROM news WHERE headline LIKE '%:title%'
OR content LIKE %:content%'
OR author LIKE '%:author%'
ORDER BY id DESC");
$statement->execute(array('title' =>$query,
'content' =>$query,
'author'=>$query));
$result = $statement->fetchAll();
print_r($result);
if (!$result || $statement->rowCount() <= 0)
{
echo'nothing in this array';
return false;
}
return $result;
}
This returns
Array ( ) nothing in this array
Using the same $db connection I can manage to INSERT data into the DB, so the connection is working.
Two questions.
What am I doing wrong in this code?
Suppose I would get the code working. Is the $result object returned by a PDO prepared statement structurally the same as a mysql_query $result object? If not, how do I convert a PDO resultset to a mysql_query one?
Your replacement variables will get escaped and quoted automatically by PDO, which means you cannot have a variable within quotes.
change the following:
$statement = $db->prepare("SELECT * FROM news WHERE headline LIKE :title
OR content LIKE :content
OR author LIKE :author
ORDER BY id DESC");
$statement->execute(array('title' =>'%'.$query.'%',
'content' =>'%'.$query.'%',
'author'=>'%'.$query.'%'));
You are doing an invalid use of placeholder. Placeholder must be used in the place of whole value.
$statement = $db->prepare("SELECT * FROM news WHERE headline LIKE :title
OR content LIKE :content
OR author LIKE :author
ORDER BY id DESC");
$statement->execute(array('title' =>"%$query%",
'content' =>"%$query%",
'author'=>"%$query%"));
This has been bugging for a long time, and I still can't figure out what i'm doing wrong.
In the code I want to select a few users with a comma separated string. The string will always be legit and valid.
In the first example, the one I would like to use, uses bindParam to assign the value of $postId to the SQL query. I have been using bindParam() for lots of other calls, but in this specific case, it fails.
$postId = "1,2,3";
$stm = $this->db->prepare('SELECT * FROM posts WHERE find_in_set(userId, "?") ORDER BY id DESC');
$stm->bindParam(1, $postId, PDO::PARAM_STR);
$stm->setFetchMode(PDO::FETCH_ASSOC);
$stm->execute();
$results = $stm->fetchAll();
return print_r($results,true);
This code returns:
array (
)
In this other code which I really wouldn't like to use, I just pass the value of $postId right into the sql query.
$stm = $this->db->prepare('SELECT * FROM posts WHERE find_in_set(userId, "'.$postId.'") ORDER BY id DESC');
$stm->setFetchMode(PDO::FETCH_ASSOC);
$stm->execute();
$results = $stm->fetchAll();
return print_r($results,true);
This code returns all the rows it is supposed to retrieve.
My question is; What is the specific problem and how can I avoid doing this again?
You shouldn't have quotes around the placeholder in yout query:
$stm = $this->db->prepare('SELECT * FROM posts WHERE find_in_set(userId, ?) ORDER BY id DESC');
See additional docs here.
Although it's not directly related to the question, it's also a handy habit to get into to use named params. When you have only one param to pass, it's not too bad, but when you start getting five or so question marks in the query, it's MUCH easier to actually read if you used named params:
SELECT * FROM posts WHERE find_in_set(userId, :someID) ORDER BY id DESC
Then you bind them as named params in your code:
$sth->bindParam(':someID', $postId, PDO::PARAM_STR);
You don't need to add the double quotes "?" when referencing the value
'SELECT * FROM posts WHERE find_in_set(userId, "?") ORDER BY id DESC'
Should be
'SELECT * FROM posts WHERE find_in_set(userId, ?) ORDER BY id DESC'