Why there is no LastOrDefault method in petapoco like FirstOrDefault? - c#

Let's say this is my table TicketUpdate in SQL Server with some data inside:
_______________________________
| Id | TicketId | Description |
-------------------------------
| 1 | 5 | desc1 |
| 2 | 6 | desc2 |
| 3 | 5 | desc3 |
| 4 | 5 | desc4 |
| 5 | 6 | desc5 |
I want to retrieve the last row with TicketId = 5 in using Petapoco.
There are several methods for retrieving single row like FirstOrDefault which looks like:
db.FirstOrDefault<TicketUpdate>("select * from TicketUpdate where TicketId = 5");
But using this statement it returns the first row with value of TicketId = 5 with a description of desc1.
My question is how can I retrieve the LastOrDefault value then? There is no such methods in Petapoco.
Additional info
Temporarily I can retrieve the last row with TicketId = 5 by nesting the query like
select *
from TicketUpdate
where Id = (select MAX(Id) from TicketUpdate where TicketId = 5)
But is there any methods or better approach for finding the last row like we retrieve First row by using FirstOrDefault method, without nesting the query?

As mentioned in the comments, you should be able to sort your data first.
Try something like this:
db.FirstOrDefault<TicketUpdate>("select TOP 1 * from TicketUpdate where TicketId = 5 orderby [Id] desc");
As long as Id is incremented it should return the last item added for TicketId == 5.

Change your query to get the last record where ID is max. Also you need to use Top 1 to get only one record.
select Top 1 * from TicketUpdate where TicketId = 5 order by ID desc

Related

is there a way to use OFFSET and FETCH in MS access or anything similiar in a query, set query has to be used in ASP.NET [duplicate]

Is it possible to emulate the following MySQL query:
SELECT * FROM `tbl` ORDER BY `date` DESC LIMIT X, 10
(X is a parameter)
in MS Access?
While the Access/JET TOP keyword does not directly provide an OFFSET capability, we can use a clever combination of TOP, a subquery, and a "derived table" to obtain the same result.
Here is an example for getting the 10 rows starting from offset 20 in a Person table in ORDER BY Name and Id...
SELECT Person.*
FROM Person
WHERE Person.Id In
(
SELECT TOP 10 A.Id
FROM [
SELECT TOP 30 Person.Name, Person.Id
FROM Person
ORDER BY Person.Name, Person.Id
]. AS A
ORDER BY A.Name DESC, A.Id DESC
)
ORDER BY Person.Name, Person.Id;
Essentially, we query the top 30, reverse the order, query the top 10, and then select the rows from the table that match, sorting in forward order again. This should be fairly efficient, assuming the Id is the PRIMARY KEY, and there is an index on Name. It might be that a specific covering index on Name, Id (rather than one on just Name) would be needed for best performance, but I think that indexes implicitly cover the PRIMARY KEY.
Another way - Let say you want from 1000 to 1999 records in a table called table1 (of course if you have that many records) you can do something like this.
MSSQL
SELECT *
FROM table1 LIMIT 1000, 1999;
MS Access
SELECT TOP 1000 *
FROM table1
Where ID NOT IN (SELECT TOP 999 table1.ID FROM table1);
To break this down
SELECT TOP NumA *
FROM table1
Where ID NOT IN (SELECT TOP NumB table1.ID FROM table1);
UpperLimit = 1999
LowerLimit = 1000
NumA = UpperLimit - LowerLimit + 1
ex. 1000 = 1999 - 1000 + 1
NumB = LowerLimit -1
ex. 999 = 1000 - 1
A better query would be:
SELECT Users.*
FROM Users
WHERE Users.id In
(
SELECT TOP X A.id
FROM [
SELECT TOP Y Users.*
FROM Users
ORDER BY Users.reg_date DESC
]. AS A
ORDER BY A.reg_date ASC
)
ORDER BY Users.reg_date DESC
Where
if((totalrows - offset) < limit) then
X = (totalrows - offset)
else
X = limit
And:
Y = limit + offset
For example, if total_rows = 12, and we set the limit to 10 (show 10 users per page), and the offset is calculated as p * limit - (limit) where p is the number of the current page, hence in the first page (p = 1) we will get: X = 12 and Y = 10, on the second X = 2 and Y = 20. The list of users is ordered by registration date (descending).
Simple and fastest solution.
myTable {ID*, Field2, Filed3...}
Assume your SortOrder contain primary KEY only
SELECT TOP PageItemsCount tb01.*
FROM myTable AS tb01
LEFT JOIN (
SELECT TOP OffsetValue ID FROM myTable ORDER BY ID ASC
) AS tb02
ON tb01.ID = tb02.ID
WHERE ISNULL(tb02.ID)
ORDER BY tb01.ID ASC
SortOrder based on other fields with duplicated values, in this case you must include your primary key in SortOrder as last one.
For exemple, myTable
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 1 | a1 | b |
| 2 | a | b2 |
| 3 | a1 | b2 |
| 4 | a1 | b |
+-------+--------+--------+
SELECT TOP 2 * From myTable ORDER BY FIELD2;
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 2 | a | b2 |
| 4 | a1 | b |
| 3 | a1 | b2 |
| 1 | a1 | b |
+-------+--------+--------+
SELECT TOP 2 * From myTable ORDER BY FIELD2, FIELD3;
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 2 | a | b2 |
| 4 | a1 | b |
| 1 | a1 | b |
+-------+--------+--------+
But if we add ID to sort order [AS LAST IN FIELDS LIST]
SELECT TOP 2 * From myTable ORDER BY FIELD2, ID;
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 2 | a | b2 |
| 1 | a1 | b |
+-------+--------+--------+
Final request
SELECT TOP PageItemsCount tb01.*
FROM myTable AS tb01
LEFT JOIN (
SELECT TOP OffsetValue ID FROM myTable ORDER BY Field2 ASC, ID
) AS tb02
ON tb01.ID = tb02.ID
WHERE ISNULL(tb02.ID)
ORDER BY tb01.Field2 ASC, tb01.ID
You can definitely get the the equivalent of "Limit" using the top keyword. See:
Access Database LIMIT keyword
No, JET SQL does not have a direct equivalent. As a workaround, you could add a WHERE clause that selects an ordered/id column between two values.
If possible, you can also use pass-through queries to an existing MySQL/other database.
While TOP in MS-Access can limit records returned, it does not take two parameters as with the MySQL LIMIT keyword (See this question).

