Add where clause if not NULL - linq-to-sql

here is my query:
List<string> kwList = GetFilterKeywords(); // returns NULL none keyword selected
var res = from d in ctx.Books
where (kwList == null || kwList.Contains(d.Name))
select d;
Looks like it is not legit to add where clause if kwList is NULL. So my question is: Is there any way to add more where clauses to the same query in IF/ELSE IF construction?
I mean:
var res = from d in ctx.Books
select d;
if (kwList != null)
{
res.Where(d => kwList.Contains(d.Name);
}

var res = ctx.Books; // no need to write select
if (kwList != null)
res = res.Where(x => kwList.Contains(x.Name));
foreach (d in res) {
...
}

You can use the tertiary operator
var res = kwList == null ? ctx.Books : ctx.Books.Where(x => kwList.Contains(x.Name));
If you want to modify the initial linq query in subsequent case statements, make sure to reassign the initial query to the modified:
var res = ctx.Books;
if (a == b)
{
// reassign here
res = res.Where(x => kwList.Contains(x.Name));
}
else if (a == c)
res = res.Where(x => x.Id == y);

Related

Log Missing Column in Destination Spreadsheet

I have the code below which allows me to update the existing spreadsheet (much like an matrix lookup). And what I am doing right now is to include a error log which will be updated in another sheet, this includes Missing data in Column A in Destination Spreadsheet and Missing Column in Destination Spreadsheet. I have worked with Missing data in Column A, my problem was the Missing Column, cause instead of the column name (found in the row 1) the result shows the column index:
code:
function updateShadowSKU() {
var source = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var dest = SpreadsheetApp.openById('179PCrIWe1mvbbzOi9ySEHxzBlFaXpCB2i0wHlYVE2vg').getSheetByName('Sheet1');
var destRange = dest.getDataRange();
var destValues = destRange.getValues();
var destHeaders = destValues[0];
var destIds = destValues.map(e => e[0]);
var values = source.getDataRange().getValues().map(e => e.filter((f, i) => !i || i > 10));
var colMap = values[0].map(e => destHeaders.indexOf(e));
Logger.log(colMap);
values = values.map((e, i, arr) => e.map((f, j) => [e[0], colMap[j], f, values[0][j], i, j])).flat().filter(e => e[0] && e[1] && e[2] && e[3] && e[4] && e[5]);
Logger.log(values);
// Initialize an array to store log entries
var logEntries = [];
// Check for missing SKUs
values.forEach(function(e) {
if (!destIds.includes(e[0])) {
logEntries.push(["Missing SKU", e[0], e[3]]);
}
});
// Check for missing column headers
colMap.forEach(function(e, i) {
if (e == -1) {
var index = destHeaders.indexOf(values[0][i]);
colMap[i] = index;
if (index == -1) {
logEntries.push(["Missing column header", values[0][e], ""]);
}
}
});
if (!values.length) {
logEntries.push(["No changes to make", "", ""]);
} else {
values = values.map(e => [destIds.indexOf(e[0]), e[1], e[2]]);
Logger.log(values.length + ' changes to make');
Logger.log(values);
values.forEach(function(e) {
try {
destValues[e[0]][e[1]] = e[2];
} catch (err) {}
});
destRange.setValues(destValues);
}
// Write log entries to the 'Shadow Log' sheet in the destination spreadsheet
if (logEntries.length > 0) {
var logSheet = SpreadsheetApp.openById('179PCrIWe1mvbbzOi9ySEHxzBlFaXpCB2i0wHlYVE2vg').getSheetByName("Shadow Log");
if (logSheet == null) {
logSheet = SpreadsheetApp.openById('179PCrIWe1mvbbzOi9ySEHxzBlFaXpCB2i0wHlYVE2vg').insertSheet("Shadow Log");
}
logSheet.clear();
logSheet.getRange(1, 1, logEntries.length, 3).setValues(logEntries);
}
}
the code block for getting the missing data in Column A destination spreadsheet works fine, but what I am having a hard time is getting the column name. The code block below shows only the column index instead of the comlumn title/header:
// Check for missing column headers
colMap.forEach(function(e, i) {
if (e == -1) {
var index = destHeaders.indexOf(values[0][i]);
colMap[i] = index;
if (index == -1) {
logEntries.push(["Missing column header", values[0][e], ""]);
}
}
});
sample sheets:
source: https://docs.google.com/spreadsheets/d/1zGqiYocUmSBRDPKRqI3iI3nIf7w3b9C7ykT-QffBROA/edit#gid=0
destination: https://docs.google.com/spreadsheets/d/1PjOvhscblzPxaBnJi1Q5oB6iCAt9_emljUR6vlAfIA0/edit#gid=0
example:
source data:
| SKU | walmart1 | amazon 2 | ebay1 |
|============|==============|==============|===========|
| SKUitem1 | SKUwm1 | | SKUebay1 |
| SKUitem2 | | | SKUitem5 |
| SKUitem3 | SKUwmi1 | | |
destination:
| items | **walmart2** | **amazon 1** | ebay1 |
|============|==============|==============|===========|
| SKUitem1 | SKUwm1 | | SKUebay1 |
|**SKUitem5**| | | |
| SKUitem3 | | | |
desired result:
in this scenario the 'Shadow Log' sheet should result into
| Missing SKU | SKUitem2 |
| Missing Column | walmart1 |
missing SKU - cause there were an update from the source but unable to find it in the destination
missing column - cause there were an update on that column but unable to find that column
you will also see that there is a mismatch column amazon 2 --> amazon 1, but you will see nothing in the desired results, it is because there's no new data to be updated.
I hope this clears things out, please don't hesitate to ask me
Check and Fix the Index when Accessing Desired Data
I noticed that when you tried to access the data from values, you used [e] as the index which will lead to an undefined value since [e] will always be -1 in your case and there is no -1 index in an arrays.
Also, when using the forEach method, the first variable (e in your case) will be the value to be processed while the second variable will be the index value (i in your case). Hence, you should use [i] when accessing data using loops.
With all that, I added a sourceCol variable to store all wanted column headers from the source.
You may change the range if you should add more columns. I changed values[0][e] to sourceCol[0][i] to access the wanted column header.
The new code should look like this: (I added comments for further guidance)
function updateShadowSKU() {
var source = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var dest = SpreadsheetApp.openById('Destination Sheet ID').getSheetByName('Sheet1');
var destRange = dest.getDataRange();
var destValues = destRange.getValues();
var destHeaders = destValues[0];
var destIds = destValues.map(e => e[0]);
var values = source.getDataRange().getValues().map(e => e.filter((f, i) => !i || i > 10));
//-----------------------------------------------------------------------------------------------
//added sourceCol variable to specifically get the array of all Column Headers from the Source
var sourceCol = source.getDataRange().getValues().map(e => e.filter((f, i) => i >= 3 && i <= 17));
var colMap = sourceCol[0].map(e => destHeaders.indexOf(e));
//-----------------------------------------------------------------------------------------------
values = values.map((e, i, arr) => e.map((f, j) => [e[0], colMap[j], f, values[0][j], i, j])).flat().filter(e => e[0] && e[1] && e[2] && e[3] && e[4] && e[5]);
// Initialize an array to store log entries
var logEntries = [];
// Check for missing SKUs
values.forEach(function (e) {
if (!destIds.includes(e[0])) {
logEntries.push(["Missing SKU", e[0], e[3]]);
}
});
// Check for missing column headers
colMap.forEach(function (e, i) {
if (e == -1) {
//--------------------------------------------------------------
//change values[0][e] to sourceCol[0][i]
logEntries.push(["Missing column header", sourceCol[0][i], ""]);
//--------------------------------------------------------------
}
});
if (!values.length) {
logEntries.push(["No changes to make", "", ""]);
} else {
values = values.map(e => [destIds.indexOf(e[0]), e[1], e[2]]);
Logger.log(values.length + ' changes to make');
Logger.log(values);
values.forEach(function (e) {
try {
destValues[e[0]][e[1]] = e[2];
} catch (err) { }
});
destRange.setValues(destValues);
}
// Write log entries to the 'Shadow Log' sheet in the destination spreadsheet
// Added an else statement to clear the 'Shadow Log` when the log is empty.
var logSheet = SpreadsheetApp.openById('Destination Sheet ID').getSheetByName("Shadow Log");
if (logEntries.length > 0) {
if (logSheet == null) {
logSheet = SpreadsheetApp.openById('Destination Sheet ID').insertSheet("Shadow Log");
}
logSheet.clear();
logSheet.getRange(1, 1, logEntries.length, 3).setValues(logEntries);
}
else {
logSheet.clear();
}
}
Output
In testing the code, I deleted 5 column headers (as seen below):
When I ran the code with the modification, I got the following output:
References
forEach
Accessing Arrays

Trying to Set Value in For Loop - apps script

I am trying to set the value of a cell in a column when two other columns at an index match values. How can I set the value using an index? (<Edited)
for (let i = 0; i < assetId.length; i++) {
for (let p = 0; p < oldId.length; p++) {
if (assetId[i] !="" && oldId[p] !="") {
if (assetId[i] == oldId[p]) {
Logger.log('Old Match: ' + assetId[i])
//if match modify 4th column at row [i] to 'null'
d.getRange(i,3).setValue('null')
}
}
}
}
Based on if assetId[i] == oldId[p], I am trying to change column F of row [i] to 'null'
Edit (examples requested)
Column J is oldId and K is newId
EXPECTED OUTPUT: F4 should be null
Full code:
function replaceIds() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const r = ss.getSheetByName("Form Responses 1")
const d = ss.getSheetByName("Devices")
const oldId = r.getRange("J2:J").getValues().flat()
const newId = r.getRange("K2:K").getValues().flat()
const studentName = r.getRange("C2:C").getValues().flat()
const assetId = d.getRange("G3:G").getValues().flat()
const annotatedUser = d.getRange("E3:E").getValues().flat()
for (let i = 0; i < assetId.length; i++) {
for (let p = 0; p < oldId.length; p++) {
if (assetId[i] !="" && oldId[p] !="") {
if (assetId[i] == oldId[p]) {
Logger.log('Old Match: ' + assetId[i])
//if match modify 4th column at row [i] to 'null'
d.getRange(i,3).setValue('null')
}
}
}
//new asset ID loop
for (let r = 0; r < newId.length; r++) {
//Logger.log(oldId[p])
if (assetId[i] !="") {
if (newId[r] !="") {
//Logger.log('## not null ##')
if (assetId[i] == newId[r]) {
Logger.log('New Match: ' + assetId[i])
}
}
}
}
}
}
Issue:
Issue is that, using a nested for loop is not a good idea as you can't properly follow where the proper index is, and it will also needlessly reiterate on items that were already visited.
Solution:
Looping only on the assetId should suffice, then using indexOf as it will help you identify if a certain element (current assetId) belongs in an array (list of oldIds).
If assetId is found, indexOf will return a non-negative number (which is what index the element is found in the array).
Exclude empty assetIds due to how you get your data
Then you can remove the column of that same row, but since index starts at 0 and your data starts at 3rd row, we need to offset the getRange row so it would match the cell we want to delete properly.
Modifying your current solution, this is what the solution says above, and should work.
Script:
function replaceIds() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const r = ss.getSheetByName("Form Responses 1")
const d = ss.getSheetByName("Devices")
const oldId = r.getRange("J2:J").getValues().flat()
const newId = r.getRange("K2:K").getValues().flat()
const studentName = r.getRange("C2:C").getValues().flat()
const assetId = d.getRange("G3:G").getValues().flat()
const annotatedUser = d.getRange("E3:E").getValues().flat()
// loop your assetId
assetId.forEach(function(cell, index){
// if assetId is listed under oldId, remove annotated location of that row
// also, skip any rows where assetIds are blank
if(oldId.indexOf(cell) > -1 && cell != "")
// offset here is 3 since assetId starts at G3 and index starts at 0
// 3 - 0 = 3, which is the offset, and 6 is column F
d.getRange(index + 3, 6).setValue('');
});
}
Output:
This function will change the value in column1 if the value of col2 at that index is in column 10 on any line. you can change the indices as you desire.
function findDataBasedOnMatch() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const sr = 2;//data start row
const vs = sh.getRange(sr, 1, sh.getLastRow() - sr + 1, sh.getLastColumn()).getValues();
const col10 =vs.map(r => r[9]);//you pick the indices
vs.forEach((r,i) => {
if(~col10.indexOf(r[1])) {//you pick the indices
sh.getRange(i + sr, 1).setValue('');
}
});
}

