get the column name where the data was found in MySQL - php

is it possible to get the Column name where a particulare data was found without looping through the result, maybe by PDO? or is there another way to do this in mySQL?
the example show only 3 columns but for my table i may have up to 30 columns need to be check
if i have a table, table1 and want to find the column(s) where 'x' was found
+----+------+------+------+
| id | Col1 | Col2 | Col3 |
+----+------+------+------+
| 0 | x | b | x |
| 1 | x | x | f |
| 2 | d | x | g |
| 3 | h | j | k |
+----+------+------+------+
currentyl i run a Select then loop to each row and check each row column if data is 'x'
$query= "SELECT * FROM table1 WHERE (Col1='x' OR Col2='x' OR Col3='x')"
$result=mysql_query($query);
$foundCols = array();
$rowCnt = 0;
while ($row = mysql_fetch_assoc($result)) {
$tmpArr = array();
if ($row['Col1'] == 'x') {
$tmpArr[] = 'Col1';
}
if ($row['Col2'] == 'x') {
$tmpArr[] = 'Col2';
}
if ($row['Col3'] == 'x') {
$tmpArr[] = 'Col3';
}
$foundCols[$rowCnt] = $tmpArr;
$rowCnt = $rowCnt+1
}
thank you

Try this:
while ($row = mysql_fetch_assoc($result)) {
...
foreach (array('Col1', 'Col2', 'Col3') as $key) {
if ($row[$key] == 'x') {
$tmpArr[] = $key;
}
}
...
}

Related

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

in MYSQL, get only those columns that have values that are the same

I have a table showing what pieces of a puzzle a user has in Boolean like...
client | col A | col B | col C | col D | col E
john Doe | 1 | 1 | 0 | 0 | 1
Jane Deer| 0 | 1 | 0 | 1 | 0
And I can grab the row from the Db.
// Get puzzle pieces
$requery = "SELECT * FROM puzzletbl WHERE client_id = '$client_id' LIMIT 1";
$reresult = mysqli_query($dbc, $requery);
// Check for missing pieces
if ($reresult){
while ($row = mysqli_fetch_array($reresult, MYSQLI_ASSOC)) {
$status = array("NO", "OKAY");
} // END WHILE
} // END IF REresult
I need to get only those columns with 0 (they are missing piece) so I can add that to an email letting them know what is missing.
Loop through $row, and test whether the value is 0.
while ($row = mysqli_fetch_array($reresult, MYSQLI_ASSOC)) {
$zero_cols = array();
foreach ($row as $col => $val) {
if ($col == "client") {
$client = $val;
} elseif ($val == 0) {
$zero_cols[] = $col;
}
}
// Send mail to $client with $zero_cols info
}

real rank in mysql and php

