How to query based on multiple relations between columns - MySQL? - php

I have four columns in a properties table: property_id, value, id, material_id.
I also have an array of properties: Array $properties
The schema is a bit complicated, because I want to find the material_id based on the matching properties.
An example:
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
Example table output:
+----+-------------+-------------+-------+
| id | material_id | property_id | value |
+----+-------------+-------------+-------+
| 1 | 1 | 3 | 5 |
| 2 | 1 | 3 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 3 |
| 5 | 2 | 2 | 6 |
| 6 | 2 | 3 | 4 |
| 10 | 4 | 1 | 9 |
| 11 | 4 | 2 | 3 |
| 12 | 4 | 3 | 6 |
+----+-------------+-------------+-------+
Now, I need material_id that satisfies all the properties. How can I do that..? Do I need to use exist statement of MySQL?

Now, for each element in your array you will want to run a statement that looks like this:
SELECT material_id FROM properties WHERE property_id = 2 AND value = 3;
Do you need help on the php code also? You could run a for each loop, but I will need to know what way you are using to communicate with your database for more specifics.
edit
foreach ($properties as $foo => $bar)
{
$sql = 'SELECT material_id FROM properties WHERE ';
foreach ($bar as $key => $value)
{
$sql .= $key .' = '. $value .' AND ';
}
$sql .= 'true';
*run your PDO code on $sql here*
}

On behalf of performance, it's not a good idea to run a query per array's value. If you have an oversized array things can get pretty slower.
So, best solution can be to build a single query including all conditions presented on $properties array:
<?php
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
$qCondition = [];
foreach($properties as $prop) {
$q = sprintf("(property_id = %d AND value = %d)", $prop["property_id"], $prop["value"]);
$qCondition[] = $q;
}
// assuming that your database table name is 'materials'
$sql = sprintf("SELECT * FROM materials WHERE (" . implode(" OR ", $qCondition) . ")");
echo $sql;
Result:
SELECT * FROM materials
WHERE ((property_id = 1 AND value = 3) OR (property_id = 2 AND value = 6) OR (property_id = 3 AND value = 4))
Therefore, you need to run only one single query to get all desired rows.
You can play with suggested solution here: http://ideone.com/kaE4sw

Related

do the math for each data in database sql post result to database in php

I'd like to fetch data from my 2 sql database and do some math and post the result in database
let's say my table1 is like this
+---+---+----------------------------+
| A | B | C |
+---+---+----------------------------+
| 2 | 9 | result from A*B*D*E in php |
| 1 | 8 | result from A*B*D*E in php |
| 4 | 7 | result from A*B*D*E in php |
| 3 | 6 | result from A*B*D*E in php |
| 6 | 5 | result from A*B*D*E in php |
| 6 | 5 | result from A*B*D*E in php |
| 5 | 4 | result from A*B*D*E in php |
+---+---+----------------------------+
and my table2 is like this
+---+----+
| D | E |
+---+----+
| 1 | 9 |
| 2 | 7 |
| 3 | 8 |
| 4 | 6 |
| 5 | 5 |
| 6 | 3 |
| 7 | 2 |
+---+----+
so far what i've done
// database connection
include_once("config.php");
// Query
$query = mysqli_query($conn, "SELECT * FROM table1");
$query2 = mysqli_query($conn, "SELECT * FROM table2");
//Source1
while($user_data1 = mysqli_fetch_array($query))
{
$A[] = $user_data1['A'];
$B[] = $user_data1['B'];
}
//Source2
while($user_data2 = mysqli_fetch_array($query2))
{
$D[] = $user_data2['D'];
$E[] = $user_data2['E'];
}
foreach (array_combine($A, $B) as $ValueA=> $ValueB)
{
foreach (array_combine($D, $E) as $ValueD=> $ValueE)
{
$result1 = $ValueA*$ValueB*ValueD*ValueE;
$val = 0.123;
$result2[] = $result1*$val;
}
$final result = min($result2);
echo round($final result, 2);
unset($result2);
}
I haven't inserted the database yet
still echoing for debug if the math is correct
somehow this code found some bug
for example using my database the final result only echo/showing 6 math result
because in table1 row 5 and 6 has same data
btw of course in my table1 and 2 has primary key
To change C in this case, you don't even need PHP. To UPDATE a value in MySQL with multiple tables just add them with a , when selecting the tables, like this:
UPDATE table1,table2 SET C = table1.A * table1.B * table2.D * table2.E WHERE C IS NULL;
Executing this code once will update all rows so that C = A*B*D*E as wanted where C is not yet set or NULL. If you want to update all rows you can just remove the WHERE condition
Note: Sometimes (at least for me) SQL will give a warning when having no WHERE condition in the SQL query. To bypass this just add WHERE 1=1 at the end.
Just for my understanding: you want to calculate a value for your calculation you need some data from table 1 that is clear, but also from table2 But which one? I guess you want to use the data from the same row ( so row 1 from table1 and row 1 from table2, row 2 from table 1 and row 2 from table2 ) right? Now you have an problem because when you make a select * from table You do not know in which order they give back from your database. Most time it may be the same order as you have input them, but there is no garantie. You have sayed you have an primary key on each table, how have you defined them? I guess you may have a id column, so you can join your table on that id?