slick joins with function inputs

How is it possible to use inputs from the function and joins in slick
example
def query (coffeID : int) = DBAction { implicit rs =>
val implicitInnerJoin = for {
c <- coffees
s <- suppliers if ((c.supID === s.id ) && (c.cofID === coffeeID))
} yield (c.name, s.name)
-- edit typo with ====
you need to use ===
def query (coffeID : int) = DBAction { implicit rs =>
val query = for {
c <- coffees
s <- suppliers if (c.supID === s.id) && (c.cofID === coffeeID)
} yield (c.name, s.name)
query.list
}

LINQ2SQL A problem with return items based on a parameter

I occured a strange problem. I have that method
public static void ProcessCategories(int? myID)
{
var tmpList = Adapter.Category.Where(x => x.IdParentCategory == myID).ToList();
}
when myID == null (the parameter), the tmpList doesn't contain any elements, but if I type
x.IdParentCategory == null then some items are returned. Why ?
Try this:
public static void ProcessCategories(int? myID)
{
var tmpList = Adapter.Category.Where(x => x.IdParentCategory == myID || (myID == null && x.IdParentCategory == null)).ToList();
}

LINQ to SQL refactoring foreach help

Can this be refactored into one LINQ statement? I feel like it can be but can't wrap my head around it. The mishmash of extension methods and LINQ just looks ugly to me.
(db is a DataContext.)
void AddToSeries(Series series, DateTime date)
{
foreach (var date in db.Ad.Select(ad => ad.DateTime.Date).Distinct())
{
var phraseCount = (from pc in db.PhraseCount
where pc.DateTime.Date == date
select pc.Count).SingleOrDefault();
var adCount = db.Ad.Where(ad => ad.DateTime.Date == date).Count();
series.Add(new KeyValuePair<DateTime, double>(date, adCount));
}
}
First refactor to consistent style.
void AddToSeries(Series series, DateTime date)
{
var dates = db.Ad
.Select(ad => ad.DateTime.Date)
.Distinct();
foreach (DateTime date in dates)
{
var phraseCount = db.PhraseCount
.Where(pc => pc.DateTime.Date == date)
.Select(pc => pc.Count)
.SingleOrDefault();
var adCount = db.Ad
.Where(ad => ad.DateTime.Date == date)
.Count();
series.Add(new KeyValuePair<DateTime, double>(date, adCount));
}
}
Aha:
phraseCount is not used
key is a date, value is a count
multiple database trips is no fun
date parameter for this method is blocked by the foreach variable
Now we can refactor:
void AddToSeries(Series series, DateTime date)
{
var pairs = db.Ad
.GroupBy(ad => ad.DateTime.Date)
.Select(g => new {key = g.Key, theCount = g.Count()});
foreach (var x in pairs)
{
series.Add(new KeyValuePair<DateTime, double>(x.key, x.theCount));
}
}