Query mysql for post and comments system - mysql

I'm using codeigniter for make a post and comments system. I did all the querys but I don't know how get the comments in the table post_comment. This is my query for take all the post shared. Thank you for the help.
function get_post_profile($user_id,$limit) {
$this->db->select('post_user.user_id,post_user.id_post_shared,post_shared.post_text,users.name,users.surname,users.id');
$this->db->join('post_shared', 'post_shared.id_post = post_user.id_post_shared');
$this->db->join('users','users.id = post_user.user_id');
$this->db->where('post_user.user_id',$user_id);
$this->db->order_by('post_user.id_post_shared','DESC');
$this->db->limit($limit);
$query = $this->db->get('post_user');
if ($query->num_rows() > 0) {
return $query->result();
} else {
return false;
}
}
users_table
id | name | surname |
1 jhon Smith
2 Sally Dunk
post_user table
id_post_shared | user_id |
1 1
post_share table
id_post | post_text
1 Hello guys
post_comment table
comment_text | id_post | id_user
Hello! 1 2

Try and reply:
$this->select('post_comment.comment_text, post_comment.id_post, post_comment.id_user')->join('post_share', 'post_share.id_post = post_comment.id_post')->join('users', 'users.id = post_comment.id_user')->get('post_comment');
EDIT
function get_comments(){
$data = array();
$posts = array();
$posts = $this->db->select('id_post as post_id, post_text', false)->order_by('id_post', 'desc')->get('post_share', 10)->result_array(); #get first 10 posts
if( is_array( $posts ) && count( $posts ) > 0 ){
foreach( $posts as $key=>$each ){
## gather the comments for the posts ###
$comments = array();
$comments = $this->db->select('comment_text, id_user')->where('id_post', $each['post_id'])->get('post_comment')->result_array();
if( is_array( $comments ) && count( $comments ) ){
$posts[$key]['comments'] = $comments;
}
}
}
return $posts;
}
EDIT 1
if( isset( $posts ) && is_array( $posts ) && count( $posts ) > 0 ){
foreach( $posts as $key=>$each ){
echo "Post id :".$each['post_id']." Post txt: ".$each['post_text']."<br>";
if( isset( $each['comments'] ) && is_array( $each['comments'] ) && count( $each['comments'] ) ){
foreach( $each['comments'] as $subKey=>$subEach ){
echo "Comment Txt :".$subEach['comment_text']."<br>";
}
}
}
}

