A more elgant way to roll up multiple rows? - codeigniter

I'm new to codeigniter (although I suppose this isn't an exclusively CI question) and have a method in a model which selects data from two tables joined by id.
table 1 (tblclients) looks like this:
+----+------------+
+ id + c_name +
+----+------------+
+ 1 + Joe Bloggs +
+ 2 + Jim Bloggs +
+ 3 + Tim Bloggs +
+----+------------+
table 2 (tblstars) looks like this:
+----+------------+
+ id + s_date +
+----+------------+
+ 1 + 27/01/12 +
+ 1 + 15/02/12 +
+ 1 + 18/02/12 +
+ 2 + 03/01/12 +
+ 2 + 11/02/12 +
+ 2 + 15/02/12 +
+ 3 + 01/01/12 +
+ 3 + 19/02/12 +
+----+------------+
I want to 'roll up' the joined data into one line for each row in tblclients so I can output, for example:
+----+------------+--------------------------------+
+ id + Name + Dates +
+----+------------+--------------------------------+
+ 1 + Joe Bloggs + 27/01/12 15/02/12 18/02/12 +
+ 2 + Jim Bloggs + 03/01/12 11/02/12 15/02/12 +
+ 3 + Tim Bloggs + 01/01/12 19/02/12 +
+----+------------+--------------------------------+
Now I've 'solved' the problem by using the following in my model:
function get_clients_concat()
{
$query = $this->db
->select('tblclients.id, tblclients.c_name, GROUP_CONCAT(tblstars.s_date SEPARATOR "#") AS star_dates', NULL, FALSE)
->join('tblstars', 'tblstars.id = tblclients.id', 'left')
->order_by('tblclients.id')
->group_by('tblclients.id')
->get('tblclients');
return $query->result();
}
and then exploding the array (created by the GROUP_CONCAT) in my view and doing some processing with it there ... but it seems really CLUNKY.
Is there a better solution?