Find out every column sum by groupwise as row Using Pivot

I have a table tbTest like this:
q1 | q2 | q3 | type
--------------------
2 | 1 | 3 | student
3 | 2 | 1 | alumni
2 | 1 | 3 | alumni
1 | 1 | 3 | student
Now I want a new table which is based on the first table and finds the sum of every question by GroupWise convert it into like this:
q | student | alumni
---------------------
q1 | 3 | 5
q2 | 2 | 3
q3 | 6 | 3
SELECT Student,
Alumni
FROM
(SELECT q1, userType FROM tbTest2) tb1
PIVOT
(
SUM(q1)
FOR userType IN (Student, Alumni)
) AS tb2;
But using(above SQL) Pivot I can manage only one row like this:
student | alumni
---------------------
3 | 5
You can unpivot the data and aggregate. Based on the C# tag, I am assuming the database is SQL Server, in which case you can use apply:
select v.question,
sum(case when t.type = 'student' then val else 0 end) as student,
sum(case when t.type = 'alumni' then val else 0 end) as alumni
from t cross apply
(values ('q1', t.q1), ('q2', t.q2), ('q3', t.q3)) v(question, val)
group by v.question;
In other database, you can do something similar using a lateral join or union all.

Case When SQL to LINQ

I am still new to LINQ and trying to convert this SQL command
Id | TitleName
------ | ------
1 | Accounts
2 | Buyer
3 | Engineer
4 | Other
5 | Apple
SELECT Id, TitleName
FROM dbo.Title
ORDER BY
CASE WHEN TitleName = 'Other'
THEN 0 ELSE 1 END DESC, TitleName ASC
This selects the table and ascends it in alphabetical order
Then it grabs 'Other' and forces it to the bottom.
So it ends up like this
Id | TitleName
------ | ------
1 | Accounts
5 | Apple
2 | Buyer
3 | Engineer
4 | Other
This works in SQL,
What is the best approach to achieve this using LINQ ?
Edit: Issue Resolved
var queryAllCustomerTitle = from cust in _titleRepository.Table
orderby cust.TitleName == "Other" ? 1 : 0, cust.TitleName
select cust;
use the ternary operator
OrderByDescending(a=>a.TitleName == "Other" ? 0:1).ThenBy(a=>a.TitleName)