Add LEFT JOIN to your post_comment
$this->db->select('post_user.user_id,post_user.id_post_shared,
post_shared.post_text,users.name,users.surname,users.id,post_comment.comment_text');
$this->db->join('post_shared', 'post_shared.id_post = post_user.id_post_shared');
$this->db->join('users','users.id = post_user.user_id');
$this->db->join('post_comment ','users.id = post_comment .id_user','LEFT');
$this->db->where('post_user.user_id',$user_id);
$this->db->order_by('post_user.id_post_shared','DESC');
$this->db->limit($limit);
$query = $this->db->get('post_user');
third parameter in the call is to specify the type of join join('table','relation','join type')

Try this:
$sql = "SELECT a.*,b.id,b.name,b.surname,c.id_post_shared,c.user_id,d.id_post,d.post_text
FROM post_comment a, users_table b, post_user c,post_share d
WHERE b.id = c.user_id
AND b.id = $user_id
AND c.id_post_shared = d.id_post
AND d.id_post = a.id_post";
$result = $this->db->query($sql)->result_array();
echo $result[0]['comment_text'];

Related

How to pivot my table in mysql

I have table database like this :
i want to make on table view like this :
Thanks.
I assume you need it per year basis.
Select year, id_lesson,
Sum(case when term = 1 then exam_1 end) exam_1_term_1,
Sum(case when term = 1 then exam_2 end) exam_2_term_1,
Sum(case when term = 2 then exam_1 end) exam_1_term_2,
Sum(case when term = 2 then exam_2 end) exam_2_term_2,
Sum(case when term = 3 then exam_1 end) exam_1_term_3,
Sum(case when term = 3 then exam_2 end) exam_2_term_3
From your_table
Group by id_lesson, year;
Try this logic, Hope it is help.
$qdata = mysqli_query("SELECT * FROM table ORDER BY ID_Lesson");
$rows = array();
if (mysqli_num_rows($qdata) > 0) {
// Store all exam based on ID_Lesson ar array
while ($data = mysqli_fetch_array($qdata)) {
if (!isset($row[$data['ID_Lesson']])) {
$rows[$data['ID_Lesson']] = array($data['ID_Lesson'], $data['Exam1'], $data['Exam2']);
}
else {
$rows[$data['ID_Lesson']][] = $data['Exam1'];
$rows[$data['ID_Lesson']][] = $data['Exam2'];
}
}
$html = '';
// Print per element as <tr> row
foreach ($rows as $k => $row) {
$html .= "<tr><td>" . implode("</td><td>", $row) . "</td></tr>";
}
}

mysql query returning different dates

I am trying to add a new feature to my weather station, date of highest temperature and the date it rained the most.
Why do does this code give different dates in the result?
If I changed the first query to either T, R, P or H, the maximum for the row are shown but the date is always the same.
Once I understand that, I may be able to fix other problems with the code.
This is the output
$result = mysqli_query($con,"
SELECT DateTime,max(Tmax)
FROM alldata
WHERE YEAR(DateTime) = YEAR(NOW())
"
);
while($row = mysqli_fetch_array($result)){
$maxtempDate1 = $row['DateTime'];
$tempMax1 = $row['max(Tmax)'];
}
$result = mysqli_query($con,"
SELECT DateTime,Tmax
FROM alldata
WHERE Tmax=(select max(Tmax) from alldata)
AND YEAR(DateTime) = YEAR(NOW())
"
);
while($row = mysqli_fetch_array($result)){
$maxtempDate = $row['DateTime'];
$tempMax = $row['Tmax'];
}
$result = mysqli_query($con,"
SELECT DateTime,Tmax
FROM alldata
WHERE YEAR(DateTime) = YEAR(NOW())
ORDER BY Tmax DESC
LIMIT 1
"
);
while($row = mysqli_fetch_array($result)){
$maxtempDate = $row['DateTime'];
$tempMax = $row['Tmax'];
}

Laravel Join table and query

I have 3 table. Users, Accounts and Booking. I have try three table join and year and month wise query. [3 Table diagram][1]
But query booking calculation is show wrong. It's showing double quantity.
$january = DB::table('users')
->join('bookings', 'users.id', '=', 'bookings.user_id')
->join('accounts', 'users.id', '=', 'accounts.user_id')
->orderBy('users.room_id','asc')
->groupBy('users.id')
->whereYear('bookings.bookingdate','=', '2016')
->whereMonth('bookings.bookingdate','=','01')
->whereYear('accounts.accountdate','=', '2016')
->whereMonth('accounts.accountdate','=','01')
->select('users.*',
DB::raw("COUNT(case when bookings.breakfast='on' then 1 else null end) AS t_breakfast"),
DB::raw("COUNT(case when bookings.lunch='on' then 1 else null end) AS t_lunch"),
DB::raw("COUNT(case when bookings.dinner='on' then 1 else null end) AS t_dinner"),
DB::raw("SUM(accounts.amount) AS t_amount")
)
->get();
dd($january);
My Accounts table is:
Accounts Table
My Booking table is:
Bookings Table
When I'm run this query it's show:
+"t_breakfast": "2"
+"t_lunch": "2"
+"t_dinner": "2"
+"t_amount": "22.00"
But I need t_breakfast, t_lunch, t_dinner quantity is: 1. But It's showing double.
When I try one query I did not solved this problem. then I try two query and solved it.
$data = DB::select("SELECT users.id, users.name , users.picture, users.room_id,
SUM(CASE WHEN bookings.breakfast='on' THEN 1 ELSE 0 END) AS t_b ,
SUM(CASE WHEN bookings.lunch='on' THEN 1 ELSE 0 END) AS t_l ,
SUM(CASE WHEN bookings.dinner='on' THEN 1 ELSE 0 END) AS t_d FROM `users`
INNER JOIN
`bookings` ON users.id=bookings.user_id AND
MONTH(bookings.bookingdate) = $month AND
YEAR(bookings.bookingdate) = $year
GROUP BY users.id
ORDER BY users.room_id ASC");
$datas = [];
$data = json_decode(json_encode($data),true);
foreach ($data as $key => $value) {
$x = [];
$x = $value;
$x['exp'] = Account::where('user_id',$x['id'])->whereMonth('accountdate','=',$month)->whereYear('accountdate','=',$year)->sum('amount');
$datas[] = $x;
}
$total_t_b = $total_t_l = $total_t_d = $total_exp = 0;
foreach ($datas as $data) {
$total_t_b += $data['t_b'];
$total_t_l += $data['t_l'];
$total_t_d += $data['t_d'];
$total_exp += $data['exp'];
}
$g_total = $total_t_b + $total_t_l + $total_t_d;
if($g_total <= 0) {
$perbookingprice = 0;
} else {
$perbookingprice = $total_exp / $g_total;
}

MySQL to MSSQL Query Translation

I am a novice when it comes to MSSQL and have been trying to convert the following MySQL query without any joy. I am connecting to a MySQL Database within Microsoft SQL Server Management Studio via ODBC. This works great and very simple queries work just fine. However the following query is a bit more complicated(and probably not as optimized as it could be), and I am not able to get it working.
First query below is the original MySQL Query, and the second query is my attempted MSSQL translation.
MySQL Query
SELECT timestamp, `First Name`, `Last Name`, `Email Address`, `Department`, `Case`, `Partner`, `Category`, `Tag Title`, `Question`, `Answer`,
MAX(CASE `Secondary Metric Question` WHEN 'Support' THEN `Secondary Metric Question` end) AS 'Metric 1 Title',
MAX(CASE `Secondary Metric Question` WHEN 'Support' THEN `Answer` end) AS 'Metric 1 Answer',
MAX(CASE `Secondary Metric Question` WHEN 'Completeness' THEN `Secondary Metric Question` end) AS 'Metric 2 Title',
MAX(CASE `Secondary Metric Question` WHEN 'Completeness' THEN `Answer` end) AS 'Metric 2 Answer',
MAX(CASE `Secondary Metric Question` WHEN 'Policy' THEN `Secondary Metric Question` end) AS 'Metric 3 Title',
MAX(CASE `Secondary Metric Question` WHEN 'Policy' THEN `Answer` end) AS 'Metric 3 Answer',
`Message`,
CASE `Reply Requested` WHEN 1 THEN "YES" ELSE "NO" END AS "Reply Requested",
`Response Session`
FROM (
SELECT T0.timestamp, T8.first_name AS 'First Name', T8.last_name AS 'Last Name', T8.email AS 'Email Address', T0.dept AS 'Department', T0.case AS 'Case', T0.partner AS 'Partner', T3.title AS 'Category', T2.title AS 'Question', T2.private_title AS 'Tag Title', T6.title AS 'Secondary Metric Question', T0.answer AS 'Answer', T4.key AS 'Message', T4.reply_requested AS 'Reply Requested', T0.response_session AS 'Response Session'
FROM responses AS T0
LEFT JOIN qrs_metrics AS T1
ON T0.qrs_metric_id = T1.qrs_metric_id
LEFT JOIN quick_responses AS T2
ON T1.qrs_id = T2.qrs_id
LEFT JOIN custom_categories AS T3
ON T2.category = T3.original_id AND T3.user_id = T2.user_id
LEFT JOIN rre_aggregates AS T4
ON T0.comment_id = T4.id
LEFT JOIN widget_responses AS T5
ON T0.widget = T5.id
LEFT JOIN secondary_metrics AS T6
ON T1.metric_id = T6.id
LEFT JOIN private_messages AS T7
ON T4.id = T7.comment_id AND T7.type = 3
LEFT JOIN users AS T8
ON T2.user_id = T8.user_id
WHERE T0.timestamp >= '2014-02-17 00:00:00'
AND T0.qrs_metric_id = T1.qrs_metric_id
) tmp_table
GROUP BY `Response Session`
MSSQL Translation Attempt
SELECT [timestamp], [First Name], [Last Name], [Email Address], [Department], [Case], [Partner], [Category], [Tag Title], [Question], [Answer],
MAX(CASE [Secondary Metric Question] WHEN 'Support' THEN [Secondary Metric Question] end) AS 'Metric 1 Title',
MAX(CASE [Secondary Metric Question] WHEN 'Support' THEN [Answer] end) AS 'Metric 1 Answer',
MAX(CASE [Secondary Metric Question] WHEN 'Completeness' THEN [Secondary Metric Question] end) AS 'Metric 2 Title',
MAX(CASE [Secondary Metric Question] WHEN 'Completeness' THEN [Answer] end) AS 'Metric 2 Answer',
MAX(CASE [Secondary Metric Question] WHEN 'Policy' THEN [Secondary Metric Question] end) AS 'Metric 3 Title',
MAX(CASE [Secondary Metric Question] WHEN 'Policy' THEN [Answer] end) AS 'Metric 3 Answer',
[Message],
CASE [Reply Requested] WHEN 1 THEN 'YES' ELSE 'NO' END AS 'Reply Requested',
[Response Session]
FROM (
SELECT T0.[timestamp], T8.first_name AS 'First Name', T8.last_name AS 'Last Name', T8.email AS 'Email Address', T0.dept AS 'Department', T0.[case] AS 'Case', T0.partner AS 'Partner', T3.title AS 'Category', T2.title AS 'Question', T2.private_title AS 'Tag Title', T6.title AS 'Secondary Metric Question', T0.answer AS 'Answer', T4.[key] AS 'Message', T4.reply_requested AS 'Reply Requested', T0.response_session AS 'Response Session'
FROM AZUREMYSQL...responses AS T0
LEFT JOIN AZUREMYSQL...qrs_metrics AS T1
ON T0.qrs_metric_id = T1.qrs_metric_id
LEFT JOIN AZUREMYSQL...quick_responses AS T2
ON T1.qrs_id = T2.qrs_id
LEFT JOIN AZUREMYSQL...custom_categories AS T3
ON T2.category = T3.original_id AND T3.user_id = T2.user_id
LEFT JOIN AZUREMYSQL...rre_aggregates AS T4
ON T0.comment_id = T4.id
LEFT JOIN AZUREMYSQL...widget_responses AS T5
ON T0.widget = T5.id
LEFT JOIN AZUREMYSQL...secondary_metrics AS T6
ON T1.metric_id = T6.id
LEFT JOIN AZUREMYSQL...private_messages AS T7
ON T4.id = T7.comment_id AND T7.type = 3
LEFT JOIN AZUREMYSQL...users AS T8
ON T2.user_id = T8.user_id
WHERE T0.timestamp >= '2014-02-17 00:00:00'
AND T0.qrs_metric_id = T1.qrs_metric_id
) tmp_table
GROUP BY [Response Session]
The current error I am receiveing in SSMS is
Column 'tmp_table.timestamp' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
If anyone can help out I would really appreciate it.
Thanks
You need to have all columns that are not aggregates in the GROUP BY.
Edit: Cant use DISTINCT here, perhaps with an nested select but GROUP BY will do just fine.
<pre>
<?php
class DB_mssql
{
function modifyQuery($query)
{
$query = str_replace("`", "", $query);
$query = str_replace( array('[',']') , '' , $query );
$tablesName = $this->getTableName($query);
$tableNamesWithoutAlise = $this->removeAliseName($tablesName);
$tableNamesWithPrefix = $this->prefixDBName($tableNamesWithoutAlise);
// Group By Function Call
$query = $this->getGroupBy($query);
// Order By Function Call
$query = $this->getOrderBy($query);
//replace Limit keyword with TOP keyword
$query = $this->getLimit($query);
// MSSQLDateFormat function call
$query = $this->getMSSQLDateFormat($query);
/*force index => WITH index*/
preg_match_all("#\sforce[\s]*index[\s]*\(\w*\)[\s]*#i",$query,$forceIndex);
if(!empty($forceIndex['0']['0']))
{
$forceString = $forceIndex['0']['0'].')';
$forceString = str_ireplace('force index','WITH (index',$forceString);
}
// Changed use index to with index
preg_match_all("#\suse[\s]*index[\s]*\(\w*\)[\s]*#i",$query,$useIndex);
if(!empty($useIndex['0']['0']))
{
$useString = $useIndex['0']['0'].')';
$useString = str_ireplace('use index','WITH (index',$useString);
}
/*Interval 10 date*/
preg_match_all("#INTERVAL\s[0-9]*\sday#i",$query,$intervalIndex);
if(!empty($intervalIndex[0][0]))
{
$intervalString = explode(" ",$intervalIndex[0][0]);
$intervalString = $intervalString[1];
} else {
$intervalString = '';
}
// Patterns
$patterns[0] ='#(?<![\w])secure_pgatxn.(?![\w][.])#i';
$patterns[1] ='#(?<![\w])secure_pga.(?![\w][.])#i';
$patterns[2] ='#\sIFNULL#i';
$patterns[3] = '#[\s]{1,}WHERE[\s]{1,}1#i';// where 1 should be replaced with WHERE 1=1
$patterns[4] ='#\sforce index[\s]*\(\w*\)[\s]*#i';// Force Index is replaced with With Index
$patterns[5] ='#\suse\sindex[\s]*\(\w*\)[\s]*#i';// use Index is replaced with with index
$patterns[6] ='#[\s]*&&{1}[\s]*#i';
$patterns[7] = '#IF[\s]*\([\s]*#i';// IF should be replaced with where IIF
$patterns[8] = '#now\([\s]*#i';// Now() function should be replaced with getutcdate()
$patterns[10] = '#[\W]DATE[\s]*\([\s]*#i';// Mysql Date() is changed to CONVERT (date,GETDATE())
$patterns[11] = '#DATE_FORMAT[\s]*\([\s]*#i';// date_format() function should be replaced with format
$patterns[12] = '#[\s]*(%Y{1}-%m{1}-%d{1})#i';// Change '%Y-%m-%d' patteren to 'yyyy-MM-dd'
$patterns[13] = '#%m{1} %d{1}#i';// Change '%m %d' patteren to 'MM dd' \'
$patterns[14] = '#DATE_SUB\([\s]*#i';// DATE_SUB() function accepts 3 parameters// curdate
$patterns[15] = '#CURDATE\([\s]*#i';// DATE_SUB() function accepts 3 parameters// curdate
$patterns[16] ='#\,[\s]*INTERVAL\s[0-9]*\sDAY#i';// INTERVAL 1 DAY is replaced with ''
$patterns[17] ='#[\s]*DATE_ADD\([\s]*#i';// Mysql Date() is changed to CONVERT (date,GETDATE())
$patterns[18] ='#[\s]*\|\|[\s]*#i'; // || to OR
$patterns[19] ='#(?<![\w])secure_lib.(?![\w][.])#i';
$patterns[20] = '#UCASE\([\s]*#i';
// Replacement Queries
$replacements[0] = ' ';
$replacements[1] = ' ';
$replacements[2] = ' ISNULL';
$replacements[3] = ' WHERE 1=1 ';
$replacements[4] = isset($forceString)?$forceString:''.' ';
$replacements[5] = isset($useString)?$useString:''.' ';
$replacements[6] = ' AND ';
$replacements[7] = 'IIF(';
$replacements[8] = 'GETDATE(';
$replacements[10] = ' CONVERT(date,';
$replacements[11] = 'FORMAT(';
$replacements[12] = 'yyyy-MM-dd';
$replacements[13] = 'MM dd';
$replacements[14] = ' DATEADD(DAY,-'.$intervalString.',';
$replacements[15] = 'GETDATE(';
$replacements[16] = '';
$replacements[17] = ' DATEADD(DAY,'.$intervalString.',';
$replacements[18] = ' OR ';
$replacements[19] = ' ';
$replacements[20] = 'UPPER(';
$query = preg_replace($patterns, $replacements, $query);
$query = $this->strReplaceTableName($query, $tableNamesWithPrefix);
return $query;
}
// Function To Change Limit to Top
function getLimit($query)
{
preg_match_all("#LIMIT[^\w]{1,}([0-9]{1,})[\s]*([\,]{0,})[\s]*([0-9]{0,})#i",$query,$matches);
$patterns = '#LIMIT[^\w]{1,}([0-9]{1,})[\s]*([\,]{0,})[\s]*([0-9]{0,})#i';
$replacements = '';
$query = preg_replace($patterns, $replacements, $query);
if(!empty($matches[1][0]) && empty($matches[3][0]))
{
$query = str_ireplace("SELECT ", "SELECT TOP ".$matches[1][0]." ", $query);
}
else if(!empty($matches[3][0]))
{
$limitQuery = " OFFSET ".$matches[1][0]." ROWS FETCH NEXT ".$matches[3][0]." ROWS ONLY";
if(stripos($query, "ORDER BY"))
{
$query .= $limitQuery;
}
else
{
$selectList = $this->selectList($query,"SELECT","FROM");
$selectList = $this->sqlParser($selectList);
$selectList = preg_replace('#[\s]as[\s]\w*#i', " ", $selectList);
$query .= " ORDER BY ".$selectList[0].$limitQuery;
}
}
return $query;
}
// Function To Change DateFormat
function getMSSQLDateFormat($query)
{
if(stripos($query, "%b %d"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'%b{1}[\s]*%d{1}\'[\s]*\)#iU",$query,$dateFormat);
if(!empty($dateFormat))
{
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0],"convert(char(3), ".$columnName.", 0)+' '+CONVERT(char(2), ".$columnName.", 4)",$query);
}
return $query;
}
else if(strpos($query, "%Y-%M"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'%Y{1}[\s]*-%M{1}\'[\s]*\)#iU",$query,$dateFormat);
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0],"DATENAME(year,".$columnName.")+'-'+DATENAME(month,".$columnName.")",$query);
return $query;
}
else if(stripos($query, "%Y-%m"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'%Y{1}[\s]*-%m{1}\'[\s]*\)#iU",$query,$dateFormat);
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0],"CONVERT(VARCHAR(7), ".$columnName.", 120)",$query);
return $query;
}
else if(stripos($query, "%M %d, %Y") || stripos($query, "%M %d. %Y"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'%M{1} %d{1}[\,|\.][\s]*%Y{1}\'[\s]*\)#iU",$query,$dateFormat);
foreach($dateFormat[0] as $key => $value)
{
$columnName = explode(",",$dateFormat[0][$key]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][$key],"CONVERT(VARCHAR(12), ".$columnName.", 107)",$query);
}
return $query;
}
else if(stripos($query, "%d/%m/%Y %H:%i:%S"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'\%d/\%m/\%Y[\s]*\%H:\%i:\%S\'[\s]*\)#iU",$query,$dateFormat);
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0],"CONVERT(VARCHAR(10), ".$columnName.", 103)+' '+CONVERT(VARCHAR(18),".$columnName.",108)",$query);
return $query;
}
else if(stripos($query, "%d%m%Y"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w]*.*\)#i",$query,$dateFormat);
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0]," REPLACE(CONVERT(VARCHAR(10),".$columnName.",103), '/','')",$query);
return $query;
}
else if(stripos($query, "%d/%m/%Y"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'\%d{1}/\%m{1}/\%Y{1}\'[\s]*\)#iU",$query,$dateFormat);
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0],"CONVERT(VARCHAR(10), ".$columnName.", 103)",$query);
return $query;
}
else if(stripos($query, "%d %M,%Y"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'\%d{1}[\s]*\%M{1}[,]\%Y{1}\'[\s]*\)#iU",$query,$dateFormat);
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0],"CONVERT(VARCHAR(11), ".$columnName.", 106)",$query);
return $query;
}
else if(stripos($query, "%H:00"))
{
preg_match_all("#DATE_FORMAT[\s]*\([\s]*[\w].*[,]{1}[\s]*\'[\s]*\%H{1}:00[\s]*\'[\s]*\)#iU",$query,$dateFormat);
$columnName = explode(",",$dateFormat[0][0]);
$columnName = str_ireplace("date_format(","",$columnName[0]);
$query = str_ireplace($dateFormat[0][0],"RIGHT(100 + DATEPART(HOUR, ".$columnName."),2)+':00'",$query);
return $query;
}
else if(stripos($query, "datediff"))
{
preg_match_all("#datediff[\s]*\([\s]*[\w].*[,]{1}[\s]*[\w].*[\s]*\)#iU",$query,$dateDiff);
if (isset($dateDiff[0])) {
foreach($dateDiff[0] as $key => $value)
{
$columnName = explode(",",$dateDiff[0][$key]);
if (count($columnName) < 3) {
$Param1 = substr($columnName[1],0,-1);
$Param2 = str_ireplace("datediff("," ",$columnName[0]);
$query = str_ireplace($dateDiff[0][$key],"datediff(DAY,$Param1,$Param2)",$query);
}
}
}
return $query;
}
else
{
return $query;
}
}
// Function To Select List To Order BY Clause
function getOrderBy($query)
{
/*Order By functionality starts*/
preg_match_all("#order[\s]by[^\w]{1,}([0-9]{1,})([\,]{0,})([0-9]{0,})#i",$query,$orderByNum);
if(!empty($orderByNum[0]))
{
$selectList = $this->selectList($query,"SELECT","FROM");
$orderByList = $this->orderByList($query,"ORDER BY","DESC");
$selectList = $this->sqlParser($selectList);
$selectList = preg_replace('#[\s]as[\s]{1,}\w*#i', " ", $selectList);
$orderByArr = explode(",",$orderByList);
$orderByArr = array_map('trim',$orderByArr);
/**Code for gropup by 1*/
if(!empty($orderByNum[0]))
{
$orderByCol=array();
foreach($orderByArr as $colno)
{
$orderByCol[]=$selectList[$colno-1];
}
}
if(!empty($orderByNum[0]))
{
$orderBy = implode(",",$orderByCol);
}
if(stripos($query, "ORDER BY"))
{
$query = preg_replace('#order[\s]by[^\w]{1,}([0-9]{1,})([\,]{0,})([0-9]{0,})([\,]{0,})([0-9]{0,})([\,]{0,})([0-9]{0,})([\,]{0,})([0-9]{0,})([\,]{0,})([0-9]{0,})([\,]{0,})([0-9]{0,})([\,]{0,})([0-9]{0,})([\,]{0,})([0-9]{0,})#i', "ORDER BY $orderBy ", $query);
}
}
return $query;
/*Ends here*/
}
// Function To Select List To Group BY Clause
function getGroupBy($query)
{
preg_match_all("#group[\s]by\s#i",$query,$groupByWord);
preg_match_all("#group[\s]by[^\w]{1,}([0-9]{1,})([\,]{0,})([0-9]{0,})#i",$query,$groupByNum);
$groupBy = !empty($groupByWord[0])?$groupByWord[0]:$groupByNum[0];
if(!empty($groupBy))
{
$selectList = $this->selectList($query,"SELECT","FROM");
$groupByList = $this->groupByList($query);
$selectList = $this->sqlParser($selectList);
$selectList = preg_replace("#[\s]as[\s]{1,}\w*#i", " ", $selectList);
$selectList = $this->removeAggregateFunc($selectList);
$groupByArr = explode(",",$groupByList);
$groupByArr = array_map('trim',$groupByArr);
/**Code for gropup by 1*/
if(!empty($groupByNum[0]))
{
$groupByCol=array();
foreach($groupByArr as $colno)
{
$groupByCol[]=$selectList[$colno-1];
}
}
if(!empty($groupByNum[0]))
{
$combineVal = array_merge_recursive($groupByCol,$selectList);
$combineVal = array_map('trim',$combineVal);
$combineVal = array_unique($combineVal);
$groupBy = implode(",",$combineVal);
}
else
{
$combineVal = array_merge_recursive($groupByArr,$selectList);
$combineVal = array_map('trim',$combineVal);
$combineVal = array_unique($combineVal);
$groupBy = implode(",",$combineVal);
}
$trimmed_array=array_map('trim',$groupByArr);
if(stripos($query, "ORDER BY"))
{
$query = preg_replace('#GROUP BY[\s\S]+?ORDER BY#i', "GROUP BY $groupBy ORDER BY ", $query);
}
else
{
$query = preg_replace('#GROUP BY[\s]{1,}.*#i', "GROUP BY ".$groupBy, $query);
}
}
return $query;
}
// Function To Remove Aggregate Function From group by list
function removeAggregateFunc($selectList)
{
if(!empty($selectList))
{
foreach($selectList as $key => $val)
{
if(stripos($val, "sum(") !== false)
{
unset($selectList[$key]);
}
else if(stripos($val, "count(") !== false)
{
unset($selectList[$key]);
}
else if(stripos($val, "MAX(") !== false)
{
unset($selectList[$key]);
}
else if(stripos($val, "MIN(") !== false)
{
unset($selectList[$key]);
}
else if(stripos($val, "AVG(") !== false)
{
unset($selectList[$key]);
}
}
}
return $selectList;
}
function groupByList($string){
if(stripos($string, "ORDER BY"))
{
preg_match_all("#group\sby(?s)(.*)order\sby#i",$string,$groupByOrderby);
return $groupByOrderby[1][0];
}
else if(stripos($string, "limit"))
{
preg_match_all("#group\sby(?s)(.*)\slimit#i",$string,$groupByLimit);
return $groupByLimit[1][0];
}
else if(stripos($string, "having"))
{
preg_match_all("#group\sby(?s)(.*)\shaving#iU",$string,$groupByHaving);
return $groupByHaving[1][0];
}
else
{
preg_match_all("#group\sby(?s)(.*)#i",$string,$groupBy);
return $groupBy[1][0];
}
}
function orderByList($string, $start, $end){
$string = ' ' . $string;
$ini = stripos($string, $start);
if ($ini == 0) return '';
$ini += strlen($start);
if(stripos($string, "DESC") === false)
{
return substr($string, $ini);
}
else
{
$len = stripos($string, $end, $ini) - $ini;
return substr($string, $ini, $len);
}
}
// Function Used to select column list from Mysql Query
function selectList($string, $start, $end){
preg_match_all("#select(?s)(.*)[\W]from#iU",$string,$selectFrom);
return $selectFrom[1][0];
}
// Function Used to select column list from Mysql Query
function sqlParser($str)
{
$str = str_split($str);
$tokens = array();
$token = "";
$stack = array();
foreach($str as $char) {
if($char == "," && empty($stack)) {
$tokens[] = trim($token);
$token = "";
} else {
$token = $token .$char;
if($char == '(') {
array_unshift($stack, $char);
}
if($char == ')') {
array_shift($stack);
}
}
}
$tokens[] = trim($token);
return $tokens;
}
// Function Used to get TableName from Mysql Query
function getTableName($query)
{
$tables = array();
$query_structure = explode( ' ', strtolower( preg_replace('!\s+!', ' ', $query) ) );
$searches_from = array_keys( $query_structure , 'from');
$searches_join = array_keys( $query_structure , 'join');
$searches_update = array_keys( $query_structure , 'update');
$searches_into = array_keys( $query_structure , 'into');
$searches = array_merge($searches_join , $searches_from , $searches_update , $searches_into);
foreach($searches as $search ){
if(isset($query_structure[$search+1])){
$tables[] = trim( $query_structure[$search+1] , '` ');
}
}
$patterns[1] ='#(?<![\w])secure_pgatxn.(?![\w][.])#i';
$patterns[2] ='#(?<![\w])secure_pga.(?![\w][.])#i';
$patterns[3] ='#(?<![\w])secure_lib.(?![\w][.])#i';
$replacements[1] = '';
$replacements[2] = '';
$replacements[3] = '';
$tables = preg_replace($patterns, $replacements,$tables);
return $tables;
}
// Function Used to Prefix Database Name. In MSSQL, we have to prefix DB Name
function prefixDBName($tableList)
{
$tableArray = array(
"job_queue_notification_log"=>"secure_pga.dbo.job_queue_notification_log"
,"old_pga_customer_card"=>"secure_pga.dbo.old_pga_customer_card"
);
$tableNamesWithPrefix = array();
foreach($tableList as $tableName) {
$tableNamesWithPrefix[$tableName] = $tableArray[$tableName];
}
return $tableNamesWithPrefix;
}
function getSubStr($query, $fromStr, $toStr) {
$fromStrLen = strlen($fromStr);
$startingPos = stripos($query, $fromStr) + $fromStrLen;
$endingPos = stripos($query, $toStr);
if(empty($endingPos))
{
return substr($query, $startingPos);
}
else{
return substr($query, $startingPos, ($endingPos - $startingPos));
}
}
function removeAliseName($tablesName) {
$cleanTablesName = array();
foreach($tablesName as $tableName) {
$temp = explode(" ",$tableName);
$cleanTablesName[] = trim($temp[0],"[]");
}
return $cleanTablesName;
}
function strReplaceTableName($query, $tableNames){
foreach($tableNames as $tableNameBare => $tableNameWithPrefix) {
if(strlen($tableNameBare)>3){
$patterns[]='#\b'.$tableNameBare.'\b#iU';
$replacements[]=$tableNameWithPrefix.'';
}
}
$query = preg_replace($patterns, $replacements, $query);
return $query;
}
// }}}
}
// Object Initializations
$DB_mssql = new DB_mssql();
//Mysql Query
$mysqlQuery = "SELECT id,name FROM table_name WHERE id = 16474 ORDER BY id DESC LIMIT 1,100";
//MSSQL Converted Query
$MssqlQuery = $DB_mssql->modifyQuery($mysqlQuery);
?>
</pre>

