Top n records per group sql in access - sql

I am making some software that tracks the scores of a test. There are multiple users, the details of which are stored in a user table. There is then a progress table which tracks a score with the date and the user who's score it is.
I can already select the 3 most recent records for a chosen userID
SELECT TOP 3 Progress.LoginID, Progress.Score, Progress.[Date Taken]
FROM Progress
WHERE (((Progress.LoginID)=[Enter LoginID:]))
ORDER BY Progress.[Date Taken] DESC;
And I can show all the records grouped by LoginID
SELECT Progress.LoginID, Progress.Score, Progress.[Date Taken]
FROM Progress
GROUP BY Progress.LoginID, Progress.Score, Progress.[Date Taken];
I want to be able to show the 3 most recent records for each user in one query and I'm unsure of how to use nested queries/subqueries to do so.
The field names for the user table are:
LoginID
Forename
Surname
DOB
Guardian Forename
Guardian Surname
Telephone Number
The field names for the progress table are:
ProgressID
LoginID
Score
Date Taken
Any help would be appreciated.

I had a similar problem a year ago: Top 3 per group including 0
Using the same approach, this will return the latest three dates for each LoginID - you may get more than three records if there are tied dates for the same LoginID.
SELECT PR1.LogInID, PR1.Score, PR1.[Date Taken]
FROM Progress AS PR1
WHERE PR1.[Date Taken] IN (
SELECT TOP 3 PR2.[Date Taken]
FROM Progress PR2
WHERE PR2.LoginID = PR1.LoginID
ORDER BY PR2.[Date Taken] DESC
)
ORDER BY LoginID, [Date Taken]

You can put your statement without top ranking into brackets and do your ranking in a second step simple as that:
SELECT Top 3 step1.*
FROM (<YOUR STATEMENT>) AS step1
The question is older but it might be a solution though.

Related

How to get Top 2 dates for each ID in MS Access? [duplicate]

I am making some software that tracks the scores of a test. There are multiple users, the details of which are stored in a user table. There is then a progress table which tracks a score with the date and the user who's score it is.
I can already select the 3 most recent records for a chosen userID
SELECT TOP 3 Progress.LoginID, Progress.Score, Progress.[Date Taken]
FROM Progress
WHERE (((Progress.LoginID)=[Enter LoginID:]))
ORDER BY Progress.[Date Taken] DESC;
And I can show all the records grouped by LoginID
SELECT Progress.LoginID, Progress.Score, Progress.[Date Taken]
FROM Progress
GROUP BY Progress.LoginID, Progress.Score, Progress.[Date Taken];
I want to be able to show the 3 most recent records for each user in one query and I'm unsure of how to use nested queries/subqueries to do so.
The field names for the user table are:
LoginID
Forename
Surname
DOB
Guardian Forename
Guardian Surname
Telephone Number
The field names for the progress table are:
ProgressID
LoginID
Score
Date Taken
Any help would be appreciated.
I had a similar problem a year ago: Top 3 per group including 0
Using the same approach, this will return the latest three dates for each LoginID - you may get more than three records if there are tied dates for the same LoginID.
SELECT PR1.LogInID, PR1.Score, PR1.[Date Taken]
FROM Progress AS PR1
WHERE PR1.[Date Taken] IN (
SELECT TOP 3 PR2.[Date Taken]
FROM Progress PR2
WHERE PR2.LoginID = PR1.LoginID
ORDER BY PR2.[Date Taken] DESC
)
ORDER BY LoginID, [Date Taken]
You can put your statement without top ranking into brackets and do your ranking in a second step simple as that:
SELECT Top 3 step1.*
FROM (<YOUR STATEMENT>) AS step1
The question is older but it might be a solution though.

Group by and Select Distinct in SQL Server