I do a simple SQL-Query:
SELECT `name`, `likes`
FROM `social`
WHERE `month` = '2015-01'
ORDER BY `likes` DESC
then I add a "Rank" wich is an intenger with ++
$data = array();
$rank = 0;
while ($table_row = mysqli_fetch_assoc($table)) {
$rank++;
$data[$table_row['name']] = $table_row;
$data[$table_row['name']]['rank'] = $rank;
}
The result is left and what I want on the right side
+------+------+-------+ +------+------+-------+
| rank | name | likes | | rank | name | likes |
+------+------+-------+ +------+------+-------+
| 1 | foo | 123 | | 1 | foo | 123 |
| 2 | mfoo | 33 | | 2 | mfoo | 33 |
| 3 | xfoo | 33 | | 2 | xfoo | 33 |
| 4 | yfoo | 30 | | 4 | yfoo | 30 |
| 5 | zfoo | 29 | | 5 | zfoo | 29 |
+------+------+-------+ +------+------+-------+
how do I get the right side table? is there a way to solve it in the query?
EDIT:
There I am standing now:
select IF(#likes=s.likes, #rownum, #rownum:=#rownum+1) rank2,
s.domain_name, s.likes,
(#likes:=s.likes) dummy
from social s,
(SELECT #rownum:=0) x,
(SELECT #likes:=0) y
WHERE `month` = '2015-01'
order by likes desc
but the rank is not 100% correct because I want to skip a rank instead of counting through
I see what's happening here.
I dont know about best practices but I'd probably do something like this myself:
$data = array();
$rank = 0;
$lastlike = 1;
$currentlike = 0;
$i = 0;
while ($table_row = mysqli_fetch_assoc($table)) {
$name = $table_row['name'];
$currentlike = $table_row['likes'];
if ($currentlike != $lastlike) $rank++;
$data[$i] = array('rank'=>$rank,'name'=>$name,'likes'=>$currentlike);
$lastlike = $currentlike;
$i++;
}
I've not checked it but you're welcome to try it out and see.
You can do this with SQL or with PHP (you can test to know which one is the faster).
Note : this 2 solutions will give you a rank which start at 0.
SQL :
SELECT
`name`,
`likes`,
(SELECT COUNT(*) FROM `social` AS S2 WHERE S1.likes > S2.likes) AS `rank_2`
FROM `social` AS S1
WHERE `month` = '2015-01'
ORDER BY `likes` DESC
PHP :
$data = array();
$rank = 0;
$likes_pre = -1;
while ($table_row = mysqli_fetch_assoc($table)) {
$likes_cur = $table_row['likes'];
if ($likes_pre > $likes_cur) {
$rank++;
}
$data[$table_row['name']] = $table_row;
$data[$table_row['name']]['rank'] = $rank;
$likes_pre = $likes_cur;
}
Not tested, but it should work.
Try this... rank should be the same for all rows with the same number of likes
$data = array();
$rank = 0;
$last_likes =0;
while ($table_row = mysqli_fetch_assoc($table)) {
if ($last_likes != $row['likes']) {
$rank++;
}
$data[$table_row['name']] = $table_row;
$data[$table_row['name']]['rank'] = $rank;
}

Check sentences if have same words

tb_content(left) and tb_word(right) :
===================================== ================================
|id|sentence |sentence_id|content_id| |id|word|sentence_id|content_id|
===================================== ================================
| 1|sentence1| 0 | 1 | | 1| a | 0 | 1 |
| 2|sentence2| 1 | 1 | | 2| b | 0 | 1 |
| 3|sentence5| 0 | 2 | | 3| c | 1 | 1 |
| 4|sentence6| 1 | 2 | | 4| a | 1 | 1 |
| 5|sentence7| 2 | 2 | | 5| e | 1 | 1 |
===================================== | 6| f | 0 | 2 |
| 7| g | 1 | 2 |
| 8| h | 1 | 2 |
| 9| i | 1 | 2 |
|10| f | 2 | 2 |
|11| h | 2 | 2 |
|12| f | 2 | 2 |
================================
I need to check if every sentence consist of words that owned by other sentences in every content_id.
for example :
Check for the content_id = 1 they are sentence1 and sentence2. from tb_word, we can see that sentence1 and sentence2 consist of the same word a. if the number of a in two sentences is >=2, then a will be the result. So if I print the result, it must be :
00Array ( [0] => a [1] => b) 01Array ( [3] => a ) 10Array ( [3] => a )11Array ( [0] => c [1] => a [2] => e) where 00 means sentence_id = 0 and sentence_id = 0
first, I make functionTotal to count how many sentence that owned by every content_id :
$total = array();
$sql = mysql_query('select content_id, count(*) as RowAmount
from tb_content Group By contente_id') or die(mysql_error());
while ($row = mysql_fetch_array($sql)) {
$total[] = $row['RowAmount'];
}
return $total;
From that function I get the value of $total and from that I need to check the similarity of some words (from tb_word) between all the possibilities of 2 sentence
foreach ($total as $content_id => $totals){
for ($x=0; $x <= ($totals-1); $x++) {
for ($y=0; $y <= ($totals-1); $y++) {
$shared = getShared($x, $y);
}
}
the function of getShared is :
function getShared ($x, $y){
$token = array();
$shared = array();
$i = 0;
if ($x == $y) {
$query = mysql_query("SELECT word FROM `tb_word`
WHERE sentence_id ='$x' ");
while ($row = mysql_fetch_array($query)) {
$shared[$i] = $row['word'];
$i++;
}
} else {
$query = mysql_query("SELECT word, count(word) as jml
FROM `tb_word` WHERE sentence_id ='$x'
OR sentence_id ='$y'
GROUP BY word ");
while ($row = mysql_fetch_array($query)) {
$jml = $row['jml'];
$token[$i] = $row['word'];
if ($jml >= 2) {
$shared[$i] = $token[$i];
}
$i++;
}
But the result I get is still wrong. the result still mix between different content_id. the result must be group by content_id also. sorry for my bad english and my bad explanation. cmiiw, please help me.. thank you :)
This one can be actually done by DBMS itself, two steps in one query. First, you make a self join in order to prepare sentence combinations within the same content:
SELECT a.content_id,
a.sentence_id AS sentence_id_1,
b.sentence_id AS sentence_id_2
FROM tb_content AS a
JOIN tb_content AS b
ON ( a.content_id = b.content_id
AND a.sentence_id <= b.sentence_id )
The "<=" will keep same sentence joins, like "1-1" or "2-2", and yet avoid bidirectional repetitions, like "1-2" and "2-1". Next you can join the above result with words and count the number of occurances. Like that:
SELECT s.content_id,
s.sentence_id_1,
s.sentence_id_2,
c.word,
Count(*) AS jml
FROM (SELECT a.content_id,
a.sentence_id AS sentence_id_1,
b.sentence_id AS sentence_id_2
FROM tb_content AS a
JOIN tb_content AS b
ON ( a.content_id = b.content_id
AND a.sentence_id <= b.sentence_id )) AS s
JOIN tb_word AS c
ON ( s.content_id = c.content_id
AND ( c.sentence_id = s.sentence_id_1
OR c.sentence_id = s.sentence_id_2 ) )
GROUP BY s.content_id,
s.sentence_id_1,
s.sentence_id_2,
c.word
HAVING Count(*) >= 2;
The result of the above query will give you the container, sentences 1 and 2, the word, and the number of occurances (which is 2 or more). All you need now is collecting the result into the array which as I see you already know to do.
Let me know, if I missunderstood your goal.
How about simply SELECT content_id, word, COUNT(*) as num_appearing FROM tb_word GROUP BY content_id, word?
EDIT: I see the complexity now: your main issue is that the getShared() function has two sentence IDs passed to it, but no content_id to know which content is being analyzed. You're also assuming that content_id and sentence_id numbers are consecutive and start at zero. My code doesn't assume that, and pulls those IDs directly from the database.
<?php
$rs = mysql_query("SELECT * FROM tb_content");
$content = array();
while ($row = mysql_fetch_assoc($rs)) {
if (!isset($content[$row['content_id']])) $content[$row['content_id']] = array();
$content[$row['content_id']][] = $row['sentence_id'];
}
foreach($content as $content_id => $sentences) {
foreach($sentences as $sentence_id) {
foreach($sentences as $compare) {
$shared = getShared($content_id, $sentence_id, $compare);
}
}
}
function getShared($cid, $s1, $s2) {
$rs = mysql_query("SELECT `word`, COUNT(*) AS 'num' FROM `tb_word` WHERE `content_id`={$cid} AND `sentence_id` IN ({$s1}, {$s2}) GROUP BY `word`");
$out = array();
while ($row = mysql_fetch_assoc($rs)) {
if ($rs['num'] >= 2) $out[$rs['word']] = $rs['num'];
}
return $out;
}

Add array elements between each of the existing array elements

I am trying to create a report in Excel by fetching data from MySql. I need to get subject headings from the database and output them to the excel sheet as columns e.g cell: D5, E5, F5 ... M5 etc.
So far I have managed to do so, therefore the display under the cells holds headings something like:
D5:Mathematics, E5:English, F5:Physics, etc.
| A | B | C | D | E | F | G | H |
--------------------------------------------------------------
1 | | | | | | | | |
...
5 | | | | Mathematics | English | Physics | ... | ... |
which is fine. The challenge is, I need to insert a GRADE heading in between each of the Subjects, something like this:
| A | B | C | D | E | F | G | H | I | J | K |
--------------------------------------------------------------------------------------
1 | | | | | | | | | | | |
...
5 | | | | Mathematics | GRADE | English | GRADE | Physics | GRADE | ... | ... |
Now here is what I have so far:
$stringindex = "DEFGHIJKLMNOPQRSTUVWXYZ"; // For the excel column cells
$arr_index = str_split($stringindex); // create array elements
$arr_val2 = array(); // create array
$subject = array();
$subname2 = array();
while($sub_row = mysqli_fetch_array($resub, MYSQLI_ASSOC)) {
$subject[] = $sub_row['name']; // Get the subjects from the database and put them in an array
}
foreach($subject as $sub => $subname) {
$subkey[] = $sub; // array of subject keys e.g 0|1|2|3
$subname2[] = $subname; // array of subjects
}
foreach($arr_index as $arr => $arr_val) {
$arr_val2[] = $arr_val; // array of letters e.g D|E|F|G
}
$acount = count($subname2);
$bcount = count($arr_val2);
$size = ($acount > $bcount) ? $bcount : $acount;
$a = array_slice($subname2, 0, $size);
$b = array_slice($arr_val2, 0, $size);
$combine = array_combine($a, $b);
$sheet = $objPHPExcel->setActiveSheetIndex(0); // PHPExcel functions
foreach($combine as $key => $val) { // GET SUBJECTS
$objPHPExcel->getActiveSheet()->getColumnDimension($val)->setAutoSize(true); // Sets Column Width
$sheet
->setCellValue($val.'5', $key); // Lists Subjects as columns
} // END of FOREACH LOOP
The above code is able to display the subjects as column headings in excel:
QUESTION:
How do I add a code to add a GRADE column after each subject heading?
I hope you'll point me in the right direction coz' I am now stuck.
Thanks in advance.
You can try something like this:
$stringindex = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // For the excel column cells
$columns = str_split($stringindex); // create array elements
$rowIndex = 5; // start at row 5 in Excel
$columnIndex = 3; // start at column D in Excel
$subjects = array();
while($sub_row = mysqli_fetch_array($resub, MYSQLI_ASSOC)) {
$subject[] = $sub_row['name']; // Get the subjects from the database and put them in an array
}
$sheet = $objPHPExcel->setActiveSheetIndex(0); // PHPExcel functions
foreach($subject as $index => $subjectName) { // GET SUBJECTS
$columnName = getColumnName($columnIndex, $columns);
$objPHPExcel->getActiveSheet()->getColumnDimension($columnName)->setAutoSize(true); // Sets Column Width
$sheet->setCellValue($columnName.$rowIndex, $subjectName); // Lists Subjects as columns
$columnIndex++;
$columnName = getColumnName($columnIndex, $columns);
$objPHPExcel->getActiveSheet()->getColumnDimension($columnName)->setAutoSize(true); // Sets Column Width
$sheet->setCellValue($columnName.$rowIndex, "GRADE");
$columnIndex++;
} // END of FOREACH LOOP
function getColumnName($index, $columns) {
$columnName = "";
$numColumns = count($columns);
while($index >= $numColumns) {
$columnName = $columns[($index % $numColumns)] . $columnName;
$index = floor($index / $numColumns) - 1;
}
$columnName = $columns[($index % $numColumns)] . $columnName;
return $columnName;
}
I added a function getColumnName() which gives you "AA", "AB", ... in the event that your subject and grade columns go past the A-Z limit.
$temp=true;
then in the loop that goes through columns:
if($temp==true){
//do stuff
$temp=false;
}else{
//do other stuff
$temp=true;
}

Categories