mySQL: How do I do multiple subqueries and group by for use with datatables?

I want to generate the following data set for use with DataTables. For the filtering and sorting to work properly, using JOINS instead of subqueries is difficult, if not impossible (as far as I can tell).
Applicant Name, Position, Interviewer, Interview 1 Score, Interview 2 Score, Demo. Score, Interview Date
Here is how the data is stored in mySQL (simplified version):
applicant_scores table
id applicant_id interviewer_id score_type score datetime_recorded
1 2 3 Interview 1 80 2013-04-23 09:35:48
2 2 45 Interview 1 70 2013-04-23 10:14:23
3 2 3 Interview 2 85 2013-04-23 09:35:48
4 2 45 Interview 2 77 2013-04-23 10:14:23
5 2 3 Demonstration 76 2013-04-23 09:35:48
6 3 45 Interview 1 79 2013-04-23 10:14:23
7 3 3 Interview 1 86 2013-04-23 09:35:48
8 3 45 Interview 2 92 2013-04-23 10:14:23
applicants table
id first_name last_name
2 John Doe
3 Jane Doe
interviewer table
id first_name last_name
3 Santa Claus
45 Fred Flintstone
applicant_positions table
position_id applicant_id
1 2
1 3
positions table
id title
1 Advanced mySQL Programmer
I've tried everything that I can think of, but I'm having trouble grouping scores by interviewer and applicant correctly. What I expect to see is:
Applicant Name Position Interviewer Interview 1 Score Interview 2 Score Demo. Score Interview Date
John Doe Advanced mySQL Programmer Santa Claus 80 85 76 2013-04-23
John Doe Advanced mySQL Programmer Fred Flintstone 70 77 2013-04-23
Jane Doe Advanced mySQL Programmer Santa Claus 86 2013-04-23
Jane Doe Advanced mySQL Programmer Fred Flintstone 79 92 2013-04-23
Here is my current query which gives zero results:
SELECT SQL_CALC_FOUND_ROWS
CONCAT( a.first_name, ' ', a.last_name),
p.title,
CONCAT( i.first_name, ' ', i.last_name),
(SELECT score FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id AND s.score_type = 'Interview 1') as score_1,
(SELECT score FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id AND s.score_type = 'Interview 2') as score_2,
(SELECT score FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id AND s.score_type = 'Demonstration') as score_3,
(SELECT DATE_FORMAT(datetime_recorded, '%m-%d-%Y') FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id) as interview_date
FROM applicants a, positions p, interviewers i, applicant_scores s
WHERE s.applicant_id = a.id AND i.id = s.interviewer_id
GROUP BY i.id
Here is the server side ajax code that is being used to feed DataTables... Here is info on how to create server side script for DataTables - http://www.datatables.net/release-datatables/examples/data_sources/server_side.html
<?php
/* Database connection information */
$gaSql['user'] = "";
$gaSql['password'] = "";
$gaSql['db'] = "";
$gaSql['server'] = "";
$q1="'";
$q2='"';
$name = "CONCAT( ".$q2."<input type='hidden' id='name' value='".$q2.", LOWER(a.last_name), ' ', LOWER(a.first_name), ".$q2."'><input type='hidden' id='applicant_id' value='".$q2.", a.id, ".$q2."'><a href='applicant_details.php?id=".$q2.", a.id, ".$q2."'><img src='img/search.png' border='0'></a> ".$q2.", a.last_name, ', ', a.first_name )";
$interviewer = "CONCAT( ".$q2."<input type='hidden' id='name' value='".$q2.", LOWER(u.lastname), ' ', LOWER(u.firstname), ".$q2."'><input type='hidden' id='interviewer_id' value='".$q2.", i.id, ".$q2."'><a href='interviewer_details.php?id=".$q2.", i.id, ".$q2."'><img src='img/search.png' border='0'></a> ".$q2.", u.lastname, ', ', u.firstname )";
$int_1_score = "(SELECT score FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id AND s.score_type = 'Interview 1' AND s.interviewer_id = i.id) as score_1";
$int_2_score = "(SELECT score FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id AND s.score_type = 'Interview 2' AND s.interviewer_id = i.id) as score_2";
$demo_score = "(SELECT score FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id AND s.score_type = 'Demonstration' AND s.interviewer_id = i.id) as score_3";
$interview_date = "(SELECT DATE_FORMAT(datetime_recorded, '%m-%d-%Y') FROM applicant_scores s, applicants a WHERE s.applicant_id = a.id) as interview_date";
$aColumns = array($name, 'p.title', $interviewer, $int_1_score, $int_2_score, $demo_score, $interview_date);
/* Indexed column (used for fast and accurate table cardinality) */
$sIndexColumn = "id";
$sIndexTable = "formtemplates";
/* DB table to use */
$sTable = "applicants a, positions p, interviewers i, applicant_scores s, users u";
$sWhere = " WHERE s.applicant_id = a.id AND i.id = s.interviewer_id AND u.id = i.user_id";
$sGroupBy = " GROUP BY i.id";
/*
* MySQL connection
*/
$gaSql['link'] = mysql_pconnect( $gaSql['server'], $gaSql['user'], $gaSql['password'] ) or
die( 'Could not open connection to server' );
mysql_select_db( $gaSql['db'], $gaSql['link'] ) or
die( 'Could not select database '. $gaSql['db'] );
/*
* Paging
*/
$sLimit = "";
if ( isset( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' )
{
$sLimit = "LIMIT ".mysql_real_escape_string( $_GET['iDisplayStart'] ).", ".
mysql_real_escape_string( $_GET['iDisplayLength'] );
}
/*
* Ordering
*/
if ( isset( $_GET['iSortCol_0'] ) )
{
$sOrder = " ORDER BY ";
for ( $i=0 ; $i<intval( $_GET['iSortingCols'] ) ; $i++ )
{
if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" )
{
if(stripos($aColumns[ intval( $_GET['iSortCol_'.$i] ) ], "c.name", 1) >= 1){
$sOrder .= "c.name ".mysql_real_escape_string( $_GET['sSortDir_'.$i] ).", ";
}elseif(stripos($aColumns[ intval( $_GET['iSortCol_'.$i] ) ], "t.firstName", 1) >= 1){
$sOrder .= "t.firstName ".mysql_real_escape_string( $_GET['sSortDir_'.$i] ).", ";
}elseif(stripos($aColumns[ intval( $_GET['iSortCol_'.$i] ) ], "d.shortName", 1) >= 1){
$sOrder .= "d.shortName ".mysql_real_escape_string( $_GET['sSortDir_'.$i] ).", ";
}else{
$sOrder .= $aColumns[ intval( $_GET['iSortCol_'.$i] ) ]."
".mysql_real_escape_string( $_GET['sSortDir_'.$i] ) .", ";
}
}
}
$sOrder = substr_replace( $sOrder, "", -2 );
if ( $sOrder == "ORDER BY" )
{
$sOrder = "";
}
}
/*
* Filtering
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here, but concerned about efficiency
* on very large tables, and MySQL's regex functionality is very limited
*/
//define columns to filter on
$aFcolumns = array( 'u.username', 'u.firstname', 'u.lastname', "REPLACE (g.status, 'OUT_FOR_SIGNATURE', 'WAITING')");
if ( $_GET['sSearch'] != "" )
{
//$sWhere .= "WHERE (";
$sWhere .= " AND (";
for ( $i=0 ; $i<count($aFcolumns) ; $i++ )
{
$sWhere .= $aFcolumns[$i]." LIKE '%".mysql_real_escape_string( $_GET['sSearch'] )."%' OR ";
}
$sWhere = substr_replace( $sWhere, "", -3 );
$sWhere .= ')';
}
/* Individual column filtering */
for ( $i=0 ; $i<count($aFcolumns) ; $i++ )
{
if ( $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' )
{
if ( $sWhere == "" )
{
$sWhere = "WHERE ";
}
else
{
$sWhere .= " AND ";
}
$sWhere .= $aFcolumns[$i]." LIKE '%".mysql_real_escape_string($_GET['sSearch_'.$i])."%' ";
}
}
/*
* SQL queries
* Get data to display
*/
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM $sTable
$sWhere
$sGroupBy
$sOrder
$sLimit
";
//echo $sQuery; die(); //for firebug debugging
$rResult = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
/* Data set length after filtering */
$sQuery = "
SELECT FOUND_ROWS()
";
$rResultFilterTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultFilterTotal = mysql_fetch_array($rResultFilterTotal);
$iFilteredTotal = $aResultFilterTotal[0];
/* Total data set length */
$sQuery = "
SELECT COUNT(".$sIndexColumn.")
FROM $sIndexTable
";
$rResultTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultTotal = mysql_fetch_array($rResultTotal);
$iTotal = $aResultTotal[0];
/*
* Output
*/
$output = array(
"sEcho" => intval($_GET['sEcho']),
"iTotalRecords" => $iTotal,
"iTotalDisplayRecords" => $iFilteredTotal,
"aaData" => array()
);
while ( $aRow = mysql_fetch_array( $rResult ) )
{
$row = array();
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
if ( $aColumns[$i] != ' ' )
{
/* General output */
$row[] = $aRow[$i];
}
}
//add another row for buttons
//$row[] = "<div style='float:right;'><span style='padding-right:2px;'><a href=''><img src='global_img\user_info.png' border='0'></a></span><span style='padding-right:2px;'><a href=''><img src='global_img\user_edit.png' border='0'></a></span><span style='padding-right:0px;'><a href=''><img src='global_img\user_delete.png' border='0'></a></span></div>";
$output['aaData'][] = $row;
}
echo json_encode( $output );
?>
I modified the server side script to attempt to use the solution provided by bluefeet and the following is the generated query:
SELECT SQL_CALC_FOUND_ROWS concat(a.first_name, ' ', a.last_name), p.title, CONCAT(i1.first_name, ' ', i1.last_name), max(case when ac.score_type='Interview 1' then ac.score else '' end), max(case when ac.score_type='Interview 2' then ac.score else '' end), max(case when ac.score_type='Demonstration' then ac.score else '' end), DATE_FORMAT(ac.datetime_recorded, '%m-%d-%Y')
FROM applicants a
inner join applicant_positions ap on a.id = ap.applicant_id inner join positions p on ap.position_id = p.id inner join applicant_scores ac on a.id = ac.applicant_id inner join interviewers i1 on ac.interviewer_id = i1.id
GROUP BY concat(a.first_name, ' ', a.last_name), p.title, CONCAT(i1.first_name, ' ', i1.last_name), DATE_FORMAT(ac.datetime_recorded, '%m-%d-%Y')
ORDER BY concat(a.first_name, ' ', a.last_name)
asc
LIMIT 0, 500
This gives me an empty result set though. HELP?
You were definitely on the right track to get the result.
You are currently missing a few joins in your query. You need to join the applicants to the positions using the applicant_positions table. You can also add a join to the applicant_scores table which will let you use an aggregate function with a CASE to get the columns containing the Interview/Demo Scores:
select
concat(a.first_name, ' ', a.last_name) ApplicantName,
p.title Position,
CONCAT(i1.first_name, ' ', i1.last_name) Interviewer,
max(case when ac.score_type='Interview 1' then ac.score else '' end) Interview1Score,
max(case when ac.score_type='Interview 2' then ac.score else '' end) Interview2Score,
max(case when ac.score_type='Demonstration' then ac.score else '' end) DemoScore,
DATE_FORMAT(ac.datetime_recorded, '%m-%d-%Y') InterviewDate
from applicants a
inner join applicant_positions ap
on a.id = ap.applicant_id
inner join positions p
on ap.position_id = p.id
inner join applicant_scores ac
on a.id = ac.applicant_id
inner join interviewers i1
on ac.interviewer_id = i1.id
group by concat(a.first_name, ' ', a.last_name),
p.title,
CONCAT(i1.first_name, ' ', i1.last_name),
DATE_FORMAT(ac.datetime_recorded, '%m-%d-%Y');
See SQL Fiddle with Demo. This give the result:
| APPLICANTNAME | POSITION | INTERVIEWER | INTERVIEW1SCORE | INTERVIEW2SCORE | DEMOSCORE | INTERVIEWDATE |
-------------------------------------------------------------------------------------------------------------------------------
| Jane Doe | Advanced mySQL Programmer | Fred Flintstone | 79 | 92 | | 04-23-2013 |
| Jane Doe | Advanced mySQL Programmer | Santa Claus | 86 | | | 04-23-2013 |
| John Doe | Advanced mySQL Programmer | Fred Flintstone | 70 | 77 | | 04-23-2013 |
| John Doe | Advanced mySQL Programmer | Santa Claus | 80 | 85 | 76 | 04-23-2013 |
SELECT CONCAT(b.first_name, ' ', b.last_Name) Applicant_Name,
CONCAT(c.first_name, ' ', c.last_Name) Interviewer_Name,
e.Title,
MAX(CASE WHEN a.score_type = 'Interview 1' THEN a.score END) `Interview 1 Score`,
MAX(CASE WHEN a.score_type = 'Interview 2' THEN a.score END) `Interview 2 Score`,
MAX(CASE WHEN a.score_type = 'Demonstration' THEN a.score END) `Demonstration Score`,
MAX(DATE(a.datetime_recorded)) `Interview Date`
FROM applicant_scores a
INNER JOIN applicants b
ON a.applicant_ID = b.ID
INNER JOIN interviewer c
ON a.interviewer_ID = c.id
INNER JOIN applicant_positions d
ON a.applicant_ID = d.applicant_ID
INNER JOIN positions e
ON d.position_ID = e.ID
GROUP BY CONCAT(b.first_name, ' ', b.last_Name),
CONCAT(c.first_name, ' ', c.last_Name),
e.Title
SQLFiddle Demo