Count all the rows that match all the values in IN clause - php

The values of my $topics are 1,2,3 i want to make a select query that is similar to SELECT COUNT(*) FROM subtopics WHERE main_id = 1 AND main_id = 2 and main_id = 3..
function countTopics($mid,$forum){
$topics = implode(', ', array_column($mid, 'main_id'));
parse_str("id=1");
$query = "SELECT COUNT(*)
FROM subtopics
WHERE main_id
IN ($topics)
GROUP BY main_id
HAVING COUNT(DISTINCT $topics) = 3";
$stmt = $forum->prepare($query);
$stmt->execute(array(
'mid' => $topics
));
$rows = $stmt->fetchAll();
$count = implode(', ', array_column($rows, 'COUNT(*)'));
$_SESSION['topics_count'] = $count;
}

There are various problems with the code, your SQL doesn't need a HAVING clause, your trying to bind to a variable which isn't in the SQL statement...
function countTopics($mid,$forum){
$topics = implode(', ', array_column($mid, 'main_id'));
$query = "SELECT main_id, COUNT(*) as countID
FROM subtopics
WHERE main_id IN ($topics)
GROUP BY main_id";
if ( $stmt = $forum->prepare($query) ) {
if ( $stmt->execute() ) {
$rows = $stmt->fetchAll();
$count = implode(', ', array_column($rows, 'countID'));
$_SESSION['topics_count'] = $count;
}
}
}
Also you should check if the previous stage has worked - so 'if the statement prepare has worked' etc. Not sure what you would do if any of these fail, but that is down to your application design.
Not surewhat $forum is as it doesn't seem to be used and it would be more normal to return the value of the count and let the calling code decide what to do with the value.
You probably want to do something like...
$rows = $stmt->fetchAll();
$_SESSION['topics_count'] = $rows;
and then later...
foreach ( $_SESSION['topics_count'] as $topic ) {
echo $topic['main_id'].'-'.$topic['countID'].PHP_EOL;
}
Update:
function countTopics($mid,$forum){
$topics = implode(', ', array_column($mid, 'main_id'));
$query = "SELECT main_id, subtopic_id, COUNT(*) as countID
FROM subtopics
WHERE main_id IN ($topics)
GROUP BY main_id, subtopic_id";
if ( $stmt = $forum->prepare($query) ) {
if ( $stmt->execute() ) {
$rows = $stmt->fetchAll();
$_SESSION['topics_count'] = $rows;
}
}
}
I've added a column called 'subtopic_id', this may need to be changed depending on your database column name. This will give rows as something like...
main_id subtopic_id countID
1 1 12
1 2 6
1 3 10
2 6 1
2 11 3
This means you will have multiple rows for each main_id, but they will have each sub topic and a count for that subtopic. If you want to output the data - you will have to use a loop, like the foreach above.

Related

Add COUNT and DISTINCT in $query

How to add select COUNT and DISTINCT in the below $query? Please let me know if you need any other details to solve this issue. Thank you for your time.
if(isset($_POST["intake_year"]))
{
$query = "
SELECT * FROM marketing_data
WHERE intake_year = '".$_POST["intake_year"]."'
";
$statement = $connect->prepare($query);
$statement->execute();
$result = $statement->fetchAll();
foreach($result as $row)
{
$output[] = array(
'semester' => $row["semester"],
'student_matric' => floatval($row["count"])
);
}
echo json_encode($output);
}
//SELECT count(student_matric) AS count, semester, intake_year FROM marketing_data GROUP BY intake_year - This query is to only COUNT student_matric
//SELECT DISTINCT semester FROM marketing_data ORDER BY semester DESC - This query is to only DISTINCT semester
I guess you are looking for something like that
$query = "
SELECT distinct semester , count(student_matric) as count FROM marketing_data
WHERE intake_year = '".$_POST["intake_year"]."'
Group by student_matric " ;

How to limit foreach for multiple table as a one

