SQL Query: Display only latest Id from each set - c#

I have the following SQL Table:
Name Description Id UserId CreatedDate
UserSet1 Desc1 1 Abc 06/01/2018
UserSet1 Desc2 2 Def 06/02/2018
UserSet2 Desc for 2 5 NewUser 06/04/2018
UserSet2 Desc for 2 7 NewUser 06/19/2018
What I want to extract from the above table is just the latest Id for each Name so that I could get the following output
Name Description Id UserId CreatedDate
UserSet1 Desc2 2 Def 06/01/2018
UserSet2 Desc for 2 7 NewUser 06/19/2018
Since Id 2 & 7 are the latest entries in the table for UserSet1 & UserSet2, I would like to display that instead of all the entries in the table.
Any inputs how can I get the desired result.
I am open for solutions directly returning the output or any linq (C#) solutions as well. Ie returning the entire dataset and then using linq to filter the above.

EDIT: Since you are looking for the highest number ID, the GROUP BY method would probably be easier to work with.
Using a window function:
SELECT *
FROM (
SELECT Name, Description, Id, UserId, CreatedDate
, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY CreatedDate DESC) AS rn
FROM myTable
) s1
WHERE rn = 1
I don't have an instance of dynamoDB to test on, but I believe it can use the ROW_NUMBER() window function.

Thanks everyone for pointing to right direction. I have got this working with the below code of Linq and C#:
var results = response.GroupBy(row => row.Name)
.SelectMany(g => g.OrderByDescending(row => row.Id).Take(1));
For the initial tests this seems to be working. Let me know if you think this has come issues.

This should be a general SQL answer:
SELECT * FROM yourtable Y1
WHERE Id = (SELECT MAX(Id)
FROM yourtable Y2
WHERE Y2.Name = Y1.Name)

If it was MS SQL you could use Partition By command, otherwise most performant way would be:
select * from Table
where Id in (
select Max(Id) from Table
Group By Name
)
not sure if you can leave Name out of the Select statement, you might need to do:
select * from Table
where Id in (
Select Id from
(select Name, Max(Id) as Id from Table
Group By Name)
)

Related

SQL Statement Not Selecting

I'm using SQL Server in a C# project for a troubleshooting program and I have a table that contains ID,Question,QuestionId,Solution and Rank. I want there to be multiple solutions to a problem and the program will choose the best ranked solution, which is just chosen by the highest number which gets incremented every time it is correct. For this I have the following SQL statement:
sql = "SELECT Solution FROM dbo.Questions WHERE Rank=(SELECT MAX(Rank) FROM
dbo.Questions) AND QuestionId =" + questionId;
When I had just one solution available this worked fine, but when I have multiple solutions it doesn't.
You need to properly parameterize your queries. Bobby Tables: A guide to preventing SQL injection
sql = "SELECT Solution FROM dbo.Questions q WHERE Rank=(SELECT MAX(Rank) FROM
dbo.Questions i where i.QuestionId = q.QuestionId) AND q.QuestionId =" + questionId;
This makes sure the max(rank) returned by the subquery is the max(rank) of the solution for the QuestionId you are querying for.
You can also do this if you just want one Solution:
select top 1 Solution
from dbo.Questions q
where QuestionId = #QuestionId
order by [Rank] desc
You're selecting the max rank of all solutions and looking for the solution to a specified question with that rank.
Start at the beginning - select the possible solutions into a CTE
with solutions as(
SELECT Solution, Rank FROM dbo.Questions WHERE QuestionId = #questionId
)
... more to come
Given that, you can use a ranking function to rank all the possible solutions, by rank and select the one with the best rank (too many ranks in that sentence!)
with solutions as(
SELECT Solution, Rank() OVER (ORDER BY Rank DESC) as rank
FROM dbo.Questions WHERE QuestionId = #questionId
)
SELECT * FROM solutions WHERE rank = 1
This doesnt cover 2 solutions having an equal rank - you'll get 2 results from the query if 2 have the same rank. Two solutions there - consider using both.
Chose a tiebreaker column - perhaps the most recent - by adding a second column into the ORDER BY (...RANK() OVER (ORDER BY rank DESC, CreatedDate DESC)
Throw a TOP 1 into the final select (SELECT TOP 1 * FROM solutions WHERE rank = 1)
The record has the MAX rank may not have the questionId you given in the AND QuestionId =" + questionId;
You might try this, I have left the where clause outside of the CTE query so that you can also use the query to get a complete list of each question with it's max rank (if you leave out the questionId filter):
with [ctreMaxSolution] as
(
select [QuestionId]
, max([Rank]) as [Rank]
from [dbo].[Questions]
group by [QuestionId]
)
select *
from [dbo].[Questions] as [q]
inner join [cteMaxSolution] as [cms] on [q].[QuestionId] = [cms].[QuestionId]
and [q].[Rank] = [cms].[Rank]
where [q].[QuestionId] = #questionId;
I've used a SQL Server variable there, but you can make a stored procedure out of it or convert it to an ad-hoc query like in your question, totally up to you.
First make a filter by "questionId" and then "order By" rank.
try with this:
SELECT TOP 1 q.solution FROM dbo.Questions q WHERE q.QuestionId = #QuestionId
ORDER BY q.Rank desc
Hope this help!
Kindly modify your query as below.
sql = "SELECT Solution FROM dbo.Questions WHERE Rank in (SELECT MAX(Rank) FROM
dbo.Questions) AND QuestionId =" + questionId;
Here i have modified where rank "in" instead of "="