What are the differences between the following two queries?
SELECT distinct(Invalid_Emails), [leads_id]
FROM [dbo].[InvalidEmails_stg]
ORDER BY LEADS_ID DESC
vs
select invalid_emails, max(leads_id) as id
from invalidEmails_stg
group by invalid_emails
having count(*) < 2
order by id desc
The second one gave me fewer rows than the first.
You are confused by the parentheses in the first query. They are doing nothing, so write the query as:
SELECT DISTINCT Invalid_Emails, leads_id
FROM [dbo].[InvalidEmails_stg]
ORDER BY LEADS_ID DESC;
This returns all pairs of Invalid_Emails/Leads_id that appear in the database. No matter how many times a given pair appears, it will be in the result set exactly one time.
This query:
select invalid_emails, max(leads_id) as id
from invalidEmails_stg
group by invalid_emails
having count(*) < 2
order by id desc;
Returns invalid_emails/leads_id pairs that occur only once in your data. It filters out any pairs that occur more than once.
Here is a simple example:
invalid_emails leads_id
a#b.com 1
a#b.com 1
b#c.com 2
b#c.com 3
d#e.com 1
The first query will return:
a#b.com 1
b#c.com 2
b#c.com 3
d#e.com 1
a#b.com is returned once because duplicates are removed.
The second will return:
b#c.com 2
b#c.com 3
d#e.com 1
a#b.com is not returned because it appears twice.
In first query
SELECT distinct(Invalid_Emails),[leads_id]
FROM [dbo].[InvalidEmails_stg]
ORDER BY LEADS_ID DESC
you dont Check Constraint < 2
Actually in Second query :
select invalid_emails, max(leads_id) as id
from invalidEmails_stg
group by invalid_emails
having count(*)<2
order by id desc
if result Contain two or more than row Having Count(*) Filter Your Result .
another diffrence is NULL value . if Column Invalid_Emails having Null Value Appear in First Query and Filter By group by in Next Query
The queries have similar intent, to get a invalid_emails by leads_id.
The 2nd query uses aggregate functions to only bring back the maximum leads_id, and uses a having clause to remove duplicates.

Case Statement for multiple criteria

