Select data from multiple tables from mysql? - php

I have 4 tables in database and an unique clientid is common in all tables but rest field are different. if we search for any client id , how can we get the information stored corresponding to the searched client id from the any table.
$clientid=$_POST['client'];
$query = "SELECT * FROM 'pfs'
JOIN 'pfssurety'
JOIN 'iso'
JOIN 'incometax'
WHERE clientid='$clientid'";
$result = mysql_query($query)or die (mysql_error());
while($row=mysql_fetch_array($result)) {
echo $row['clientid'];
echo $row['name'];
}

Here is an implementation using mysqli and prevents injection for your $clientid where the id is a number grate then zero as AUTO_INCREMENT columns will never have a 0 value they start at 1
// as this is an int using inval will force it to be a valid whole number
// basic SQL Injection Protection for a fixed id
$clientid = intval($_POST['client']);
if($clientid === 0){
// it was not a valid number as an auto_increment field in mysql can never be 0
die("invalid client");
}
$query="SELECT * FROM `pfs`
JOIN `pfssurety` ON pfssurety.clientid = pfs.clientid
JOIN `iso` ON iso.clientid = pfs.clientid
JOIN `incometax` ON incometax.clientid = pfs.clientid
WHERE pfs.clientid=$clientid";
$result= mysqi_query($query) or die("Query Failed");
while($row=mysql_fetch_array($result))
{
echo $row['clientid'];
echo $row['name'];
}

You meant to use backtique instead of single quote. Otherwise your table names are considered as normal string literal. Also, you are missing ON condition for all your JOIN clauses So your query
SELECT * FROM 'pfs'
Should actually be
SELECT * FROM `pfs`
Change your query to be
SELECT * FROM `pfs`
JOIN `pfssurety` ON condition
JOIN `iso` ON condition
JOIN `incometax` ON condition
WHERE clientid='$clientid'

Maybe you need to set the on in your join as something like this:
SELECT * FROM 'pfs'
JOIN 'pfssurety' ON pfs.clientid=pfssurety.clientid
JOIN 'iso' ON pfs.clientid=iso.clientid
JOIN 'incometax' ON pfs.clientid=incometax.clientid
WHERE clientid='$clientid'
Y suposed that all tables have the clientid attribute.
Instead of using the SELECT * you could use the enumeration of the different attributes you need

You are on the right track using JOIN. You need to specify the common column that the JOIN should be made on.
https://www.w3schools.com/sql/sql_join_left.asp
SELECT a.fieldname, i.fieldname, t.fieldname, p.fieldname FROM 'pfs' as a
LEFT JOIN 'pfssurety' as p ON p.clientid = a.clientid
LEFT JOIN 'iso' as i ON i.clientid = a.clientid
LFT JOIN 'incometax' as t ON t.clientid = a.clientid
WHERE a.clientid='$clientid'";
Also, you should escape your variables to prevent SQL Injection. At a minimum:
a.clientid= "' . mysqli_real_escape_string($clientid) . '"';
http://php.net/manual/en/mysqli.real-escape-string.php

Your code is vulnerable to SQL Injection, you should never use user input directly into your SQL queries. In your code the problem is here:
$clientid = $_POST['client']; // anyone could manipulate this field to inject malicious code
# ...
WHERE clientid='$clientid'";
Check what happens if the value for $_POST['client'] is: ' or 1 = 1;
Next as mentioned in one of the comments stop using deprecated methods, instead for example you can use mysqli. Here is an example of how to use mysqli with prepared statements to avoid SQL Injection:
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$stmt = $conn->prepare('SELECT * FROM `pfs` JOIN `pfssurety` ON condition JOIN `iso` ON condition JOIN `incometax` ON condition WHERE clientid = ?');
$stmt->bind_param('i', $clientid);
$stmt->execute();
$stmt->close();
$conn->close();
A prepared statement is a feature used to execute the same (or similar) SQL statements repeatedly with high efficiency.
Compared to executing SQL statements directly, prepared statements have three main advantages:
Prepared statements reduces parsing time as the preparation on the query is done only once (although the statement is executed multiple times)
Bound parameters minimize bandwidth to the server as you need send only the parameters each time, and not the whole query
Prepared statements are very useful against SQL injections, because parameter values, which are transmitted later using a different protocol, need not be correctly escaped. If the original statement template is not derived from external input, SQL injection cannot occur.
Finally one more thing worth mentioning, try not using * to fetch all columns, instead simply list the columns you need to get. Even if you need to get all columns there are good reasons why not to use *, but instead list all columns.

Related

PHP Prepared Statement variable binding error with subquery

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).

Using the WHERE clause and not filtering a thing

The WHERE clause is exists to help us filter the results, I'm getting from the user a value which tells me how to filter the results such as
WHERE brand="'$brand_that_chosen_by_user'"
One of the options is Every brand which means don't filter at all.
So what value $brand_that_chosen_by_user needs to be so the WHERE clause won't filter a thing and return All brands results.
You would first test if they selected the ALL value before adding the where clause.
$sql = " SELECT * FROM tbl";
if($brand != 'ALL'){
$sql .= " WHERE brand = '{$brand}'";
}
You have a sql injection vulnerability.
$brand_that_chosen_by_user = union select user,password from
users
You should consider just dropping the 'where' clause when the user selects "Every".
You have two options.
Either dynamically add the WHERE clause as needed:
if ($brand != 'Every brand') {
$sql .= " WHERE brand = :brand";
}
Or make your SQL statement handle this as a special case:
SELECT * FROM some_table WHERE :brand = 'Every brand' OR brand = :brand
I'm using PDO prepared statements (to prevent SQL injection), so in both cases, you would need to bind the parameter with $statement->bindParam("brand", $brand);.