I have the issue with LIMIT with foreach using PHP.
Basics: I have 50 different tables and in every table I have 2 rows.
When I try to add LIMIT 1 to $$modules_for_all, then I see 50 rows, but I want to see only 1. If I add LIMIT 2, then I see 100 rows.
How I can connect all these tables as a one LIMIT 1 to get 1 row in foreach?
<?php
for ($i = 1; $i <= 50; $i++) {
// $array_table_name contains names with tables
$table_names = $array_table_name[$i];
$modules_for_all = 'g_module_for_all_'.$i;
$$modules_for_all = $db->QueryFetchArrayAll("SELECT * FROM $table_names WHERE user='1' LIMIT 1");
}
for ($i = 1; $i <= 50; $i++) {
$modules_for_from = ${"g_module_for_all_$i"};
foreach ($modules_for_from as $m_foreach_as) {
echo $m_foreach_as['id'];
}
}
Example tables:
table_1
id date_added
1 2018-12-01 00:00:00
2 2018-12-02 00:00:00
table_2
id date_added
1 2018-12-03 00:00:00
2 2018-12-04 00:00:00
table_3
id date_added
1 2018-12-05 00:00:00
2 2018-12-06 00:00:00
Example foreach:
<?php
$array_table_name_1 = 'table_1';
$array_table_name_2 = 'table_2';
$array_table_name_3 = 'table_3';
$for_table_1 = $db->QueryFetchArrayAll("SELECT * FROM $array_table_name_1 WHERE id='1' LIMIT 1 ORDER BY date_added");
$for_table_2 = $db->QueryFetchArrayAll("SELECT * FROM $array_table_name_2 WHERE id='1' LIMIT 1 ORDER BY date_added");
$for_table_3 = $db->QueryFetchArrayAll("SELECT * FROM $array_table_name_3 WHERE id='1' LIMIT 1 ORDER BY date_added");
foreach ($for_table_1 as $m_foreach_as) {
echo $m_foreach_as['id'];
}
foreach ($for_table_2 as $m_foreach_as) {
echo $m_foreach_as['id'];
}
foreach ($for_table_3 as $m_foreach_as) {
echo $m_foreach_as['id'];
}
// Now result is '111' but I want only '1' (realted to make LIMIT 1 to all foreach)
The only way to connect the tables is by using a UNION. So you will need to build one large UNION query and then perform the select after the loop:
$tables = array();
for ($i = 1; $i <= 50; $i++) {
// $array_table_name contains names with tables
$table_names = $array_table_name[$i];
$tables[] = "(SELECT * FROM $table_names WHERE user='1')";
}
$query = implode(" UNION ", $tables) . " ORDER BY date_added LIMIT 1";
$result = $db->QueryFetchArrayAll($query);
foreach ($result as $row) {
echo $row;
}
You are gonna have to use UNION ALL for summing this rows together before ordering and limiting the results.
But keep in mind that a query like this will only work if all the tables in your array have the same structure. If they do not, then you will have to be specific in the query to make them have the same fields.
$array_table_name = [
'table_1',
'table_2',
'table_3',
];
$search_id = 1;
$selectsArray = [];
foreach ($array_table_name as $table_name) {
$selectsArray[] = "SELECT * FROM $table_name WHERE id='$search_id'\n";
}
As you see, I am using foreach() and not for() so you won't update the for by decreasing/increasing the number of tables in the array. So to finally have:
$selectsUnion = implode("UNION ALL\n", $selectsArray) . "ORDER BY date_added \nLIMIT 1";
You can see the code tested and query mounted here: https://3v4l.org/HXH2K
I solved my problem using this: foreach ($modules_for_from as $m_foreach_as) if ($tmp++ < 1) {

Store multiple row table into array to allow for user updates

I have struggled with this concept for a while and am hoping someone can help, please. I can query database records if all values are stored in one row. The challenge I have is when the quantity values are stored on multiple rows but with a common key (e.g. order_id). I want to store into an array and then assign each value to an on-screen variable to allow user updates so that I can update the table again.
For example, if the table looks as follows:
id line part qty
-- ---- ---- ---
1 1 63 2
1 2 104 3
1 3 54 2
1 4 50 1
I have not had success with the following where I establish the number of rows and then try to build a foreach loop to capture the data:
$sql = 'SELECT *, COUNT(*) as $count FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$data = $q->fetch(PDO::FETCH_ASSOC);
for ($x = 0; $x <= $count; $x++ {
$var($x) = $data['qty'];
}
If I can properly separate the values into an array and then reference them somehow, then I could do the following and get them displayed and easily update back to the database:
$var_1 = $data['63']; // part_id = 63
$var_2 = $data['104']; // part_id = 104
$var_3 = $data['54']; // part_id = 54
$var_4 = $data['50']; // part_id = 50
Change this:
$sql = 'SELECT *, COUNT(*) as $count FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$data = $q->fetch(PDO::FETCH_ASSOC);
for ($x = 0; $x <= $count; $x++ {
$var($x) = $data['qty'];
}
To something that makes sense like this
$sql = 'SELECT * FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
while(false !== ($row = $q->fetch(PDO::FETCH_ASSOC))){
echo $row['qty'];
};
UPDATE
$sql = 'SELECT * FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$array = [];
while(false !== ($row = $q->fetch(PDO::FETCH_ASSOC))){
$array['line_'.$row['line']] = $row;
};
UPDATE
The additional code that answers what I was looking for is as follows. Your answer was key to my understanding it all:
$sql = 'SELECT * FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$array = [];
while(false !== ($row = $q->fetch(PDO::FETCH_ASSOC))){
$qty['line_'.$row['line']] = $row['qty'];
};
$var_54 = $qty['line_54'];
$var_63 = $qty['line_63'];

SQL Select count of repeated dates

I'm trying to select count of repeated dates and output its numbers
$user_curr_id = $_SESSION['user_id'];
$sql = "SELECT COUNT(datum) FROM table_name WHERE user_ids = $user_curr_id";
I have no idea how to do it.
2014-07-23,2014-07-23,2014-07-23 => 3
2014-07-24,2014-07-24 =>2
2014-07-25 => 1
and get $result = 3,2,1
I assume you're looking after the GROUP BY clause:
$sql = "SELECT datum, COUNT(datum) as cnt
FROM table_name
WHERE user_ids = $user_curr_id
GROUP BY datum
ORDER BY COUNT(datum) DESC;";
if your column datum is of the data type DATE.
Note
As already mentioned you're vulnerable to sql injection. You should use a parameterized prepared statement and bind your input value to this parameter like that:
$sql = "SELECT datum, COUNT(datum) cnt
FROM table_name
WHERE user_ids = ?
GROUP BY datum
ORDER BY COUNT(datum) DESC;";
$result = array();
if ($stmt = $mysqli->prepare($sql)) {
if ($stmt->bind_param('s', $user_curr_id)) {
if($res = $stmt->execute()) {
while ($row = $res->fetch_assoc()) {
$result[] = $row['cnt']; // add the content of field cnt
}
}
}
}
echo implode(',', $result);

PreparedStatement select with php not working as expected

I have this query:
SELECT id, result, ip_address, added_date
FROM results
WHERE course_id = (
SELECT id
FROM courses
WHERE course = 'informatica'
AND macro_course_id = (
SELECT id
FROM macro_courses
WHERE macro_course = 'scienze-matematiche-fisiche-e-naturali'
AND organization_id = (
SELECT id
FROM organizations
WHERE organization = 'universita-degli-studi-di-torino'
AND city_id = (
SELECT id
FROM cities
WHERE city = 'torino'
AND region_id = (
SELECT id
FROM regions
WHERE region = 'piemonte' ))))) ORDER BY id DESC
And i'm using this code to do it with a preparedstatement
public function getResults($region, $city, $organization, $macro_course, $course) { //works
//added_date=datetime : YYYY-MM-DD HH:mm:ss
echo "SELECT id, result, ip_address, added_date
FROM results
WHERE course_id = (
SELECT id
FROM courses
WHERE course = '$course'
AND macro_course_id = (
SELECT id
FROM macro_courses
WHERE macro_course = '$macro_course'
AND organization_id = (
SELECT id
FROM organizations
WHERE organization = '$organization'
AND city_id = (
SELECT id
FROM cities
WHERE city = '$city'
AND region_id = (
SELECT id
FROM regions
WHERE region = '$region' ))))) ORDER BY id DESC"; //just for me to know what query is being executed
if ($stmt = $this->mysqli->prepare(("
SELECT id, result, ip_address, added_date
FROM results
WHERE course_id = (
SELECT id
FROM courses
WHERE course = ?
AND macro_course_id = (
SELECT id
FROM macro_courses
WHERE macro_course = ?
AND organization_id = (
SELECT id
FROM organizations
WHERE organization = ?
AND city_id = (
SELECT id
FROM cities
WHERE city = ?
AND region_id = (
SELECT id
FROM regions
WHERE region = ? ))))) ORDER BY id DESC
"))) {
$return = array();
$stmt->bind_param('sssss', $course, $macro_course, $organization, $city, $region);
$stmt->execute();
if ($stmt->fetch()) {
$i = 0;
while ($row = $stmt->fetch()) {
print_r($row);//this is never reached
continue;
$s = new Result($row['result'], $row['added_date'], $row['id']);
$return[$i] = $s;
$i+=1;
}
}
}
return $return;
}
The problem is that this function returns 0 rows and 0 errors (checked with $this->mysqli->error), it seems that $row = $stmt->fetch() is always false.
However, if i copy and execute on PHPMyAdmin the output i get at the function top, i see
Showing lines 0 - 0 ( 1 total, Query time 0.0003 sec)
So the query returns a line but it is not catched by php. What am i missing? How can i fix this?
Because you used $stmt-fetch() two times here
if ($stmt->fetch()) {
$i = 0;
while ($row = $stmt->fetch()) {
Remove the if ($stmt->fetch()) condition, it will work as expected.
EDIT
from docs
Note that all columns must be bound by the application before calling $stmt->fetch().
You have to bind the result before calling $stmt->fetch() like this
/* bind result variables */
$stmt->bind_result($name, $code);

Categories