I would like to ignore some of the results of my query as for all intents and purposes, some of the results are a duplicate, but based on the way the request was made, we need to use this hierarchy and although we are seeing different 'Company_Name' 's, we need to ignore one of the results.
Query:
SELECT
COUNT(DISTINCT A12.Company_name) AS Customer_Name_Count,
Company_Name,
SUM(Total_Sales) AS Total_Sales
FROM
some_table AS A12
GROUP BY
2
ORDER BY
3 ASC, 2 ASC
This code omits half a doze joins and where statements that are not germane to this question.
Results:
Customer_Name_Count Company_Name Total_Sales
-------------------------------------------------------------
1 3 Blockbuster 1,000
2 6 Jimmy's Bar 1,500
3 6 Jimmy's Restaurant 1,500
4 9 Impala Hotel 2,000
5 12 Sports Drink 2,500
In the above set, we can see that numbers 2 & 3 have the same count and the same total_sales number and similar company names. Is there a way to create a case statement that takes these 3 factors into consideration and then drops one or the other for Jimmy's enterprises? The other issue is that this has to be variable as there are other instances where this happens. And I would only want this to happen if the count and sales number match each other with a similar name in the company name.
Desired result:
Customer_Name_Count Company_Name Total_Sales
--------------------------------------------------------------
1 3 Blockbuster 1,000
2 6 Jimmy's Bar 1,500
3 9 Impala Hotel 2,000
4 12 Sports Drink 2,500
Looks like other answers are accurate based on assumption that Company_IDs are the same for both.
If Company_IDs are different for both Jimmy's Bar and Jimmy's Restaurant then you can use something like this. I suggest you get functional users involved and do some data clean-up else you'll be maintaining this every time this issue arise:
SELECT
COUNT(DISTINCT CASE
WHEN A12.Company_Name = 'Name2' THEN 'Name1'
ELSE A12.Company_Name
END) AS Customer_Name_Count
,CASE
WHEN A12.Company_Name = 'Name2' THEN 'Name1'
ELSE A12.Company_Name
END AS Company_Name
,SUM(A12.Total_Sales) AS Total_Sales
FROM some_table er
GROUP BY CASE
WHEN A12.Company_Name = 'Name2' THEN 'Name1'
ELSE A12.Company_Name
END
Your problem is that the joins you are using are multiplying the number of rows. Somewhere along the way, multiple names are associated with exactly the same entity (which is why the numbers are the same). You can fix this by aggregating by the right id:
SELECT COUNT(DISTINCT A12.Company_name) AS Customer_Name_Count,
MAX(Company_Name) as Company_Name,
SUM(Total_Sales) AS Total_Sales
FROM some_table AS A12
GROUP BY Company_id -- I'm guessing the column is something like this
ORDER BY 3 ASC, 2 ASC;
This might actually overstate the sales (I don't know). Better would be fixing the join so it only returned one name. One possibility is that it is a type-2 dimension, meaning that there is a time component for values that change over time. You may need to restrict the join to a single time period.
You need to have function to return a common name for the companies and then use DISTINCT:
SELECT DISTINCT
Customer_Name_Count,
dbo.GetCommonName(Company_Name) as Company_Name,
Total_Sales
FROM dbo.theTable
You can try to use ROW_NUMBER with window function to make row number by Customer_Name_Count and Total_Sales then get rn = 1
SELECT * FROM (
SELECT *,ROW_NUMBER() OVER(PARTITION BY Customer_Name_Count,Total_Sales ORDER BY Company_Name) rn
FROM (
SELECT
COUNT(DISTINCT A12.Company_name) AS Customer_Name_Count,
Company_Name,
SUM(Total_Sales) AS Total_Sales
FROM
some_table AS A12
GROUP BY
Company_Name
)t1
)t1
WHERE rn = 1

find column which have biggest number of approved transactions sql server

I need to find the Filiyal which have biggest number of approved transactions.
I've try like this:
select max(Filiyal)
from Transactions
where Status = 'Approved'
But it gives me wrong result. Where I'm wrong?
Here is my table:
Filiyal | Status
-------------------------
Bank1 | Approved
Bank2 | Not Approved
Bank1 | Approved
Bank4 | Approved
Your query as written would give you the largest value of Filiyal (alphabetically) from the set of banks that have an approved status. If what you are looking to find is the Filiyal with the most approved records, then you need to have something that counts the records that are approved.
select top 1 Filiyal
from Transactions
where Status = 'Approved'
group by Filiyal
order by COUNT(Filiyal) desc
The group by clause returns a record for each Filiyal and the order by orders them by the number of records for each value that has 'Approved' as a status. The "top 1" will return only the record with the most approved records. In case of a tie though you will get one of them randomly.
You can try with order by desc and top 1:
select top 1 Filiyal
, count(*) as total_approved
from Transactions
where status = 'Approved'
group by Filiyal
order by total_approved desc
P.S. Doesn't cover cases when multiple Filiyals can have the same amount of maximum total_approved.

How to pull top 3 per group in access SQL

I'm attempting to pull the top three performers in a group. I'm not sure how to do this in Access, what I need is for each group to pull the top three.
http://allenbrowne.com/subquery-01.html
I've tried these subqueries however they give me an error message. Is there a better way to do this?
It's for keyword performance.
Table fields are
Keyword | Campaign | Ad Group | Clicks | Impressions
I want the top 3 for clicks for each ad group. I want top 3 impressions too but once I know how to do clicks I'll be able to modify it as needed.
I'm trying to get like
Ad Group 1 - First Top
Ad Group 1 - Second Top
Ad Group 1 - Third Top
Ad Group 2 - First Top
Ad Group 2 - Second Top
Ad Group 2 - Third Top
etc
SELECT KeywordReport.ID, KeywordReport.Campaign, KeywordReport.[Ad group], KeywordReport.Keyword, KeywordReport.Clicks, KeywordReport.Impressions, KeywordReport.[Avg CPC], KeywordReport.[Search Impr share], KeywordReport.Cost
FROM KeywordReport
WHERE (((KeywordReport.ID) In (SELECT TOP 3 ID
FROM KeywordReport AS Dupe
WHERE Dupe.ID = KeywordReport.ID
ORDER BY Dupe.Clicks DESC)))
ORDER BY KeywordReport.[Ad group];
It is returning all entries not the top 3.
I think you were close:
WHERE (((KeywordReport.ID) In (SELECT TOP 3 ID
FROM KeywordReport AS Dupe
WHERE Dupe.[Ad Group] = KeywordReport.[Ad Group] <-- change this line
ORDER BY Dupe.Clicks DESC)))