I can't retrieve the values from database

$raw_results=mysql_query("SELECT resort_name FROM resorts WHERE resort_id=(SELECT resort_id FROM resort_place WHERE place_id=(SELECT place_id FROM place WHERE place='$query')) ") or die(mysql_error());
$check_num_rows=mysql_num_rows($raw_results);
$solutions = array();
while($row = mysql_fetch_assoc($raw_results)) {
$solutions[] = $row['solution'];
}
This is my code and it returns an error message like
Warning: mysql_query() [function.mysql-query]: Unable to save result set in C:\xampp\htdocs\search\news.php on line 131
Subquery returns more than 1 row
can any one help me to retrieve the values from the data base...
this will yield the same result with you multiple subquery.
SELECT DISTINCT a.resort_name
FROM resorts a
INNER JOIN resort_place b
ON a.resort_id = b.resort_id
INNER JOIN place c
ON b.place_id = c.place_id
WHERE c.place='$query'
As a sidenote, the query is vulnerable with SQL Injection if the value(s) came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?
Use prepared statements using mysqli_ or PDO functions instead. Your query can be accomplished using an explicit JOIN:
SELECT DISTINCT resorts.resort_name
FROM resorts
JOIN resort_place ON resort_place.resort_id = resorts.resort_id
JOIN place ON place.place_id = resort_place.place_id
WHERE place.place = '$query'
use IN operator like place_id in (your sub query here)
$raw_results=mysql_query("SELECT resort_name FROM resorts WHERE resort_id IN
(SELECT resort_id FROM resort_place WHERE place_id IN
(SELECT place_id FROM place WHERE place='$query')
)
") or die(mysql_error());
The other answers are wise, you could do better than nesting queries.
If you really want to do AND my_column_id = (SELECT something FROM ...)
make sure that the subquery returns only one row, maybe by ending it with LIMIT 0, 1.

php loop in mysql query

I have a big mysql query like this:
SELECT u.userid AS `User`
, SUM(CASE WHEN activitydate='2011-07-01' THEN round(time/60) ELSE 0 END) AS `2011-07-01`
, SUM(CASE WHEN activitydate='2011-07-02' THEN round(time/60) ELSE 0 END) AS `2011-07-02`
.......
, SUM(CASE WHEN activitydate='2011-07-30' THEN round(time/60) ELSE 0 END) AS `2011-07-30`
FROM hoursbase h
JOIN person u
ON h.userid = u.id
WHERE h.activitydate BETWEEN '2011-07-01' AND '2011-07-30'
GROUP BY h.userid
ORDER BY h.userid
Is there any way that i can put above query in loop using php.
Also i am try to add one drop down menu and on selecting, the respective month will update in query.
Regards,
Chandru.
If you don't mind the query having a different output format you can rewrite it like so:
SELECT u.userid AS `User`
,activitydate
,sum(round(ifnull(time,0)/60)) as timetaken
FROM hoursbase h
JOIN person u ON h.userid = u.id
WHERE h.activitydate BETWEEN :startdate AND :enddate /*note the : params*/
GROUP BY h.userid, h.activitydate
ORDER BY h.userid, h.activitydate
This will return your data grouped by userid first and then by activitydate.
It will also run a lot faster.
Finally it will be easier to get the results per user per date in php.
And when you change months you don't have to change the number of columns.
Here's how to loop through it in php using a loop:
I've copied the code from this answer: How do I loop through a MySQL query via PDO in PHP?
// $attrs is optional, this demonstrates using persistent connections,
// the equivalent of mysql_pconnect
$attrs = array(PDO::ATTR_PERSISTENT => true);
// connect to PDO
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "password", $attrs);
// the following tells PDO we want it to throw Exceptions for every error.
// this is far more useful than the default mode of throwing php errors
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare the statement. the place holders allow PDO to handle substituting
// the values, which also prevents SQL injection
$stmt = $pdo->prepare("SELECT u.userid AS `User`..... ");
// bind the parameters
$stmt->bindValue(":startdate", "2011-07-01");
$stmt->bindValue(":enddate", "2011-07-31");
// initialise an array for the results
$products = array();
if ($stmt->execute()) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
//do more useful stuff here
//escape all fields that can be entered by users using htmlspecialchars
//to prevent XSS exploits.
echo htmlspecialchars($row['User']);
echo htmlspecialchars($row['activitydate']);
echo $row['timetaken'];
}
}
// set PDO to null in order to close the connection
$pdo = null;
About htmlspecialchars()
You need to escape all string fields that can be entered by a user and that you output to screen.
In this case I escaped userid and activitydate because I'm only 95% sure these are integer and date fields, I'd skip escaping if I was 100% sure, but if I'm not I have to escape.
Links:
How to escape output in PHP
How do I loop through a MySQL query via PDO in PHP?

How can I count the numbers of rows that a MySQL query returned?

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';

Categories