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;
}
Related
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;
}
I have a csv table (my csv file http://jpst.it/1GCd9)
| id | email | name | google.com | yahoo.com |
| 1 | email1#email.com | jack | | + |
| 2 | email2#email.com | jack | + | |
| 3 | email3#email.com | jack | | |
Is it possible to get emails that have "+" by column name?
For example I want to specify google.com and get email email2#email.com
I just know how to get data by column id :(
while (($row = fgetcsv($fileHandle, 0, ",")) !== FALSE) {
if($flag) { $flag = false; continue; }
$explode = explode(";",$row[4]);
echo $explode[4]. ", ";
}
By using sanitized CSV (removing all the excess white space and array filter you can get what you want.
I used array_map('trim', array_filter(explode($delimeter, $lines[0]), function($entry){return !empty($entry);})); to sanitize all input from whitespaces, and discard the "empty" header you have at the end by the last pipe character.
See the following functions: array_map, trim, array_filter.
Then when everything is "normalized" we have an array of associative arrays with the correct fields, so we can search by using array_filter again. The variable $only_with_plus will then only contain associative arrays that match the search parameters.
$only_with_plus = array_filter($entries, function($entry) {
return $entry['google.com'] == '+' && $entry['email'] = 'email2#email.com';
});
See it online: https://ideone.com/ZDn2dv
<?php
$CSV = <<<EOF
| id | email | name | google.com | yahoo.com |
| 1 | email1#email.com | jack | | + |
| 2 | email2#email.com | jack | + | |
| 3 | email3#email.com | jack | | |
EOF;
$delimeter = '|';
$lines = explode("\n", $CSV);
$key_names = array_map('trim', array_filter(explode($delimeter, $lines[0]), function($entry){return !empty($entry);}));
$entries = [];
$len = count($lines);
for($c = 1; $c < $len; $c++) {
$line = array_map('trim', array_filter(explode($delimeter, $lines[$c]), function($entry){return !empty($entry);}));
$entry = [];
foreach($line as $key => $value) {
$entry[$key_names[$key]] = $value;
}
$entries[] = $entry;
}
$only_with_plus = array_filter($entries, function($entry) {
return $entry['google.com'] == '+' && $entry['email'] = 'email2#email.com';
});
var_dump($only_with_plus);
// your code goes here
You cant filter csv directly, but you can filter it after parsing it to array;
http://sandbox.onlinephpfunctions.com/code/f17969e35fcfc5e2f4b2f25202359f1b4cc4840b
I have a csv file with 5 rows :
id | price| name | sku | qty
1 | 22 | widget0 | abcd | 1
2 | 21 | widget1 | efgh | 1
3 | 10 | widget0 | abcd | 2
4 | 44 | widget1 | efgh | 1
5 | 22 | widget4 | mnop | 1
etc...
The first 3 columns are just here for visual purpose and are not used for what I need to achieve.
What I need to do is read the sku and qty data in the file and output the result.
I have to count the number of the same skus and get the total qty per sku.
Based on the example above, I need :
sku | qty
abcd | 3
efgh | 2
ijkl | 1
mnop | 1
With the following code, I can get the total number of the same skus in the file :
$file = ('my.csv');
$fh = fopen($file, 'rb');
$tag = array();
$qty = array();
$row=1;
while($col = fgetcsv($fh)) {
if($row == 1){ $row++; continue; } //skip 1st row
$num = count($fh);
if (isset($tag[$col[3]])) {
$tag[$col[3]]++;
}
else {
$tag[$col[3]] = 1;
}
}
print_r($tag);
It gives me :
sku | qty
abcd | 2
efgh | 2
ijkl | 1
mnop | 1
Which is not correct. I don't know how to get the qty column value and associate it to the total number of skus value in the csv file.
Any thoughts ?
Use below code for your solution
$file = ('my.csv');
$fh = fopen($file, 'rb');
$tag = array();
$qty = array();
$row=1;
while($col = fgetcsv($fh)) {
if($row == 1){ $row++; continue; } //skip 1st row
$num = count($fh);
if (isset($tag[$col[3]])) {
//$tag[$col[3]]++;
$tag[$col[3]] = (int)$tag[$col[3]] + (int)$col[4]; // where $col[4] = qty with forcing to `int` value
}
else {
$tag[$col[3]] = $col[4];
}
}
print_r($tag);
you need to make SUM of quantity instead just increase with +1
Hope this will help!
try this solution
$file = ('my.csv');
$fh = fopen($file, 'rb');
$tag = array();
$qty = array();
$row=1;
//skip first row
fgetcsv($fh, 10000, ",");
while($col = fgetcsv($fh,10000)) {
$num = count($fh);
if (isset($tag[$col[3]])) {
$tag[$col[3]]++;
}
else {
$tag[$col[3]] = 1;
}
}
print_r($tag);
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;
}
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;
}
}
...
}