MS Access - Aggregate functions and max - ms-access

I have this query, where I am trying to get max age of a retail store seller(There's multiple towns), and show multiple if there's multiple people with the same (max)age. I am using Microsoft Access 2010. Here is the query:
SELECT Linnad.Linn, Myyjad.Nimi, Max(Myyjad.Vanus) As Vanus
FROM Linnad INNER JOIN Myyjad ON Linnad.LinnID = Myyjad.LinnID
GROUP BY Linnad.Linn, Myyjad.Nimi
ORDER BY Linnad.Linn;
The problem is, it seems to ignore the MAX, and just shows all of the values, and I can't remove the group by Myyjad.Nimi, because it gives me an error that aggregate function not included for Myyjad.Nimi.
And the output should be:
Town - Name - Max(Age)
Also, Linn = Town, Nimi = Name and the Vanus = Age.

I think this may be what your looking for:
SELECT L.Linn, M.Nimi, M.Vanus
FROM Linnad As L,
(
SELECT M2.LinnID, M2.Nimi, M2.Vanus
FROM Myyjad As M2
WHERE M2.Vanus = (SELECT Max(Z.Vanus) FROM Myyjad As Z WHERE Z.LinnID = M2.LinnID)
) As M
WHERE M.LinnID = L.LinnID
This performs a sub-select to get a list of the Linn ID's with all Nimi's showing the maximum Vanus, then we link this sub-select back to the Linnad table via the LinnID.

I think you want:
SELECT Linnad.Linn, Myyjad.Nimi, Myyjad.Vanus
FROM Linnad INNER JOIN Myyjad ON Linnad.LinnID = Myyjad.LinnID
WHERE DateValue(Myyjad.Vanus)
= (SELECT Max(DateValue(Myyjad.Vanus)) FROM Myyjad)
ORDER BY Linnad.Linn
Top N per group:
SELECT Linnad.Linn, Myyjad.Nimi, Myyjad.Vanus
FROM FROM Linnad INNER JOIN Myyjad ON Linnad.LinnID = Myyjad.LinnID
WHERE Myyjad.ID In (
SELECT Top 1 m.ID
FROM Myyjad m
WHERE m.LinnID=Linnad.ID
ORDER BY m.Vanus Desc, m.ID)

Grouping by Linn (town) and Nimi (name) tells the db engine to give you one row for each combination of town and name, and show you the maximum Vanus (age) for each of those combinations. And logically, that's not what you want. You want the name of each person whose age is the same as the maximum age in that town.
First verify you can retrieve the max age for each LinnID.
SELECT
LinnID,
Max(Vanus) As MaxOfVanus
FROM
Myyjad
GROUP BY LinnID;
If that works, you can save it as "qryTownAge", then use it in another query where you join it (on LinnID) with Linnad. That will allow you to retrieve the matching Linn.
SELECT l.LinnID, l.Linn, q.MaxOfVanus
FROM
Linnad AS l
INNER JOIN qryTownAge AS q
ON l.LinnID = q.LinnID
ORDER BY l.Linn;
If that works, save it as qryTownAge2. Then try this query.
SELECT q.Linn, q.MaxOfVanus, m.Nimi
FROM
qryTownAge2 AS q
INNER JOIN Myyjad AS m
ON (
m.LinnID = q.LinnID
AND m.Vanus = q.MaxOfVanus
)
ORDER BY q.Linn;
If that all works, you could create a single query which does it all. However, doing it step by step should help us pinpoint errors.

Related

Select from SQL database information with newest revisions

I coding web app for my client and have issue with selecting from database raports with newest revisions.
SELECT
raports.*,
r1.*,
users.*,
(SELECT COUNT(*) FROM changes WHERE changes.changes_raports_id = raports.raports_id) as changes,
(SELECT changes.changes_date FROM changes WHERE changes.changes_raports_id = raports.raports_id ORDER BY changes.changes_date DESC LIMIT 1) as last_change,
(SUM(injuries.injuries_min_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as min,
(SUM(injuries.injuries_max_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as max
FROM raports
LEFT JOIN users
ON users.users_id = raports.raports_users_id
LEFT JOIN changes
ON changes.changes_raports_id = raports.raports_id
LEFT JOIN raports_to_changes r1
ON r1.raports_to_changes_raports_id = raports.raports_id
LEFT JOIN injuries_to_raports
ON injuries_to_raports.injuries_to_raports_raports_id = r1.raports_to_changes_raports_id
LEFT JOIN injuries
ON injuries_to_raports.injuries_to_raports_injuries_id = injuries.injuries_id
WHERE r1.raports_to_changes_changes_id = (SELECT max(raports_to_changes_changes_id) FROM raports_to_changes r2 WHERE r2.raports_to_changes_raports_id = r1.raports_to_changes_raports_id)
GROUP BY raports.raports_id ORDER BY raports.raports_id ASC;
In columns max and min i have not correct average from injuries. When i checked it and count all injuries i had 36 when true number is 2 but i have 18 revisions. So is logic that i have looped COUNT with all revisions but i want only the newest
I try changing WHERE statements and more LEFT JOINs but nothing helped.
Could someone fixed that code?
Thank you in advanced
Based on the clues revealed by your queries, the data model may look like this:
The select list shows that you need:
users information of a reports_id
aggregated injuries_min_procent and injuries_max_procent at raports_id level. (see cte_raport_injuries)
number of changes of a raports_id (see cte_raport_changes)
the last change_date of a raports_id (see cte_raport_changes)
I'm not sure about the need for raports_of_changes based on information revealed in the question, so I'm going to ignore it for now.
with cte_raport_injuries as (
select r.raports_id,
sum(i.injuries_min_procent) / count(*) as injuries_min_procent,
sum(i.injuries_max_procent) / count(*) as injuries_max_procent
from raports r
join injuries_to_raports ir
on r.raports_id = ir.injuries_to_raports_raports_id
join injuries i
on ir.injuries_to_raports_injuries_id = i.injuries_id
group by r.raports_id),
cte_raport_changes as (
select r.raports_id,
count(c.changes_id) as changes,
max(c.changes_date) as last_change
from raports r
join changes c
on r.raports_id = c.changes_raports_id
group by r.raports_id)
select u.users_id,
r.raports_id,
ri.injuries_min_procent,
ri.injuries_max_procent,
rc.changes,
rc.last_change
from raports r
join users u
on r.raports_users_id = u.users_id
join cte_raport_injuries ri
on r.raports_id = ri.raports_id
join cte_raport_changes rc
on r.raports_id = rc.raports_id;
The result looks like this:
users_id|raports_id|injuries_min_procent|injuries_max_procent|changes|last_change|
--------+----------+--------------------+--------------------+-------+-----------+
1| 11| 15.0000| 25.0000| 2| 2022-12-02|
So my question for you is what's in reports_to_changes that you need and what's its relationship between others? For further involvement from the community, you may want to share the following information in text format:
DDLs of each tables (primary key, foreign key, column names & data types)
Some representable sample data and basic business rules
Expected output

mysq: Using the same subquery in FROM and WHERE clause without repeating it?

I need to select data with all the cars that have been the longest in a workshop. So if the max of days is 16 and there are multiple cars with 16 days I need all of them.
My models are like this
Car: id_car, mat_car, mod_car, color, type
Period: id_per, date_ini, date_fin
Relacion4: id_car, id_per
This method works but is there a way to do it with without repeating the same subquery in FOR and in WHERE clause as well?
select * from (
select Car.mat_car, mod_car, color, type, date_ini, date_fin, datediff(date_fin, date_ini) daysInWorkshop from Car
inner join Relacion4 on Car.mat_car = Relacion4.mat_car
inner join Period on Relacion4.id_per = Periodo.id_per
) as CarWithDurr
where daysInWorkshop = (
select max(daysInWorkshop) from (
select datediff(date_fin, date_ini) daysInWorkshop from Car
inner join Relacion4 on Car.mat_car = Relacion4.mat_car
inner join Period on Relacion4.id_per = Period.id_per
) as CarWithDurr
);
I think you can slim down a bit.
select Car.mat_car, mod_car, color, type,
date_ini, date_fin, datediff(date_fin, date_ini) daysInWorkshop
from Car
inner join Relacion4 on Car.mat_car = Relacion4.mat_car
inner join Period on Relacion4.id_per = Periodo.id_per
where datediff(date_fin, date_ini) =
(
select max(datediff(date_fin, date_ini))
from Period
)
;
If this doesn't work as you wish please add sample data and expected output as text to the question.
btw WHERE DO YOU GET Relacion4.mat_car it isn't in your published table!! AND Periodo is misspelled.

SELECT group by twice

I'm not strong in DB at all and I need your help.
I need SQL request with GROUP by twice.
Example of my data in table
<table border="1" style="border-collapse:collapse">
<tr><th>id</th><th>market_id</th><th>price</th><th>low</th><th>high</th><th>symbol</th><th>created_at</th></tr>
<tr><td>1</td><td>1</td><td>5773.8</td><td>5685</td><td>6020</td><td>btcusd</td><td>2017-10-27 16:46:10</td></tr>
<tr><td>2</td><td>1</td><td>0.4274</td><td>0.39</td><td>0.43983</td><td>iotusd</td><td>2017-10-27 16:46:11</td></tr>
<tr><td>3</td><td>1</td><td>0.20026</td><td>0.1986</td><td>0.20352</td><td>xrpusd</td><td>2017-10-27 16:46:12</td></tr>
<tr><td>4</td><td>2</td><td>5771</td><td>5685</td><td>6020</td><td>btcusd</td><td>2017-10-27 16:46:18</td></tr>
<tr><td>5</td><td>2</td><td>0.4274</td><td>0.39</td><td>0.43983</td><td>iotusd</td><td>2017-10-27 16:46:18</td></tr>
<tr><td>6</td><td>2</td><td>0.20026</td><td>0.1986</td><td>0.20352</td><td>xrpusd</td><td>2017-10-27 16:46:19</td></tr>
<tr><td>7</td><td>1</td><td>5773.1</td><td>5685</td><td>6020</td><td>btcusd</td><td>2017-10-27 16:46:25</td></tr>
<tr><td>8</td><td>1</td><td>0.4274</td><td>0.39</td><td>0.43983</td><td>iotusd</td><td>2017-10-27 16:46:25</td></tr>
<tr><td>9</td><td>1</td><td>0.20026</td><td>0.1986</td><td>0.20352</td><td>xrpusd</td><td>2017-10-27 16:46:26</td></tr>
<tr><td>10</td><td>2</td><td>5773.1</td><td>5685</td><td>6020</td><td>btcusd</td><td>2017-10-27 16:46:32</td></tr>
<tr><td>11</td><td>2</td><td>0.42741</td><td>0.39</td><td>0.43983</td><td>iotusd</td><td>2017-10-27 16:46:32</td></tr>
<tr><td>12</td><td>2</td><td>0.20026</td><td>0.1986</td><td>0.20352</td><td>xrpusd</td><td>2017-10-27 16:46:33</td></tr></table>
I would like to get latest data for every market_id and symbol
That's mean I need somethind like that in the end :
- id market_id symbol
- 7 1 btcusd
- 8 1 iotusd
- 9 1 xrpusd
- 10 2 btcusd
- 11 2 iotusd
- 12 2 xrpusd
Really need help, a little bit blocked.
You are almost there. Try this
SELECT c.*
FROM CRYPTO as C
JOIN (
SELECT market_id, symbol, MAX(id) as maxid
FROM CRYPTO
GROUP BY market_id, symbol
) AS C2
ON C2.maxid = C.id and C.market_id = c2.market_id and c.symbol = c2.symbol
Along these lines...
SELECT MAX(id), market_id, symbol
FROM crypto
GROUP BY market_id, symbol
Here's my comment stated as SQL.
SELECT A.ID, A.MarketID, A.Symbol, A.Price, A.Low, A.High
FROM CRYPTO A
INNER JOIN (SELECT max(Created_at) MCA, Market_ID, Symbol
FROM crypto
GROUP BY Market_ID, Symbol) B
on A.Created_At = B.MCA
and A.market_ID = B.Market_ID
and A.Symbol = B.Symbol
What this does:
The derived table (aliased B) generates 1 line for each market_ID and symbol having the max created_at time. It then uses this derived table set to join back to the base set (aliased A) to limit the data to just those having the max created_at. this allows us to show the whole record from A for each unique market_Id and symbol; but only for records having the max created_at.
Other engines would allow you to use a cross apply or an analytic to obtain the desired results.
I tried these requests
SELECT * FROM CRYPTO as C3
JOIN (
SELECT MAX(id) as max
FROM CRYPTO as C1
GROUP BY symbol
) AS C2
ON C2.max = C3.id
SELECT M.id, M.name, R.symbol FROM MARKET AS M
JOIN (
SELECT DISTINCT C.symbol, C.market_id
FROM CRYPTO as C
) as R
ON M.id = R.market_id
But finally I did not find the good combination.

mysql query group by totals

I am using the following query to retrieve the number of events per state from 2 tables that are linked by a userID.
SELECT state,COUNT(*) AS num
FROM tableUserInfo
WHERE userID IN (SELECT userID
FROM tableEvents
WHERE conditionOne = 1
AND conditionTwo = 2)
GROUP BY state
This query works correctly. My problem is that not all states have user entries, and I need the query to return 0 for those. I was wondering if there was a method such as joining or using an in clause, that would included a set of all states, making the query return 0 for any that didn't have entries in tableEvents?
Do you have a list of states? If not then this would give a list of all the states your database knows about:
SELECT DISTINCT state FROM tableUserInfo
....and enclosing this in brackets it can be dropped in place in the query below:
SELECT s.state, IFNULL(cnt, 0) AS num
FROM list_of_states s
LEFT JOIN (
SELECT state,COUNT(*) AS cnt
FROM tableUserInfo ui
INNER JOIN tableEvents te
ON ui.userId=te.userId
WHERE conditionOne = 1
AND conditionTwo = 2
GROUP BY state
) u
ON s.state=u.state;
Although in the absence of "list_of_states" it would be more efficient to do this:
SELECT ui.state, SUM(IF(te.userId IS NULL, 0, 1)) AS cnt
FROM tableUserInfo ui
LEFT JOIN tableEvents te
ON ui.userId=te.userId
AND te.conditionOne = 1
AND te.conditionTwo = 2
GROUP BY state;
As #raymond-nijland suggested you can use Left Join to include all states.
SELECT tableUserInfo.state,COUNT(tableUserInfo.*) AS num
FROM tableUserInfo Left Join tableEvents on tableUserInfo.userID = tableEvents.userID
WHERE tableEvents.conditionOne = 1 AND tableEvents.conditionTwo = 2
GROUP BY state

SQL query creation

I have to do a query without using views that displays the automobile brand that has the maximum number of cars that have a single owner.
that's the table that I have
CAR(idcar, brand, name, year_p)
OWNER(idowner,name, b_date)
PROPERTY(idcar,idowner,date_b, date_s)
That's what I was writing..
SELECT Car.brand, COUNT(PROPERTY.idowner) as con
FROM PROPERTY JOIN CAR ON Car.idcar=Property.idcar
GROUP BY Car.brand
ORDER BY con ASC
LIMIT 1;
It's ok? what I can do to improve it?
That's how it should work
CAR
-----------------
1|FIAT|test1|2000
2|Alfa|test2|2011
3|FIAT|test3|2001
4|Alfa|test4|2006
5|Alfa|test5|2004
OWNER
-----------
1|John|1990
2|Jack|1980
3|Sam |1991
4|Rick|1980
5|Cris|1993
6|Holm|1992
PROPERTY
-------------
1|1|2000|2000
2|1|2001|2003
3|2|2000|2004
1|3|2002|2005
4|4|2004|2006
5|6|2003|2008
2|5|2001|2009
So the query should return Alfa because I've 3 people that have only one car and those 3 people have one alfa ( so 3 alfa). It can't be FIAT because I only have 2 people with only one car that is a FIAT(so 2 FIAT). The OWNER n1 is excluded because he has 2 car
I think you were on the right path with your query, it's only need a little modification...
First if you want to select brand with most owner than you should order them in descending order so the max will be at the top... And second you need to add WHERE clause which will exclude all owner that have more then one car...
It should look like this:
SELECT c.brand, COUNT(p.idowner) as con
FROM PROPERTY p
JOIN CAR c
ON c.idcar=p.idcar
WHERE p.idowner NOT IN (SELECT idowner
FROM (SELECT idowner, COUNT(idowner) as c
FROM PROPERTY
GROUP BY idowner) x
WHERE c > 1)
GROUP BY c.brand
ORDER BY con DESC
LIMIT 1;
Here is the SQL Fiddle to take a look how it's work...
GL!
This is too long for a comment.
Your query is not correct. It returns the brands that have the most properties for its cars. That may or may not have to do with the number of owners. I'm sure there's a relationship of some sort ("no properties" --> "no owners" and vice versa).
In any case, I don't know what you mean by "the maximum number of cars that have a single owner". You should edit your question with sample data and desired results. A SQL Fiddle would also be helpful.
--CTE to Get single owner
WITH CTEsingleowner(ct, idowner)
AS (SELECT Count(1) AS ct,
idowner
FROM property WITH(nolock)
GROUP BY idowner
HAVING Count(1) = 1)
-- Select brand with maximum number of single owner
-- with ties is used to resolve confilict more than one record set returned
SELECT TOP (1) WITH ties Count(1) AS cnt,
brand
FROM CTEsingleowner ct
JOIN property p WITH(nolock)
ON p.idowner = ct.idowner
JOIN car c WITH(nolock)
ON ( c.idcar = p.idcar )
GROUP BY brand
ORDER BY cnt DESC ;
--CTE to Get single owner
WITH CTEsingleowner(ct, idowner)
AS (SELECT Count(1) AS ct,idowner
FROM property WITH(nolock)
GROUP BY idowner
HAVING Count(1) = 1)
-- Select brand with maximum number of single owner
-- with ties is used to resolve conflict more than one rows returned
SELECT TOP (1) WITH ties Count(1) AS cnt, brand
FROM CTEsingleowner ct
JOIN property p WITH(nolock)
ON p.idowner = ct.idowner
JOIN car c WITH(nolock)
ON ( c.idcar = p.idcar )
GROUP BY brand
ORDER BY cnt DESC ;