Check value of datatable to update or insert in c#

I have a datatable with following structure:
Department | DocumentID | Days
Before I add rows to this datatable I should consider two situations:
If Department and DocumentID already exists, update number of Days in same row.
else add row.
Example:
Instead of multiple records for same Department and DocumentID
Marketing | 1 | 10
Human Resources | 1 | 5
Marketing | 1 | 5
Marketing | 2 | 5
Should add number of days to existing row
Marketing | 1 | 15
Human Resources | 1 | 5
Marketing | 2 | 5
If this is not easily doable, I thought of adding multiple records to one table and then sum days where Department and DocumentID are the same, but I didn't succeed in doing this also.
Any tips?
You can search your datatable with the Select method which use a SQL like syntax for the filtering.
Then either insert a new row or update the one you found.
var rows = dataTable.Select(string.Format("DocumentId = {0}", documentId));
if (rows.Length == 0)
{
// Add your Row
}
else
{
// Update your Days
rows[0]["Days"] = newDayValue;
}

How do a make a query to count which string appears the most in a certain column?

I'm making a program and I need to make a query to the database asking for the string that appears most often in a given column. In this example, its "stringONE".
----------------------------
| ID | Column (string) |
----------------------------
| 1 | stringONE |
----------------------------
| 2 | stringTWO |
----------------------------
| 3 | stringONE |
----------------------------
| 4 | stringONE |
----------------------------
Now I need to take the name of the string that appears the most and put it into a variable string, for example:
string most_appeared_string = sql.ExecuteScalar();
Also, what happens if there is no string that appears the most, rather 2 or more strings that appear the same amount of times, like this:
----------------------------
| ID | Column (string) |
----------------------------
| 1 | stringONE |
----------------------------
| 2 | stringTWO |
----------------------------
| 3 | stringTWO |
----------------------------
| 4 | stringONE |
----------------------------
Thanks ahead.
#KeithS
Do you have an sql-server version of the query because I'm getting some errors when trying it there. Here's a table example of what I'd like to do precisely.
------------------------------------------------
| ID | column1 (string) | author (string) |
------------------------------------------------
| 1 | string-ONE | John |
------------------------------------------------
| 2 | string-TWO | John |
------------------------------------------------
| 3 | string-ONE | Martin |
------------------------------------------------
| 4 | string-ONE | John |
------------------------------------------------
SELECT TOP (1) column1, COUNT(*) FROM table WHERE author='John' ORDER BY ID
It should return "string-ONE" since it appears the most (2) times for the author John. When trying the query in MS-SQL Management Studio though, this is the error I'm getting:
Column 'table.column1' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Nevermind the edit. Thank you.
This is a pretty easy query (in T-SQL at least):
select top 1 Column, Count(*) from Table group by Column order by Count(*) desc
ExecuteScalar, by an implementation detail, will return the string value because it's the first column of the only row in the result set, even though there are two columns. You could also use ExecuteReader to access the number of times that string occurs.
select top (1) SomeCol, count(*) as Row_Count
from YourTable
group by SomeCol
order by Row_Count desc
Also, what happens if there is no string that appears the most, rather
2 or more strings that appear the same amount of times, like this:
In that case, using the above query, you will get one arbitrary row. You can add with ties to get all rows that has the same highest value.
select top (1) with ties SomeCol, count(*) as Row_Count
from YourTable
group by SomeCol
order by Row_Count desc
SELECT max(counted) AS max_counted FROM (
SELECT count(*) AS counted FROM counter GROUP BY date
)
This could do the trick

Categories

Resources