Change data in Google sheet for better understanding based on a column value
From this:
entity_id | data_key | data_value
1 | name | some name
1 | author | john
1 | likes | 12
2 | name | another name
2 | author | sam
3 | name | different name
3 | author | mary
3 | likes | 3
To this:
entity_id | name | author | likes
1 | some name | john | 12
2 | another name | sam |
3 | different name| mary | 3
I checked features like transpose, it falls short of what I actually need.
Run the function in the below snippet as a custom function:
const data = [
['entity_id', 'data_key', 'data_value'],
[1, 'name', 'some name'],
[1, 'author', 'john'],
[1, 'likes', 12],
[2, 'name', 'another name'],
[2, 'author', 'sam'],
[3, 'name', 'different name'],
[3, 'author', 'mary'],
[3, 'likes', 3],
];
/**
*#customfunction
*/
const myTranspose = range => {
range.shift();
const headers = [];
const undefToStr = value => (undefined === value ? '' : value);
const obj = range.reduce((acc, row) => {
if (!acc[row[0]]) acc[row[0]] = {};
acc[row[0]][row[1]] = row[2];
if (-1 === headers.indexOf(row[1])) headers.push(row[1]);
return acc;
}, {});
return Object.entries(obj).reduce(
(acc, entry) => {
const row = [entry[0]];
headers.forEach(header => row.push(undefToStr(entry[1][header])));
acc.push(row);
return acc;
},
[['entity_id', ...headers]]
);
};
console.log(myTranspose(data));
The result of the function in Google Sheets:
The function first builds and then transposes it into a new 2D array.
Assuming that data is located columns A to C
={A1,transpose(unique(B2:B));arrayformula(ROW(A2:A)-1),arrayformula(iferror(vlookup((row(A2:A)-1)&"|"&transpose(unique(B2:B)),{arrayformula(A2:A&"|"&B2:B),arrayformula(C2:C)},2,0)))}
https://docs.google.com/spreadsheets/d/12LOBTcialZ8wef9enII-hFsjrRnuOhx35_EXtg4Zreo/copy
Try
=newTab(A1,A2:C9)
with custom function
function newTab(title,data){
var headers=[]
var items = new Map()
var n = 0
data.forEach(function(elem){
items.set(elem[1],'')
n= Math.max(n,elem[0])
})
items.forEach(function(value, key) {headers.push(key)})
var result = Array.from({ length: n + 1 }, () => Array.from({ length: headers.length + 1 }, () => ''));
result[0] = [title, ...headers]
data.forEach(function(elem){
result[elem[0]][headers.indexOf(elem[1])+1]=elem[2]
result[elem[0]][0]=elem[0]
})
return(result)
}
https://docs.google.com/spreadsheets/d/12LOBTcialZ8wef9enII-hFsjrRnuOhx35_EXtg4Zreo/copy
Related
I would like to update the given date [reset day] on weekly periods.
During this update if weekly attendance will also reset to 0 and if its value is less than 2 Attendance points will decrease by 8 points.
Example Initial Sheet
Name | Attendance Point | Weekly Attendance | Reset Day
--------------------------------------------------------------
Jack | 12 | 0 | 13/09/2018
Jacob | 23 | 0 |
Emily | 12 | 1 |
Rick | 11 | 2 |
Rob | 21 | 3 |
Desired Update
Name | Attendance Point | Weekly Attendance | Reset Day
--------------------------------------------------------------
Jack | 4 | 0 | 20/09/2018
Jacob | 15 | 0 |
Emily | 4 | 0 |
Rick | 11 | 0 |
Rob | 21 | 0 |
Sample base sheet
https://docs.google.com/spreadsheets/d/1khPC5r2p0b1srsEGka3fl-GAl6nHACaVR0Cf31cqA1o/edit?usp=sharing
Thanks in advance
function resetCells() {
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet');
var range = ss.getDataRange().offset(1, 0, ss.getLastRow() - 1);
var values = range.getValues().map(function(e) {
return e[0] ? [false, e[1], e[2], e[3], e[4] + 1, e[5]] : e;
});
range.setValues(values);
}
Update Function
function weekDays() {
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet').getRange('F2').setValue(new Date())
}
I solved the problem with this snippet of script
function weekDays() {
var sd = SpreadsheetApp.getActive().getSheetByName('Sheet').getRange('F2').setValue(new Date())
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet');
var range = ss.getDataRange().offset(1, 0, ss.getLastRow() - 1);
var values = range.getValues().map(function(e) {
if (Number(e[4]) < 2 && Number(e[2] >= 8) ) {
return e[1] ? [e[0], e[1], Number(e[2]) - 8, e[3], 0, e[5]] : e;
} else if (Number(e[4]) < 2 && Number(e[2]) < 8) {
return e[1] ? [e[0], e[1], 0, e[3], 0, e[5]] : e;
} else {
return e[1] ? [e[0], e[1], e[2], e[3], 0, e[5]] : e;
}
});
range.setValues(values);
}
I have 2 sheets in the same spreadsheet, call them sheet1 and sheet2. In each sheet, every row describes some hardware component and its properties. The point of sheet2 is to eventually replace the outdated sheet1.
Simple example, (real sheets are hundreds of lines long):
sheet1:
componentId | prop1 | prop2 | prop3 | isvalid
---------------------------------------------
1 | x1 | y1 | z1 | yes
2 | x1 | y2 | z3 | yes
3 | x2 | y1 | z1 | yes
sheet2:
componentId | quantity | prop1 | prop2 | prop3 | prop4 | isvalid
----------------------------------------------------------------
15 | 4 | x1 | y1 | z1 | w1 | TBD
23 | 25 | x3 | y3 | z2 | w1 | TBD
33 | 3 | x1 | y2 | z3 | w2 | TBD
The final column "isValid" in sheet1 has been manually populated. What I would like to do is write a script that iterates through sheet1, producing a tuple of the property values, and then looks for matching property value tuples in sheet2. If there is a match, I would like to copy the "isValid" field from sheet1 to the "isValid" field in sheet2.
What I have so far is the following, but I am experiencing a error "The coordinates or dimensions of the range are invalid" - see comment in code below showing where error is. And, the entire thing feels really hacky. Was hoping someone could maybe point me in a better direction? Thanks in advance.
function arraysEqual(a, b) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
function copySheetBasedOnRowTuples(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName('sheet 1 name');
var sheet2 = ss.getSheetByName('sheet 2 name');
s2data = sheet2.getDataRange().getValues()
s1data = sheet1.getDataRange().getValues()
for( i in s1data ){
sheet1Tuple = [ s1data[i][1], s1data[i][2], s1data[i][3] ]
// Now go through sheet2 looking for this tuple,
// and if we find it, copy the data in sheet1 column 4
// to sheet2 column 6 for the rows that matched (i and j)
for ( j in s2data){
sheet2Tuple = [ s2data[j][2], s2data[j][3], s2data[j][4] ]
if ( arraysEqual(sheet1Tuple, sheet2Tuple) ){
// ERROR HAPPENS HERE
sheet2.getRange(j, 6).setValue( sheet1.getRange( i, 4 ).getValue() )
}
}
}
}
The reason of error is the start number between array and range. The index of array starts from 0. The row and column of getRange() start from 1. So how about this modification?
From :
sheet2.getRange(j, 6).setValue( sheet1.getRange( i, 4 ).getValue() )
To :
sheet2.getRange(j+1, 7).setValue( sheet1.getRange( i+1, 5 ).getValue() )
If this was not useful for you, please tell me. I would like to modify.
Suppose I have table A and B.
Table A contain column id, name
id | name
----|-----------
1 | X
2 | Y
3 | Z
Table B contain column id, tax_type, rate
id | tax_type | rate
----|-----------|--------
1 | services|12
2 | vat |3
3 | others |4
I have created grid view using table B, so the column of grid view are id and name.
But I want column dynamically in grid view by fetching table B values.
Like:
id | name |services | vat | others
----|-------|-----------|-------|--------
1 | X | 12 | 3 | 4
2 | Y | 12 | 3 | 4
3 | Z | 12 | 3 | 4
If the row change in table B then columns are also change in grid view.
Your Gridview columns can have any value. Do the following in your view:
First, get your data from table B:
$taxInfo = TableB::find()->indexBy('tax_type')->all();
Then, in your view in column definitions just add this:
'columns' => [
'id',
'name',
//...
[
'label' => 'Services',
'value' => function ($model) use $taxInfo {
$taxInfoObject = $taxInfo['services'];
return $taxInfoObject->rate;
}
],
[
'label' => 'VAT',
'value' => function ($model) use $taxInfo {
$taxInfoObject = $taxInfo['vat'];
return $taxInfoObject->rate;
}
],
[
'label' => 'Others',
'value' => function ($model) use $taxInfo {
$taxInfoObject = $taxInfo['others'];
return $taxInfoObject->rate;
}
],
]
Note how the $taxInfo variable we defined above is passed to our anonymous functions. (Generally those functions work with $model which, in your case, would contain a specific row of table A).
I'm trying to convert an Excel macro to Google Apps Script. I would like to create a new row on a specific sheet for each not empty column in Google Spreadsheets.
My Inputsheet looks like the following:
ID | Inrellevant Column | Givenmoney | Takenmoney | Othermoney
1 | Data1 | 100 | 200 | 300
2 | Data2 | 400 | | 500
I want to create a new row in another sheet for each not empty cell, so the desired Outputsheet would be:
ID | Inrellevant Column | Moneycode | Amount
1 | Data1 | Givenmoney | 100
1 | Data1 | Takenmoney | 200
1 | Data1 | Othermoney | 300
2 | Data2 | Givenmoney | 400
2 | Data2 | Othermoney | 500
I tried the following:
Outputsheet.getRange('A2').offset(0, 0, Inputsheet.length).setValues(Inputsheet);
However I can't see to create a loop to create new rows for each not empty column.
Hoi Fred, assuming you want the output to appear from the top left cell onwards in the sheet 'Outputsheet', try this code:
function myFunction() {
var ss = SpreadsheetApp.getActive(),
source = ss.getSheetByName('Inputsheet'),
target = ss.getSheetByName('Outputsheet'),
arr = [
["ID", "Header 2nd col", "Moneycode", "Amount"]
],
data = source.getDataRange().getValues(),
headers = data[0];
data.splice(1)
.forEach(function (r) {
r.forEach(function (c, i) {
if (!isNaN(parseFloat(c)) && isFinite(c) && i > 1) {
arr.push([r[0], r[1], headers[i], c])
}
})
})
target.getRange(1, 1, arr.length, arr[0].length).setValues(arr);
}
See this example sheet where you can run the above script from the menu 'My Menu'....
I have a table student attendance.
Fields/data sample
id | studid | cls_id | smonth | syear | total_p | total_a
1 | 20 | 2 | 08 | 2015 | 2 | 1
2 | 21 | 2 | 08 | 2015 | 1 | 0
3 | 22 | 2 | 08 | 2015 | 2 | 1
I want, to check what is the total_p and total_a value of each students in last update and then increment 1.
If I am enter the both students are present = 1 so I want total_p value 20=3, 21=2, 22=3
How to get database field values and increment 1's.?
My controller
$present = Input::get($student->id);
if ($checkatt)
{
if ($present == 1)
{
DB::table($wys_total_attend_table)->where('studid', $student->id)
->where('smonth', $date_exploded[1])
->where('syear', $date_exploded[2])
->where('stotal_p', 1)
->update(array(
'stotal_p' => 1 + 1,
));
DB::table($wys_total_attend_table)->where('studid', $student->id)
->where('smonth', $date_exploded[1])
->where('syear', $date_exploded[2])
->where('stotal_p', 0)
->update(array(
'stotal_p' => 1,
'stotal_a' => 0,
));
} elseif ($present == 0)
{
DB::table($wys_total_attend_table)->where('studid', $student->id)
->where('smonth', $date_exploded[1])
->where('syear', $date_exploded[2])
->where('stotal_a', 1)
->update(array(
'stotal_a' => 1 + 1,
));
DB::table($wys_total_attend_table)->where('studid', $student->id)
->where('smonth', $date_exploded[1])
->where('syear', $date_exploded[2])
->where('stotal_a', 0)
->update(array(
'stotal_a' => 1,
));
DB::table($wys_total_attend_table)->where('studid', $student->id)
->where('smonth', $date_exploded[1])
->where('syear', $date_exploded[2])
->where('stotal_p', 1)
->where('stotal_a', 0)
->update(array(
'stotal_a' => 0 + 1,
));
}
}
I think u just want to update each record of total_p and total_a column just make it simple:
//get the id of student
$student_id = Input::get('student_id');
$present = Input::get('status'); //dropdown value 0,1
//You need a model for your table let say:
#Student.php
<?php
class Student extends Eloquent{
protected $table = 'students'; //table name
}
//Your Controller codes
public function findStudent($id, $status){
$query=Student::find($id);
if($query->count() && $status==1 ){ //status 1 = present
$query->total_p += 1; //plus one value in the total_p column in the tbl.
$query->save();
}else{
$query->total_a +=1;
$query->save();
}
}