Join tables horizontally and dynamically

I need some help from joining tables horizontally my tables are
+---------+---------+
| Candidates Table |
+---------+---------+
| can_id | Name |
+---------+---------+
| 1 | Liza |
| 2 | Sarah |
| 3 | Jane |
| | |
+---------+---------+
+---------+---------+
| Judges Table |
+---------+---------+
| id | Name |
+---------+---------+
| 1 | judge1 |
| 2 | judge2 |
| 3 | judge3 |
+-------------------+
+---------+---------------+--------+-------+
| Score Table |
+---------+-------+------------------------|
| sco_id | can_id| jud_id |crit_id |score|
+---------+--------+-----------------------+
| 1 | 1 | 2 | 1 | 87 |
| 2 | 1 | 3 | 1 | 89 |
| 3 | 1 | 1 | 1 | 80 |
+------------------------------------------+
I need an output of something like this one..
+---------+---------------+-------------+
| Score board |
+---------+---------+-------------------|
| Name | judge1 | judge2 | judge3 |
+---------+---------+-------------------|
| Liza | 80 | 87 | 89 |
|some data|some data|some data|some data|
|some data|some data|some data|some data|
+---------------------------------------+
notes: crit_id is criteria id from criteria table.
Normally I would use some joins and subqueries but my problems is I need the output dynamically where in if I add a new judges it will automatically generate a new column. I need at least 1 candidate data with all of the judges scores then just loop it with parameters on php to get the other candidates data something like
php loop start
<td>name</td>
<td>judge1 score</td>
<td>judge2 score</td>
php end loop
or if i could get the whole candidates table with judges score much better for me not to loop them per candidate
I've tried to research similar questions like
Concatenate more than two tables horizontally in SQL Server
I've tried to code myself but I got stuck with joining the judges..
SELECT s.sco_id,c.Name,c.Municipalities
FROM `tbl_scoring` s
LEFT JOIN tbl_candidates c ON c.`can_id` = s.`can_id`
WHERE s.can_id = 11
AND crit_id = 1
ORDER BY s.jud_id asc
I need a query that would generate dynamically depending on the number of judges either get candidate data with scores of judge then loop it on php or much way better if i get all the data without looping
Initialize the following arrays:
$judges = [];
$scores = [];
$candidates = [];
Then execute your query, and loop the results. Set those values for each iteration:
$judges[$row['jud_id']] = 1;
$candidates[$row['can_id']] = $row['Name'];
$scores[$row['can_id']][$row['jud_id']] = $row['score'];
Now you want to get the participant judges names, so let's run a SQL query:
$sql = 'SELECT Name FROM judges WHERE id IN (' . implode(',', array_keys($judges)) . ')';
And on every iteration set the judge's name in the $judges array:
$judges[$row['id']] = $row['Name'];
Then for the output:
echo '<tr>';
echo '<td>Name</td>';
ksort($judges);
foreach ($judges as $name) {
echo '<td>Judge: ' . $name . '</td>';
}
echo '</tr>';
foreach ($scores as $candidateId => $data) {
echo '<tr>';
echo "<td>$candidates[$candidateId]</td>";
ksort($data);
foreach ($data as $score) {
echo "<td>$score</td>";
}
echo '</tr>';
}
I used ksort on $judges and $data so the score will fit each judge.
first, we retrieve the judges' ids and name that exist on the score table.
$judges = [];
$query = "SELECT id, name FROM Judges WHERE id IN ( SELECT DISTINCT jud_id FROM Score )";
// execute the query and store the results in the $judges array.
we retrieve the candidates' ids and name that exist on the score table.
$candidates = [];
$query = "SELECT id FROM Candidate WHERE id IN ( SELECT DISTINCT can_id FROM Score )";
// execute the query and store the results in the $candidates array.
then, we join the candidate and score table.
$candidate_score = [];
$query = "SELECT Candidate.name, Candidate.id as candidate_id , Score.jud_id, Score.score FROM Candidate JOIN Score ON Score.can_id = Candidate.id";
// execute the query and store it in the $candidate_score array.
now, for each candidate, we fill its score on the $score_board array.
$score_board = [];
foreach ( $candidates as $candidat )
{
$score_board[$candidat] = [];
foreach ( $judges as $judge )
{
$judge_name = $judge['name'];
$judge_id = $judge['id'];
$score_board[$candidat][$judge_name] = get_judge_score($candidate_score,$candidat,$judge_id);
}
}
this is how the get_judge_score will work:
function get_judge_score ( $scores , $candidate , $judge )
{
$score_filtred = array_filter($scores, function ($score) use ($candidate,$judge) {
return $score['jud_id'] == $judge && $score['candidate_id'] = $candidate;
});
return count($score_filtred) > 0 ? $score_filtred[0]['score'] : 0;
}

