SQLite-Net: use comparison in ORDER BY clause - sql-order-by

I'm using a SQLite-Net database and would like to order by a comparison, like this:
var value1 = 10;
var items = connection.Table<Item>.OrderBy(i => i.Field1 > value1).ToArray();
(Note: value1 and Field1 are both integers)
This throws an exception:
System.NotSupportedException: Order By does not support: i => i.Field1 > value1
As a workaround, I've now split this query into two parts:
Select the item where Field1 is larger than value1
Select the item where Field1 is smaller than or equal to value1
And then these results are combined to a single result.
Is there a better way to handle this using SQLite-Net?

My first approach was:
var value1 = 10;
var items = new List<Item>();
items.AddRange(connection.Table<Item>.Where(i => i.Field1 <= value1));
items.AddRange(connection.Table<Item>.Where(i => i.Field1 > value1));
But I finally settled for a single query:
var value1 = 10;
var items = connection
.Query<Item>(#"SELECT *
FROM [Item]
ORDER BY [Field1] > ? ASC", value1);

Related

Executing list of IEnumerable queries

I have multiple Link queries loading to a IEnumerable list
var queries = new List<IEnumerable<Customers>>();
queries.Add(from c in context.Customers where c.region = 'NE' select c);
queries.Add(from c in context.Customers where c.region = 'SW' select c);
//want count of customers in those two regions
var result = queries.Sum(q => Count());
However it is returning a count of the queries (2), not count of the Customers.
How can execute the List of IEnumerable queries?
The mistake is at the last line:
q => Count()
Instead of actually counting the elements in a sequence, which would be q => q.Count(), you are calling a method Count() of either a current instance or the current class.
Actually, there is no need to do two separate queries. Instead, use a single query:
var query = from c
in context.Customers
where c.region = 'NE' || c.region = 'SW'
select c;
var result = query.Count();
or, slightly shorter:
var result = context.Customers.Count(c => c.region = 'NE' || c.region = 'SW');

Find Minimum and Maximum of a column in LInq query result

I have an Linq query like this:
var result = from c in displayedEmployees select new[] { c.Name, c.Code, c.Rank.ToString(), c.Id.ToString(),c.Rank. };
If i want to select the min and max of any column for example Rank along with this like:
var result = from c in displayedEmployees select new[] { c.Name, c.Code, c.Rank.ToString(), c.Id.ToString(),min(c.Rank) ,max(c.Rank)};
how can I do this?
Select actually performs a transformation of every item (displayedEmployee), so ends up with the same number of items as you started with. Min and max are reductions, they reduce the list into a scalar.
After the "select" keyword is a function that only recieves the current item (c in your case). So there is no way to get the max there and you don't want every item in result to repeat the same maximum value.
You should compute the minimum and maximum separately.
After:
var result = from c in displayedEmployees select { c.Name, c.Code, c.Rank };
You could do something like this:
var min = result.Min(x => x.Rank);
var max = result.Max(x => x.Rank);
See more samples here (LINQ 101): http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

LINQ to Entity : Multiple join conditions

There are numerous post regarding LINQ and multiple joins.
I have however not found any solution to the join I'd like to make.
The SQL equivalent would be something like this:
SELECT * FROM table1 a
LEFT JOIN table2 b ON a.col1 = b.key1 AND
a.col2 = b.key2 AND
b.from_date <= now() AND
b.deleted = 0;
Here's one of the numerous linq queries I've attempted
var query = (from x in context.table1
join y in context.table2 on new {x.col1, x.col2} equals {b.key1, b.key2}
into result
from result......
How may I add the additonal conditions of the date and deleted flag?
If I use .Where conditions, then this is treated as a inner join, not a left join.
Another way could be like
var query = (from x in context.table1
join y in context.table2 on
new {
Key1 = x.col1,
Key2 = x.col2,
Key3 = true,
Key4 = true
}
equals
new {
Key1 = y.key1,
Key2 = y.key2,
Key3 = y.from_date< DateTime.Now,
Key4 = !y.deleted
}
into result
from r in result.DefaultIfEmpty()
select new {x.Something, r.Something}
LINQ supports both the join syntax and the older ANSI-82 WHERE syntax. Using the later, you could do what your looking for on an inner join with
var nowTime = DateTime.Now;
var query = from a in context.table1
from b in context.table2
where a.col1 == b.key1
&& a.col2 == b.key2
&& b.from_date < nowTime
&& b.deleted == false
select ???;
For an outer join, I prefer a syntax using a hybrid of where and select many. (Realize that the order in the LINQ query does not need to mimic what you would do in SQL and the order is more flexible.)
var nowTime = DateTime.Now;
var query = from b in context.table2
from a1 in a.Where(a2 =>
b.key1 = a.col &&
b.key2 = a.col2 &&
b.from_date < nowTime &&
b.deleted == false).DefaultIfEmpty()
select ???;
I had problem with naming of properties in anonymous object:
var subscriptions = context.EmailSubscription.Join(context.EmailQueue,
es => new { es.Id, 9 },
eq => new { eq.EmailSubscriptionId, eq.EmailTemplateId },
(es, eq) => new { es.Id, eq.Id }
).ToList();
Compiler was not happy so above answer helps me to figure out what was wrong and here is my working solution. It took me some time to find stupid mistake :) :
var subscriptions = context.EmailSubscription.Join(context.EmailQueue,
es => new { EmailSubscriptionId = es.Id, EmailTemplateId = 9 },
eq => new { eq.EmailSubscriptionId, eq.EmailTemplateId },
(es, eq) => new { es.Id, eq.Id }
).ToList();
Could you not just filter the 1st result set with a second query?
var query = (from x in context.table1
join y in context.table2 on new {x.col1, x.col2} equals {b.key1, b.key2}
into result
query = from x in query
where ...
Would that work?
In addition to #Muhammad Adeel Zahid answer, you could use also some several conditions like:
new
{
Key1 = ppl.PeopleId,
Key2 = true,
Key3 = true
}
equals
new
{
Key1 = y.PeopleId,
Key2 = !y.IsDeleted,
Key3 = (y.RelationshipType == 2 || y.RelationshipType == 4)
}

Using LINQ to get all the records in a table having the same value in a specific column

I am trying to get all the rows in a table having the same value in a column. I got it working by using group by:
var groupedData = from row in Tab1Model.ExcelGridDataSource.AsEnumerable()
group row by row.Field<string>("A");
foreach (var group in groupedData)
{
if (group.Count() > 1)
{
//select from each group only the DataRows
//having a certain value in a second column
foreach (var dataRow in group)
{
multipleRowsList.Add(dataRow);
}
}
}
I would like to avoid calling foreach ,get only the groups having a count > 1 and then get ONLY
the DataRows that have a second column with a specific value. Thanks!
try this:
var query = from row in excelDataSource
group row by row.Field<string>("A") into g
select new { Value = g.Key, Rows = g };
var nonZeroRows= from q in query
where q.Rows.Count() > 0
select q.Rows;
// at this point you have an enumerable of enumerables of tablerows.
var list = nonZeroRows.Aggregate(Enumerable.Empty<TableRow>(),
(a, b) => a.Concat(b.Where(c => c.Something == true)); // your condition here
Thanks Atanamir! Here is the final code, just wonder if you have any better ways of doing it. the end goal of this is to flag one of the rows that is entered twice.
var groupedData = from row in Tab1Model.ExcelGridDataSource.AsEnumerable()
group row by row.Field<string>("A")
into g
select new {Value = g.Key, Rows = g};
var nonZeroesRows = from q in groupedData
where q.Rows.Count() > 1
select q.Rows;
//at this point you have an enumerable of enumerables of tables rows
var listRows = nonZeroesRows.Aggregate(Enumerable.Empty<DataRow>(),
(a, b) => a.Concat(b.Where(c => c.Field<bool>("Omit Row") == false)));
//grouped them again and get only the last row from the group wiht a count > 1
var doubleRows = from row in listRows
group row by row.Field<string>("A")
into g
where g.Count() > 1
select g.Last();
Or maybe better:
var groupedData = from row in Tab1Model.ExcelGridDataSource.AsEnumerable()
group row by row.Field<string>("A")
into g
where g.Count() > 1
select new {/*Value = g.Key,*/ Rows = g};
//at this point you have an enumerable of enumerables of tables rows
var listRows = groupedData.Aggregate(Enumerable.Empty<DataRow>(),
(a, b) => a.Concat(b.Rows.Where(c => c.Field<bool>("Omit Row") == false)));
//grouped them again and get only the last row from the group wiht a count > 1
var doubleRows = from row in listRows
group row by row.Field<string>("A")
into g
where g.Count() > 1
select g.Last();

Linq extract a count() value from a data object

I have divAssignments that has potential multiple rows by rNI, an official id, according to a compound key of Indictment and booking numbers.
rNI Booking Indictment
12345 954445 10 12345
12345 954445 10 12346
12345 954445 10 12347
So ID has a count of 3 for a single booking number for this rni.
I get lost attempting to generate a count and a group by booking Number:
var moreThen = from dA in divAssignments
select new { dA.rNI, IndictmentCount = dA.indictmentNumber.Count() };
Most of the examples are dealing with static int[] and don't seem to work in my case.
How do I get a group and then a count? If I could put in a having that would be fantastic.
from a t-sql POV I'd use this:
Select rni, bookingNumber, count(*) IndictmentCount
from divAssignments
group by rni, bookingNumber
having count(*) > 0
TIA
How about something like this:
var query = from item in divAssignments
group item by item.rNI into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
If you're interested in grouping by both the rNI and the booking number, I would change it to this:
var query = from item in divAssignements
group item by new { item.rNI, a.Booking } into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count
};
OR
var query = from item in divAssignments
group item by item into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
and implement IEquatable on the divAssignment object to support equality comparison. The other option if you'd like is to write an IEqualityComparer instance to do the composite key comparison. Your query could then look like:
var query =
divAssignments
.GroupBy(i => i, new MyCustomEqualityComparer())
.Select(i => new { Key = i.Key, Count = i.Count());
var query =
from dA in divAssignments
group dA by new { dA.rNI, dA.bookingNumber };
foreach(var grp in query)
{
Console.WriteLine("rNI={0}, bookingNumber={1} => Count={2}", grp.Key.rNI, grp.Key.bookingNumber, grp.Count());
}
If you use a Grouping operator in Linq you will get what you need. The code:
var count = from a in divAssignments
group a by new { a.rNI, a.Booking } into b
select b;
will return a collection of IGrouping objects. This will give you the Key (in my example this will be an anonymous type with an rNI and a Booking property) and a collection of the divAssignments that match the key.
Using Method syntax (much easier to read in my opinion):
First group the records, then select a new result for each group that contains the count.
var groups = divAssignments.GroupBy(d => new { d.rNI, d.Booking });
groups.Select(g=> new { g.Key.rNI, g.Key.Booking, IndictmentCount = g.Count() });

Resources