I want the last entries in my Microsoft SQL Server database but get duplication

My problem is that I want to start a database query which should give me the last (maxDate) entry of every Serial number.
I am working with a Microsoft SQL Server database.
The first picture shows all entries in the database:
After I have run the following code I get this output:
string aQuery = #" SELECT *
FROM (
SELECT SerialNumber, MAX(Date) as MaxDate
FROM eBox_Deploy
GROUP BY SerialNumber
) r
INNER JOIN eBox_Deploy t
ON t.SerialNumber = r.SerialNumber AND t.Date = r.MaxDate";
using (var db = new eBoxDataContext())
{
list.AddRange(db.ExecuteQuery<eBox_Deploy>(bQuery));
}
After picture:
Now my problem is that I have duplicates because they already exists in the database. Distinct doesn't work well because these all have different Id´s.
How can I get them away?
You could use windowed functions:
SELECT *
FROM (SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY [SerialNumber] ORDER BY [Date] DESC)
FROM eBox_Deploy) AS sub
WHERE rn = 1;
If your [Date] is not unique within SerialNumber group use RANK() to get ties.

SQL : Compound Subset Select

LAYOUT:
I have a Subscriber database with Subscriber info in a table, all with unique AccountID's.
I have multiple History databases with a History table in each, all pertaining to the AccountID's in the Subscriber database.
I NEED:
I need a list of the most recent History record entered, in any of the History databases, for each AccountID in the Subscriber data. 1 record per AccountID.
I can achieve this with multiple hits to the database, but there are potentially millions of records and that doesn't sit well in my head. I want to make this happen in one hit.
Help. Me. Thanks.
Here's something I have tried already, but it doesn't give me a single record per AccountID...
SELECT
MAIN.*,
ISNULL(SubData.Name, '') AS [Name],
ISNULL(SubData.AcctLineCode, '') AS AcctLineCode,
ISNULL(LTRIM(RTRIM(SubData.AcctNum)), '') AS AcctNum
FROM
(
SELECT AccountID, AlarmDate, AlarmCode FROM [History1113]..SignalHistory WHERE AccountID IN (SELECT DISTINCT AccountID FROM Subscriber..[Subscriber Data])
UNION
SELECT AccountID, AlarmDate, AlarmCode FROM [History1013]..SignalHistory WHERE AccountID IN (SELECT DISTINCT AccountID FROM Subscriber..[Subscriber Data])
UNION
SELECT AccountID, AlarmDate, AlarmCode FROM [History0913]..SignalHistory WHERE AccountID IN (SELECT DISTINCT AccountID FROM Subscriber..[Subscriber Data])
)
AS MAIN
LEFT JOIN Subscriber..[Subscriber Data] AS SubData ON Main.AccountID = SubData.AccountID
ORDER BY AccountID, AlarmDate DESC
I'd do it as a view. Biggest issue will be making sure the view can see all the history tables if they are in seperate databases. You may have to get into linked servers
Create view historytable
as
select * from historytable1
union all
select * from historytable2
union all
etc...
Now query from historytable as if it was a table with all rows in it.
Edit:
the statement you've added has no aggregates, so it has no method of filtering down (or grouping by) into one record.
To your reply:
Lets call my view above main so I don't have to type so much.
Select account_id, max(alarm_date) as maxdate from main group by account_id
This simple select brings back to most recent record. Inner join it so it functions as a filter.
select ...
from main
inner join (Select account_id, max(alarm_date) as maxdate from main group by account_id) maxdate
on main.account_id = maxdate.account_ID and maxdate.maxdate = main.alarm_date
Add your subscriber join to the bottom of that and fill in the columns you need
With a little help from a couple of you, I was able to figure this out. So, thank you all.
Here's a code snippet of how I got it to work. I still need to do some joins to bring in account info, but this was the hard part.
`
SELECT MAIN.AccountID, MAX(MAIN.AlarmDate) AS AlarmDate FROM
(
SELECT AccountID, MAX(AlarmDate) AS AlarmDate FROM [History1113]..SignalHistory WHERE AccountID IN (SELECT DISTINCT AccountID FROM Subscriber..[Subscriber Data])
GROUP BY AccountID
UNION
SELECT AccountID, MAX(AlarmDate) AS AlarmDate FROM [History1013]..SignalHistory WHERE AccountID IN (SELECT DISTINCT AccountID FROM Subscriber..[Subscriber Data])
GROUP BY AccountID
UNION
SELECT AccountID, MAX(AlarmDate) AS AlarmDate FROM [History0913]..SignalHistory WHERE AccountID IN (SELECT DISTINCT AccountID FROM Subscriber..[Subscriber Data])
GROUP BY AccountID
)
AS MAIN
GROUP BY MAIN.AccountID
`

