473,395 Members | 1,343 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

SQL id of record at which maximum occurs, by group

Hey all,

I have a question that ought to be simple but has given me headaches for a while.

I have a table with contact email addresses, say.

Expand|Select|Wrap|Line Numbers
  1. T
  2. ID ContID Priority Emailaddress
  3. ----------------------------------------------
  4. 1     1         10     email1@contact1.fi
  5. 2     1          7      email2@contact1.fi
  6. 3     2          9      email1@contact2.fi
  7. 4     2          8          ....
  8. ...

Now, the main question:
I want to create a query that gives me
- the ID-number of the records
- that correspond to the highest-priority emailaddress
- of each contact.


I then want to use this query-result of ID-numbers to INNER JOIN to table T (or actually a table with more fields) to get the fields I'm interested in; the joining being done on the ID-fields, something like:
Expand|Select|Wrap|Line Numbers
  1. SELECT t1.ContID, t1.Emailaddress
  2. FROM t AS t1
  3. INNER JOIN
  4. (
  5.   SELECT "the ID with the highest priority"
  6.   FROM t AS t2
  7.   GROUP BY t2.ContID
  8. ) AS t3 ON t3.ID = t1.ID
  9.  
The problem is that it's not possible to get "the ID of the record with the highest-priority email for each contact" with SQL- at least, none that I know of.
(It IS possible to "get the maximum ID of the records for each contact" or "get the maximum priority for each contact", as shown below.)


I did think of some solutions, but none that I like.


I could do the JOINing on other fields, something like
Expand|Select|Wrap|Line Numbers
  1. SELECT t1.ContID, t1.Emailaddress
  2. FROM t AS t1
  3. INNER JOIN
  4. (
  5.   SELECT t2.ContID, MAX(t2.priority) AS MaxPrio
  6.   FROM t AS t2
  7.   GROUP BY t2.ContID
  8. ) AS t3 ON t3.ContID = t1.ContID AND t3.MaxPrio = t1.Priority
  9.  
but this has the disadvantage of needing to join on multiple fields that may not necessarily be unique (there may be a contact with several emailaddresses with the same priority) - I want to get only one record per contact, maximum.

This could multiplicity can be solved by GROUPing also in the outer query, like this:
Expand|Select|Wrap|Line Numbers
  1. SELECT t1.ContID, FIRST(t1.Emailaddress) AS FirstEmail
  2. FROM t AS t1
  3. INNER JOIN
  4. (
  5.   SELECT t2.ContID, MAX(t2.priority) AS MaxPrio
  6.   FROM t AS t2
  7.   GROUP BY t2.ContID
  8. ) AS t3 ON t3.ContID = t1.ContID AND t3.MaxPrio = t1.Priority
  9. GROUP BY t1.ContID
  10.  
but also this solution has the disadvantage of JOINing on multiple non-unique fields.
It also makes it difficult to include additional conditions: if the table has a yes/no field 'IsWork', and I want to get the highest-priority work-email, I need to include the 'WHERE IsWork = TRUE' line in both the inner and the outer query.

It's just not pretty!


Another possible solution is
Expand|Select|Wrap|Line Numbers
  1. SELECT t1.contID, t1.EmailAddress
  2. FROM t AS t1 
  3. INNER JOIN 
  4. (
  5. SELECT t2.ID, COUNT(*) 
  6.   FROM t AS t2
  7.   INNER JOIN t AS t3 ON (t2.ContID = t3.ContID) AND ((t2.priority < t3.priority) OR (t2.priority = t3.priority AND t2.ID <  t3.ID)) 
  8.   GROUP BY t2.ID
  9.   HAVING COUNT(*)  =1
  10.   )  AS t4 ON t4.ID =t4.ID
  11. ORDER BY t1.contID