If you want to get all that data in a single query (with each row's id unique), then yes--that's the way to go.
If you need to sort or filter the results, you'll run into performance bottlenecks when the tables fill up.
It seems odd though--why wouldn't you select from tblstars (joining tblclients) instead, then use application logic to index the dates by c_name/id?
<?php
// Select data from tables
$data = $this->db
->select('tblclients.id, tblclients.c_name, tblstars.s_date')
->join('tblclients', 'tblclients.id = tblstars.id')
->order_by('tblstars.id')
->get('tblstars');
// Index data by client id
// (keeping record of client name and dates array for each)
$clients = array();
foreach ($data->result() as $result)
{
if (empty($clients[$result->id]))
{
$clients[$result->id] = array(
'name' => $result->c_name,
'dates' => array($result->s_date)
);
}
else
{
$clients[$result->id]['dates'][] = $result->s_date;
}
}
return $clients;

Related

HOW TO CHANGE DATATABLE ROW GROUP COLOR

I want to change the colour of the grouped row in a datatable. I just can't seem to get it to work the way I would like and I'm unsure how to get it too. I have done a drawback and get this to work in the group header but for the life of me I can't get it to work in the grouped row footer.
rowGroup: {
/// Group Header Colour
//startRender: null, SET TO NULL IF GROUP HEADER NOT REQUIRED
startRender: function(rows, group) {
// colour the group header and uncomment to show
// return $('<tr class="group group-start"><td class="' + (group == '1' ? 'green' : (group == '0' ? 'green' : 'green')) + '" colspan="9">' + group + ' ' + ' ('+rows.count() + '</td></tr>');
},
// Below used for Grouping and summing at end of each dept in this case
endRender: function ( rows, group ) {
var filteredData = $('#giftcards').DataTable()
.rows()
.data()
.filter( function ( data, index ) {
return data[groupColumn] == group ? true : false;
} )
.pluck(6) // the column we are counting in this case retail value per dept
.sum();
//return 'Dept: <tr class="rowgroup"><td colspan="9">' + group + '('+ rows.count() + ' rows on page , £' + roundTo(filteredData,2) + 'Retail Sale value for all pages)'; /// Needs multiplied by PD.TotalShelfstockQuantity
return 'Dept: <tr class="group group-start"><td class="' + (group == '1' ? 'green' : (group == '0' ? 'green' : 'green')) + '" colspan="11">' + group + ' ' + '('+ rows.count() +')'
+ ' rows on page , <larger>£ </larger>' + roundTo(filteredData,2) + ' Retail Sale value for all pages)' + '</td></tr>'; /// Needs multiplied by PD.TotalShelfstockQuantity
// $(row).css("background-color", "green");
},
dataSrc: groupColumn,
//backgroundColor = styleEqual('Dept','red')
},`
```
THE BELOW PIECE OF CODE SEEMS TO BE ALMOST THERE - HOWEVER, IT IS ONLY SHOWING IN A FEW COLUMNS - I am not a programmer by the way.
```
return 'Dept: <tr class="group group-start"><td class="' + (group == '1' ? 'green' : (group == '0' ? 'green' : 'green')) + '" colspan="11">' + group + ' ' + '('+ rows.count() +')'
+ ' rows on page , <larger>£ </larger>' + roundTo(filteredData,2) + ' Retail Sale value for all pages)' + '</td></tr>';
```
Thanks in advance. Below is the status as is at minute. I would like the green to populate the entire row.
[![enter image description here](https://i.stack.imgur.com/P46Rz.png)](https://i.stack.imgur.com/P46Rz.png)
I have tried various solutions that were on this forum but I am missing something. I know that' I'm close but no cigar.

Alias Column In Resultset

I have a query in backend spring project, where I create a field alias named agent_id but I don´t have that column in Model. What is the best approach for showing this as a field in table view in front end???.
Here´s the query:
Query query = em.createNativeQuery("SELECT" +
" ips.*, " +
" s.mls_id AS imported," +
" p.INTEGRATOR_SALES_ASSOCIATED_ID AS agent_id " +
"FROM test1.ilist_property_summary ips " +
" LEFT JOIN test1.statistics s ON s.mls_id = ips.INTEGRATOR_PROPERTY_ID " +
" LEFT JOIN test1.person p ON p.INTEGRATOR_SALES_ASSOCIATED_ID = ips.INTEGRATOR_SALES_ASSOCIATED_ID " +
"WHERE ips.AGENCY_ID = :agencyId AND (s.statistics_type = 1 OR s.statistics_type IS NULL) AND ips.ORIG_LISTING_DATE BETWEEN :startDate AND :endDate");
query.setParameter("agencyId", agencyId)
.setParameter("startDate", DateUtil.asDate(startDate), TemporalType.DATE)
.setParameter("endDate", DateUtil.asDate(endDate), TemporalType.DATE);
return (List<PropertyVO>) query.getResultList().stream().map(o -> processProperty((Object[]) o)).collect(Collectors.<PropertyVO>toList());
I already have a field that shows agent_id, but not fetched with same field of table Person. I need to retrieve that field agent id alias fetched from left join.
I followed another approach:
Query query = em.createNativeQuery("SELECT" +
" ips.id, ips.agency_id, ips.integrator_property_id, ips.orig_listing_date, ips.contract_type," +
" ips.transaction_type, ips.current_listing_price, ips.current_listing_currency, ips.apartment_number, ips.commercial_residential," +
" ips.commission_percent, ips.commission_value, ips.property_type, ips.street_name, ips.street_number," +
" s.mls_id AS imported," +
" p.INTEGRATOR_SALES_ASSOCIATED_ID AS INTEGRATOR_SALES_ASSOCIATED_ID" +
" FROM test1.ilist_property_summary ips " +
" LEFT JOIN test1.statistics s ON s.mls_id = ips.INTEGRATOR_PROPERTY_ID " +
" LEFT JOIN test1.person p ON p.INTEGRATOR_SALES_ASSOCIATED_ID = ips.INTEGRATOR_SALES_ASSOCIATED_ID " +
"WHERE ips.AGENCY_ID = :agencyId AND (s.statistics_type = 1 OR s.statistics_type IS NULL) AND ips.ORIG_LISTING_DATE BETWEEN :startDate AND :endDate ");
Here field
INTEGRATOR_SALES_ASSOCIATED_ID
is taken from table p, and not from ips. I just selected specific fields so this one could be taken from the other table.

Why query just returns first 100 users?

I want get 40 users where "score" less or equal to some value, and 40 users where "score" greater or equal to the same value. But both queries return just first 100 users which sorted by score in descending order.
Here is some part of code
var query = ParseUser.Query;
if(mode==0)
{
query.WhereNotEqualTo("fbLogged", true)
.WhereNotEqualTo("username", SaveManager.Instance.TempUsername)
.WhereGreaterThanOrEqualTo("score", SaveManager.Instance.Score)
.Limit(40);
}
query.FindAsync().ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted)
{
foreach (var e in t.Exception.InnerExceptions)
Debug.LogError("Error: " + e.Message);
return;
}
else
{
var query1 = ParseUser.Query;
if(mode==0)
{
query1.WhereNotEqualTo("fbLogged", true)
.WhereNotEqualTo("username", SaveManager.Instance.TempUsername)
.WhereLessThanOrEqualTo("score", SaveManager.Instance.Score)
.Limit(40);
}
query1.FindAsync().ContinueWith(t1=>
{
Debug.Log("first query count: " + t.Result.ToList().Count);
Debug.Log("second query count: " + t1.Result.ToList().Count);
var r = t.Result.ToList();
r.AddRange(t1.Result.ToList());
List<UserRank> ranks = new List<UserRank>();
r.ForEach(info => { ranks.Add(RetrieveUserRankData((ParseUser)info)); });
ranks = ranks.OrderByDescending(ur => ur.Score).ToList();
UserRank first = ranks.First();
UserRank last = ranks.Last();
Debug.Log("my score: " + SaveManager.Instance.Score);
Debug.Log("first name and score: " + first.Name + " " + first.Score);
Debug.Log("last name and score: " + last.Name + " " + last.Score);
Also here is the log
What did I do wrong?
By default, a query default limit is 100 rows. And the maximum number of rows is 1000. To increase the limit, use query.setLimit(1000) to increase the number of queried row to 1000.

Laravel Query Builder on (column1 + column2 + ..)

I've some problem to translate this raw query to Laravel Query Builder:
SELECT
(x.ans_277 + x.ans_278 + x.ans_279 + x.ans_280) as jml, `a`.*
FROM
`rawdata` AS `a`
LEFT JOIN `answer` AS `x` ON `x`.`mhs` = `a`.`id`
WHERE
`jalur` = 1
AND `is_lest` = 'Y'
AND `x`.`ans_173` NOT IN (8,10)
AND `x`.`ans_182` NOT IN (17,11)
AND (x.ans_277 + x.ans_278 + x.ans_279 + x.ans_280) < 1000001
ORDER BY
`final_time` ASC
i've been trying use this:
$query->where('(x.ans_277 + x.ans_278 + x.ans_279 + x.ans_280)','<',1000001);
but it's not working.
You can use whereRaw():
$query->whereRaw('(x.ans_277 + x.ans_278 + x.ans_279 + x.ans_280) < 1000001');

Conditionally modifying multiple strings with For

So I have 13 binary values, which I call b_1... b_13, and based off these values I'd like to either set something I call indic_j to a previously defined string called inf_j, or nothing at all. Is it possible to do this without using 13 "If..." statements? What I have tried is below:
inf_1 = "aaaaa"
inf_2 = "bbbbb"
... and so on defining 13 infs, where aaaaa, bbbbb etc are names of columns in a table that I want to select.
FOR j = 1 to 13
IF b_j = 1 THEN "indic_"+j = inf_j + ",";
ELSE "indic_"+j = ""
ENDIF
ENDFOR
Also, before this I haven't introduced anything called indic_1, indic_2, etc. Is this needed?
My end goal is to transfer selected columns over to Excel. I've no problems doing this with predetermined columns, but I'm not sure how to allow for selected columns only.
I've tried using 13 IF statements, but I'm getting operator/operand type mismatch errors. My code currently is
IIF(b_1 = 1, indic_1 = inf_1 + ",",indic_1 = "")
IIF(b_2 = 1, indic_1 = inf_2 + ",",indic_1 = "")
IIF(b_3 = 1, indic_1 = inf_3 + ",",indic_1 = "")
and so on for 13 times, and then
SELECTIONRANG = indic_1 + indic_2 + indic_3 + indic_4 + indic_5 + indic_6 +indic_7 + indic_8 + indic_9 + indic_10 + indic_11 + indic_12 + indic_13
SELECTIONRANGE = LEFT(SELECTIONRANG,LEN(Selectionrang)-1)
You could create te variable name as a string and use it with &
As:
ind = 13
Var = "inf_" + ind
&Var ** inf_13

Resources