Count same values in different column mysql

I need to count how many times in ripeted the same values in different columns for the same id..
I'll try to clarify with an example:
TABLE:
+-----+-----+-----+-----+-----+
| id | d01 | d02 | d03 | d04 |
+=====+=====+=====+=====+=====+
| 1 | A | A | B | B |
+-----+-----+-----+-----+-----+
| 2 | A | A | A | A |
+-----+-----+-----+-----+-----+
| 3 | B | B | A | A |
+-----+-----+-----+-----+-----+
| 4 | A | A | A | A |
+-----+-----+-----+-----+-----+
| 5 | A | A | A | A |
+-----+-----+-----+-----+-----+
| 6 | B | A | A | A |
+-----+-----+-----+-----+-----+
I need to know how many times the value "B" is repeating for any person (ID)..
Is that possible to do that? RESULTS
+-----+-----+-----+
| id | count B |
+=====+=====+=====+
| 1 | 2 |
+-----+-----+-----+
| 2 | 0 |
+-----+-----+-----+
| 3 | 2 |
+-----+-----+-----+
I was thinking to use the function "SUM" but I have no idea how to display just the single ID.
Thanks in advance, hope the question is clear enough!
If there are only four columns:
SELECT id, (d01 = 'B') + (d02 = 'B') + (d03 = 'B') + (d04 = 'B')
FROM tablename
No there are 31 columns
That's a problem which you can solve in two ways:
Repeat the condition for the other 27 columns :)
Normalize your structure so that each value is dependent on both the id and a numeric value that represents a calendar.
The PHP way
You can also fetch all columns and let PHP solve this for you:
$res = $db->query('SELECT * FROM tablename');
foreach ($res->fetchAll(PDO::FETCH_ASSOC) as $row) {
$id = $row['id'];
unset($row['id']); // don't count the id column
$count = count(array_keys($row, 'B', true));
printf("ID %d: %d\n", $id, $count);
}
Since you seem to be using mysql_*:
// SHOW COLUMNS returns all the columns and constrains of the defined table
// We only need the column names so we will be later calling it by 'Field'
$sql = mysql_query("SHOW COLUMNS FROM table"); //your table name here
$val_to_count = 'B'; //value to count here
$id = 1; //id to search for
$new_sql = 'SELECT id, ';
// In this loop we will construct our SELECT query using the columns returned
// from the above query
while($row=mysql_fetch_array($sql)){
if($row['Field']!='id'){
$new_sql .= ' ('.$row['Field'].' = "'.$val_to_count.'") + ';
}
}
//Removing the last "+ " produced in the select query
$new_sql = rtrim($new_sql,"+ ");
$new_sql .= ' as count FROM table WHERE id = '.$id; //table name here again
// so $new_sql now has an output like:
// SELECT ID, (d01 = 'B') + (d02 = 'B') ... WHERE id = 1
$sql2 = mysql_query($new_sql);
//executing the constructed query with the output below
while($row2=mysql_fetch_array($sql2)){
echo 'ID - '.$row2['id']."<br>";
echo 'Count - '.$row2['count']."<br>";
}
Note:
mysql_* is deprecated, please consider to migrate to mysqli_*

PHP and MySQL, array associated with 2 keys

