Why does this get me multiple records?

  • Trying to return just a single record for the max audit date for an agent. I thought this would do it:

    select completed, Max(auditDate) from tblAudit_AuditSchedule where agentNumber = '54321' group by auditdate, completed HAVING auditDate = MAX(auditDate)

    But I get:

    02011-12-24 00:00:00

    02012-11-07 00:00:00

    02013-02-04 07:30:00

    02013-02-13 00:00:00

    02013-02-15 00:00:00

    02013-02-20 00:00:00

    12013-02-22 00:00:00

    Not sure why the HAVING clause doesn't limit it to just the last record. Any help on what I am doing wrong would be appreciated.

    Sean

  • Hi Sean

    The MAX is applied to each group and since the auditdate column is in the GROUP BY clause you will get a group for each auditdate. This means that your HAVING clause is effectively just doing auditdate = auditdate and you will get a returned row for each.

    If you remove the auditdate from you GROUP BY clause you will get up to 2 returned rows in your query, since you also have the completed column in your GROUP BY clause and this appears to be a bit flag.

    I would say that you don't need to have a GROUP BY clause, but you will need to determine how you want the completed column handled, eg MAX or some other aggregate function.

    I suspect that you are looking for the last audit record for the agent, so you could try something like

    SELECT TOP 1 completed, auditdate

    FROM tblAudit_AuditSchedule

    WHERE agentNumber = '54321'

    ORDER BY auditdate DESC

  • SQL told me I couldn't have auditdate in the HAVING CLAUSE without it being in the GROUP BY CLAUSE which is the only reason I added it. And the MAX(auditdate) can't be in the WHERE because it is an aggregate, so I'm confused about how to do it.

  • You need to remove the auditdate from the grouping and in your HAVING clause you need max(auditdate) = xxxx (depends on what you want it to equal?)

  • infact looking again at your post you dont even need a HAVING clause. you just need the max

    select Max(auditDate) from tblAudit_AuditSchedule where agentNumber = '54321'

    if you need it per agent

    select AgentNumber, Max(auditDate) from tblAudit_AuditSchedule group by AgentNumber

    and if you need it per agent and competed status

    select completed, AgentNumber, Max(auditDate) from tblAudit_AuditSchedule group by Completed, AgentNumber

  • Sean Grebey (2/13/2013)


    Trying to return just a single record for the max audit date for an agent. I thought this would do it:

    select completed, Max(auditDate) from tblAudit_AuditSchedule where agentNumber = '54321' group by auditdate, completed HAVING auditDate = MAX(auditDate)

    But I get:

    02011-12-24 00:00:00

    02012-11-07 00:00:00

    02013-02-04 07:30:00

    02013-02-13 00:00:00

    02013-02-15 00:00:00

    02013-02-20 00:00:00

    12013-02-22 00:00:00

    Not sure why the HAVING clause doesn't limit it to just the last record. Any help on what I am doing wrong would be appreciated.

    Sean

    What are you trying to return? Without having DDL (CREATE TABLE statement), sample data (INSERT INTO statements), expected results based on sample data; all we can give you are shots in the dark.

  • Let me explain it a little bit better. Every agentNumber will have dozens of audits, so for example:

    agentNumber auditdate completed

    54321 1/1/2013 1

    54321 1/15/2013 1

    54321 2/1/2013 0

    12345 1/1/2013 1

    12345 1/8/2013 1

    12345 1/17/2013 1

    I need to know the value of completed for each agentNumber on their Max(auditdate), i.e.

    54321 0

    12345 1

    SO really all I need to get back is an agentNumber matched with if their last audit was completed. I don't even care what the last audit date is, just if it was completed or not.

  • And thanks for the help by the way. Much appreciated.

  • Animal Magic (2/13/2013)


    infact looking again at your post you dont even need a HAVING clause. you just need the max

    select Max(auditDate) from tblAudit_AuditSchedule where agentNumber = '54321'

    if you need it per agent

    select AgentNumber, Max(auditDate) from tblAudit_AuditSchedule group by AgentNumber

    and if you need it per agent and competed status

    select completed, AgentNumber, Max(auditDate) from tblAudit_AuditSchedule group by Completed, AgentNumber

    Kind of the other way around, I need the completed value by agent only for their last auditdate. Thanks for the input though.

  • There are a number of ways of doing this. Here's a few ways of writing essentially the same query.

    SELECT completed, auditdate, a.agentNumber

    FROM tblAudit_AuditSchedule a

    INNER JOIN (

    SELECT agentNumber, MAX(auditdate) maxdate

    FROM tblAudit_AuditSchedule

    GROUP BY agentNumber

    ) b ON a.agentNumber = b.agentNumber and a.auditdate = b.maxdate

    -- or

    SELECT completed, auditdate, agentNumber

    FROM tblAudit_AuditSchedule a

    WHERE auditdate = (

    SELECT MAX(auditdate)

    FROM tblAudit_AuditSchedule b

    WHERE a.agentNumber = b.agentNumber

    )

    -- or

    ;with LastAuditDatePerAgent AS (

    SELECT agentNumber, MAX(auditdate) maxdate

    FROM tblAudit_AuditSchedule

    GROUP BY agentNumber

    )

    SELECT completed, auditdate, a.agentNumber

    FROM tblAudit_AuditSchedule a

    INNER JOIN LastAuditDatePerAgent b ON a.agentNumber = b.agentNumber and a.auditdate = b.maxdate

    The previous query I put in would have worked for a single agentNumber.

  • mickyT (2/13/2013)


    There are a number of ways of doing this. Here's a few ways of writing essentially the same query.

    SELECT completed, auditdate, a.agentNumber

    FROM tblAudit_AuditSchedule a

    INNER JOIN (

    SELECT agentNumber, MAX(auditdate) maxdate

    FROM tblAudit_AuditSchedule

    GROUP BY agentNumber

    ) b ON a.agentNumber = b.agentNumber and a.auditdate = b.maxdate

    -- or

    SELECT completed, auditdate, agentNumber

    FROM tblAudit_AuditSchedule a

    WHERE auditdate = (

    SELECT MAX(auditdate)

    FROM tblAudit_AuditSchedule b

    WHERE a.agentNumber = b.agentNumber

    )

    -- or

    ;with LastAuditDatePerAgent AS (

    SELECT agentNumber, MAX(auditdate) maxdate

    FROM tblAudit_AuditSchedule

    GROUP BY agentNumber

    )

    SELECT completed, auditdate, a.agentNumber

    FROM tblAudit_AuditSchedule a

    INNER JOIN LastAuditDatePerAgent b ON a.agentNumber = b.agentNumber and a.auditdate = b.maxdate

    The previous query I put in would have worked for a single agentNumber.

    Thank you, that got me what I needed.

  • Forgive me but isn't this easily done as follows?

    ;WITH AuditDates (AgentID, AuditDate, Completed) AS (

    SELECT 54321, '2013-01-01', 1

    UNION ALL SELECT 54321,'2013-01-15', 1

    UNION ALL SELECT 54321,'2013-02-01', 0

    UNION ALL SELECT 12345,'2013-01-01', 1

    UNION ALL SELECT 12345,'2013-01-08', 1

    UNION ALL SELECT 12345,'2013-01-17', 1

    )

    SELECT AgentID, Completed

    FROM (

    SELECT AgentID, AuditDate, Completed

    ,n=ROW_NUMBER() OVER (PARTITION BY AgentID ORDER BY AuditDate DESC)

    FROM AuditDates) a

    WHERE n = 1


    My mantra: No loops! No CURSORs! No RBAR! Hoo-uh![/I]

    My thought question: Have you ever been told that your query runs too fast?

    My advice:
    INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
    The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.

    Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
    Since random numbers are too important to be left to chance, let's generate some![/url]
    Learn to understand recursive CTEs by example.[/url]
    [url url=http://www.sqlservercentral.com/articles/St

Viewing 12 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic. Login to reply