SQL Query in c#

I might have a problem with my SQL query. In this query I'm combining 4 different tables.
I have a table courses where general information is stored (course_number, course_title).
I have a table employees where general information of employees isstored (empname, and a job_id).
A employee has a job. A employee needs to take courses. It depends on the job which courses he has to take. This info is stored in the table job_course (with the job_id and the course_id).
If a employee completed a course it is stored in the table emp_courses (with the e_id and the course_id)
Now I want to search a certain course - when the user presses the search button he should get two different results.
The first one: here you can see which employee already took this course (this query works so far)
the second one: here you can see which employee still needs to take the course. So i need to check which job the employee has and if he needs to make that course . and also i just want to have the ones that are not completed yet.
And that's the query that is not working
Here it is:
OpenDb_Open("select course_number,course_title, empname from course
INNER JOIN (job_course INNER JOIN (employee INNER JOIN emp_course
ON emp_course.e_id<>employee.e_id) ON job_course.job_id=employee.job_id)
ON course.course_id=job_course.course_id
where course_number like '" + coursenumber + "'");
Can someone please help me with this?
Courses the employee hasn't taken.
SELECT * FROM courses
WHERE course_number IN (
SELECT course_id FROM job_course
WHERE course_id NOT IN (
SELECT course_id FROM emp_courses
WHERE emp_id = {someid}
) AND job_id = (
SELECT job_id FROM employees
WHERE emp_id = {user_input}
)
)
Which employees still need to take a course.
SELECT emp_name FROM employees
WHERE emp_id NOT IN (
SELECT emp_id FROM emp_courses
WHERE course_id = {user_input}
)
Variant of above.
SELECT emp_name FROM employees
WHERE emp_id NOT IN (
SELECT emp_id FROM emp_courses
WHERE course_id = (
SELECT course_id FROM courses
WHERE course_number = {user_input}
)
)

Last record of orders for specific customer - SQL

i am trying to show the last order for the a specific customer on a grid view , what i did is showing all orders for the customer but i need the last order
here is my SQL code
SELECT orders.order_id, orders.order_date,
orders.payment_type, orders.cardnumber, packages.Package_name,
orders.package_id, packages.package_price
FROM orders INNER JOIN packages ON orders.package_id = packages.Package_ID
WHERE (orders.username = #username )
#username get its value from a cookie , now how can i choose the last order only for a cookie value " Tony " for example ?
To generalize (and fix a little bit) Mitch's answer, you need to use SELECT clause embellished with TOP(#N) and ORDER BY ... DESC. Note that I use TOP(#N), not TOP N, which means you can pass it as an argument to the stored procedure and return, say, not 1 but N last orders:
CREATE STORED PROCEDURE ...
#N int
...
SELECT TOP(#N) ...
ORDER BY ... DESC
SELECT top 1
orders.order_id,
orders.order_date,
orders.payment_type,
orders.cardnumber,
packages.Package_name,
orders.package_id,
packages.package_price
FROM orders
INNER JOIN packages ON orders.package_id = packages.Package_ID
WHERE (orders.username = #username )
ORDER BY orders.order_date DESC
In fact assuming orders.order_id is an Identity column:
SELECT top 1
orders.order_id,
orders.order_date,
orders.payment_type,
orders.cardnumber,
packages.Package_name,
orders.package_id,
packages.package_price
FROM orders
INNER JOIN packages ON orders.package_id = packages.Package_ID
WHERE (orders.username = #username )
ORDER BY orders.order_id DESC

Categories

Resources