(adjusted from http://rickosborne.org/blog/index.ph...grouped-query/, with the "(t2.ContID = t3.ContID) AND ((t2.priority < t3.priority) OR (t2.priority = t3.priority AND t2.ID < t3.ID)) " line to force a consistent ordering upon the recordset, even if a contact has several emailaddresses with the same priority.)

I like this solution; all the selecting of the correct ID numbers is done isolatedly in the inner query, and additional conditions can be included here without needing to change something in the outer query.

But it's really slow! :(

Can someone help me out? Suggestions for an adequete, pretty, fast query to do the job?

Thanks!!

Sjaak

if wanted i can prepare an Access file, of course.
I'm using access 2007, SQL ANSI-92
Nov 23 '09 #1

✓ answered by NeoPa

@SjaakBanaan
Thank you. I had to work this out some while back, but having discovered this approach I missed the (generally more flexible) SQL approach until much later.

Your point about the joining is correct (I discovered after a bit of a think through). The SQL need not even return the ContID field in fact :
Expand|Select|Wrap|Line Numbers
  1. SELECT T.ContID,
  2.        T.Emailaddress
  3. FROM   T INNER JOIN
  4.        (
  5.     SELECT   Val(Mid(Max(Format([Priority],'0000') & T.ID),5)) AS ID
  6.     FROM     T
  7.     GROUP BY [ContID]
  8.        ) AS subT ON T.ID=subT.ID
@SjaakBanaan
Apologies for the incorrect order. I'm afraid I did it off the top of my head rather than going through any testing cycle.

As far as the data is concerned, as your otherwise very thorough OP didn't mention how you wanted to handle multiple results I rather assumed that this was not possible in your scenario. As I can see no way, using aggregation, of selecting one above any other I think this approach can be considered a dud.

4 3931
Delerna
1,134 Expert 1GB
I think you have all SQL possibilities pretty much covered but am interested to see alternatives if any.
Nov 24 '09 #2
NeoPa
32,556 Expert Mod 16PB
You would have thought that something like this would have been built into the SQL standards. It wasn't as far as I can see :(

I would use either of two methods :
  1. Expand|Select|Wrap|Line Numbers
    1. SELECT T.ContID,
    2.        T.Emailaddress
    3. FROM   T INNER JOIN
    4.        (
    5.     SELECT   [ContID]
    6.              Val(Mid(Max(Format([Priority],'0000') & T.ID),5)) AS ID
    7.     FROM     T
    8.     GROUP BY [ContID]
    9.        ) AS subT ON T.ContID=subT.ContID
  2. Expand|Select|Wrap|Line Numbers
    1. SELECT [ContID],
    2.        [Emailaddress]
    3. FROM   T AS T1
    4. WHERE  [Priority] In
    5.        (
    6.     SELECT   Max([Priority]) AS Data
    7.     FROM     T AS T2
    8.     GROUP BY [ContID]
    9.     WHERE    T2.ContID=T1.ContID
    10.        )
Nov 24 '09 #3
NeoPa, thanks for your suggestions

Your first is quite creative :) (There's a typo in that the joining should be on the ID-fields, btw)

The second one unfortunately doesnt work (even after reversing the WHERE and GROUP BY lines), as it lists all records with the same (highest) priority of a contact, not just one: if a contact has 2 emailaddresses both with prio=10 then both will show up in the final result.

I'll think I'll go for the first, should be pretty fast and is quite readable. Unless someone else has a sudden great brain wave, of course!

Sjaak
Nov 24 '09 #4
NeoPa
32,556 Expert Mod 16PB
@SjaakBanaan
Thank you. I had to work this out some while back, but having discovered this approach I missed the (generally more flexible) SQL approach until much later.

Your point about the joining is correct (I discovered after a bit of a think through). The SQL need not even return the ContID field in fact :
Expand|Select|Wrap|Line Numbers
  1. SELECT T.ContID,
  2.        T.Emailaddress
  3. FROM   T INNER JOIN
  4.        (
  5.     SELECT   Val(Mid(Max(Format([Priority],'0000') & T.ID),5)) AS ID
  6.     FROM     T
  7.     GROUP BY [ContID]
  8.        ) AS subT ON T.ID=subT.ID
@SjaakBanaan
Apologies for the incorrect order. I'm afraid I did it off the top of my head rather than going through any testing cycle.

As far as the data is concerned, as your otherwise very thorough OP didn't mention how you wanted to handle multiple results I rather assumed that this was not possible in your scenario. As I can see no way, using aggregation, of selecting one above any other I think this approach can be considered a dud.
Nov 25 '09 #5

Sign in to post your reply or Sign up for a free account.

Similar topics

17
by: John Bentley | last post by:
John Bentley: INTRO The phrase "decimal number" within a programming context is ambiguous. It could refer to the decimal datatype or the related but separate concept of a generic decimal number....
6
by: Hari Om | last post by:
Here are the details of my error log files: I execute the command and get following message at console: ---------------------------------------------------------------------- ../sqlldr...
5
by: Andrew | last post by:
Hi All, Have come across something weird and am after some help. Say i run this query where rec_id is a column of table arlhrl, select * from arlhrl where rec_id >= 14260 This returns to...
8
by: Zlatko Matić | last post by:
There is a form (single form) and a combobox. I want that current record of the form is adjusted according to selected value in the combobox. Cuurrent record should be the same as the value in the...
12
by: Wadim Grasza | last post by:
I want to store and display (on a form or a report) multiple pictures per record in an access database. The pictures are not stored within the database. They are stored as files and the database...
4
by: Tintin | last post by:
Hi everyone, I have a problem which I think you people can solve. I am having problems. I have a table which stores surveys submitted. We have multiple types of surveys, hence a person can have...
23
by: Gerrit | last post by:
Hi all, I'm getting an OutOfMemoryException when I initialize a byte array in C# like this: Byte test = new Byte; I'm using ASP.NET 2.0. In ASP.Net 1.1 it works fine. So what am I doing...
5
by: payffl | last post by:
My users are running Access '03. They have a database with a form that allows them to enter new records. Frequently they will move to a new record and not enter any information. This prevents...
16
by: google | last post by:
In a continuous form the following code is under a button in the form header. In Access 2003 and earlier, this goes to a new record, then adds relevant data to that new record. DoCmd.GoToRecord...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.