I have this scenario.
I input $groupid="1";
main table
----------------------
| groupid | postid |
|---------------------|
| 1 | 1 |
| 2 | 2 |
| 1 | 3 |
$query = "SELECT postid FROM `mainl` WHERE groupid='$groupid'";
$result = mysql_query($query);
// a group of postids belonging to that groupid which should hold [1, 3] for groupid=1
while($row = mysql_fetch_array($result)) {
$postids[] = $row["postid"];
}
second table
-------------------------------------------
| postid | commentid | comment |
-------------------------------------------
| 1 | 1 | testing 1 |
| 1 | 2 | testing 2 |
| 1 | 3 | what? |
| 2 | 1 | hello |
| 2 | 2 | hello world |
| 3 | 1 | test 3 |
| 3 | 2 | begin |
| 3 | 3 | why? |
| 3 | 4 | shows |
$query = "SELECT * FROM `second`";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
if (in_array($row["postid"], $postids)) {
$comments[$row["postid"]] = $row["comment"];
But how should I take care of commented
I want the postid array to be [1,3] and my comment array to be
[commentid: comment] [1:testing1, 2: testing2, 3: what?] for postid=1
and
[1:test3, 2:begin, 3: why? 4:shows] for postid=3
how should be arrange everything such comment are associated with commentid and postid?
First I would follow rokdd suggestion and make 1 query
SELECT m.groupid , s.postid, s.commentid, s.comment FROM `main1` m JOIN `second` s USING (postid) where m.groupid = 1
Then I would make a multi-dimensional array
while ($row = mysql_fetch_array($result))
$groups[$row['groupid'][$row['postid']][$row['commentid']=$row['comment'];
then to iterate through the array
foreach($groups as $group)
foreach($group as $post)
foreach($post as $comment)
echo $comment;
This will keep track of groups also (if you ever want to select by more than 1 group.
If you don't care about groups just drop off the first part of the array.
while ($row = mysql_fetch_array($result))
$posts[$row['postid']][$row['commentid']=$row['comment'];
foreach($posts as $post)
foreach($post as $comment)
echo $comment;
I guess to use the join in sql so that you will have one statement:
SELECT * FROM second as second_tab LEFT join main as main_table ON main_table.post_id=second_table.post_id WHERE main_table.group_id="3"
Well not tested now but thats a way to solve some of your problems!

php retrieve multiple data from mysql

I insert multiple id from my checkbox to MySQL database using php post form. In example I insert id (checkbox value table test) to mysql. Now I need a function to retrieve data from MySQL and print to my page with my example output (print horizontal list name of table test where data = userid)
My checkbox value (table name is test):
id | name
----+-------
1 | test1
2 | test2
3 | test3
4 | test4
5 | test5
6 | test6
7 | test7
9 | test9
MySQL data insert (name of table usertest):
id | data | userid
----+---------+--------
1 | 1:4:6:9 | 2
2 | 1:2:3:4 | 5
3 | 1:2 | 7
Example outout :( print horizontal list name of table test where data = userid )
user id 2 choise : test1 - test4 - test6 - test9
Thanks
Assuming your usertest table has only the three columns listed in your example you should replace it with the following -
CREATE TABLE usertest (
data INTEGER NOT NULL,
userid INTEGER NOT NULL,
PRIMARY KEY (data, userid)
);
Then your data will look like -
+------+--------+
| data | userid |
+------+--------+
| 1 | 2 |
| 4 | 2 |
| 6 | 2 |
| 9 | 2 |
| 1 | 5 |
| 2 | 5 |
| 3 | 5 |
| 4 | 5 |
| 1 | 7 |
| 2 | 7 |
+------+--------+
Querying this data then becomes trivial -
SELECT usertest.userid, GROUP_CONCAT(test.name SEPARATOR ' - ')
FROM usertest
INNER JOIN test
ON usertest.data = test.id
GROUP BY usertest.userid
You can read more about GROUP_CONCAT here
You could use a PHP solution and store the possible checkbox values in an array indexed by their ids. Something like -
<?php
$db = new PDO('mysql:dbname=test;host=127.0.0.1', 'user', 'pass');
$sql = 'SELECT id, name FROM test';
$stmt = $db->prepare($sql);
$stmt->execute();
$array = array();
while ($row = $stmt->fetchObject()) {
$array[$row->id] = $row->name;
}
$sql = 'SELECT userid, data FROM usertest';
$stmt = $db->prepare($sql);
$stmt->execute();
while ($row = $stmt->fetchObject()) {
$data = explode(':', $row->data);
foreach($data as $key => $val) {
$data[$key] = $array[$val];
}
print "user id {$row->userid} choise : " . implode(' - ', $data) . "<br/>\n";
}

Categories