Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Database & SysAdmin
  3. Database
  4. Select first entries in a table matching given criteria

Select first entries in a table matching given criteria

Scheduled Pinned Locked Moved Database
databasesaleshelpquestion
9 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    Dewald
    wrote on last edited by
    #1

    Here's a problem I've come up against on a number of occasions and I have so far failed to come up with an elegant query to deal with it. I feel the GROUP BY clause might have to come into play but I don't really know how. Let's say I have a table called Orders containing information on orders received from customers. The table has the following columns: CustomerID (INT) OrderPlaced (DATETIME) ProductID (INT) AmountOrdered (INT) So I want to write a query that will show me the information from this table on the first order for a specific product (let's say id 123) received by every customer. The following query will get me almost there:

    SELECT CustomerID, MIN(OrderPlaced)
    FROM Orders
    WHERE ProductID = 123

    It only gets me almost there though because notice how the AmountOrdered field is missing from the query and unless it's part of an aggregate function I can't add it. I can add it with a subquery but that is where the query loses its elegance rapidly, especially considering that the real world tables I'm dealing with usually have more than just one or two extra columns. Any ideas?

    M 1 Reply Last reply
    0
    • D Dewald

      Here's a problem I've come up against on a number of occasions and I have so far failed to come up with an elegant query to deal with it. I feel the GROUP BY clause might have to come into play but I don't really know how. Let's say I have a table called Orders containing information on orders received from customers. The table has the following columns: CustomerID (INT) OrderPlaced (DATETIME) ProductID (INT) AmountOrdered (INT) So I want to write a query that will show me the information from this table on the first order for a specific product (let's say id 123) received by every customer. The following query will get me almost there:

      SELECT CustomerID, MIN(OrderPlaced)
      FROM Orders
      WHERE ProductID = 123

      It only gets me almost there though because notice how the AmountOrdered field is missing from the query and unless it's part of an aggregate function I can't add it. I can add it with a subquery but that is where the query loses its elegance rapidly, especially considering that the real world tables I'm dealing with usually have more than just one or two extra columns. Any ideas?

      M Offline
      M Offline
      Mycroft Holmes
      wrote on last edited by
      #2

      Almost all your solutions using an aggregate will require a sub query, there is nothing inelegant about using one! You can also look into ROW_NUMBER and PARTITION. Never underestimate the power of human stupidity RAH

      D 1 Reply Last reply
      0
      • M Mycroft Holmes

        Almost all your solutions using an aggregate will require a sub query, there is nothing inelegant about using one! You can also look into ROW_NUMBER and PARTITION. Never underestimate the power of human stupidity RAH

        D Offline
        D Offline
        Dewald
        wrote on last edited by
        #3

        Thanks. I've been shying away from Over(), ROW_NUMBER and Partition By because they're rather Microsoft specific. I agree, generally there's nothing inelegant about using a subquery but in this particular case it is anything but elegant. Consider the table in my example and let's say there are a few more columns: ContractID (INT) OrderSource (INT) AgentID (INT) ProvinceID (INT) DeliveryMethod (INT) So, in order to get what I want, using GROUP BY and subqueries, it would end up looking something like this:

        SELECT
        CustomerID,
        MIN(OrderPlaced),
        --(Some or other subquery to get the value for AmountOrdered),
        --(Some or other subquery to get the value for ContractID),
        --(Some or other subquery to get the value for OrderSource),
        --(Some or other subquery to get the value for AgentID),
        --(Some or other subquery to get the value for ProvinceID),
        --(Some or other subquery to get the value for DeliveryMethod)
        FROM Orders
        WHERE ProductID = 123
        GROUP BY CustomerID

        I'm sure you'll agree that the above query is pretty much the antithesis of elegance.

        M 1 Reply Last reply
        0
        • D Dewald

          Thanks. I've been shying away from Over(), ROW_NUMBER and Partition By because they're rather Microsoft specific. I agree, generally there's nothing inelegant about using a subquery but in this particular case it is anything but elegant. Consider the table in my example and let's say there are a few more columns: ContractID (INT) OrderSource (INT) AgentID (INT) ProvinceID (INT) DeliveryMethod (INT) So, in order to get what I want, using GROUP BY and subqueries, it would end up looking something like this:

          SELECT
          CustomerID,
          MIN(OrderPlaced),
          --(Some or other subquery to get the value for AmountOrdered),
          --(Some or other subquery to get the value for ContractID),
          --(Some or other subquery to get the value for OrderSource),
          --(Some or other subquery to get the value for AgentID),
          --(Some or other subquery to get the value for ProvinceID),
          --(Some or other subquery to get the value for DeliveryMethod)
          FROM Orders
          WHERE ProductID = 123
          GROUP BY CustomerID

          I'm sure you'll agree that the above query is pretty much the antithesis of elegance.

          M Offline
          M Offline
          Mycroft Holmes
          wrote on last edited by
          #4

          No no no you want the ID of the record for each customers earliest order (I hope) so first create a query that gets you that order ID, probably add the orderID to the above query. Make sure the IDs are the expected results before moving on to the next stage. Now wrap that query in a Select * from Orders where orderID in (Your innerquery) or if there are multiple fields in your inner query use a join Select * From Orders inner join (Yourinnerquery) X on X.orderid = orders.orderid You can make the inner query as complex as required but it should return the minimum required to join to your field table (Orders presumably)

          Never underestimate the power of human stupidity RAH

          D 1 Reply Last reply
          0
          • M Mycroft Holmes

            No no no you want the ID of the record for each customers earliest order (I hope) so first create a query that gets you that order ID, probably add the orderID to the above query. Make sure the IDs are the expected results before moving on to the next stage. Now wrap that query in a Select * from Orders where orderID in (Your innerquery) or if there are multiple fields in your inner query use a join Select * From Orders inner join (Yourinnerquery) X on X.orderid = orders.orderid You can make the inner query as complex as required but it should return the minimum required to join to your field table (Orders presumably)

            Never underestimate the power of human stupidity RAH

            D Offline
            D Offline
            Dewald
            wrote on last edited by
            #5

            BINGO! You've hit the nail on the head. Thanks. Here is the query that does that:

            SELECT *
            FROM Orders
            WHERE OrderID IN (
            SELECT (
            SELECT TOP 1 OrderID
            FROM Orders O2
            WHERE CustomerID = O1.CustomerID
            ORDER BY Inserted
            )
            FROM Orders O1
            GROUP BY CustomerID
            )

            Of course this query relies on the existence of OrderID, a primary key of the Orders table. I didn't define it in my original question but just about every table should have a primary key anyway and just about all my tables usually do :) The great thing about this query is that the outermost query can have a SELECT * and, as you say, could even join the Orders table with any other table that might contain linked information on the orders. Thanks again. It might seem insignificant but you've just helped me solve a problem I've been grappling with for years and never really bothered to definitively put to bed.

            M J 2 Replies Last reply
            0
            • D Dewald

              BINGO! You've hit the nail on the head. Thanks. Here is the query that does that:

              SELECT *
              FROM Orders
              WHERE OrderID IN (
              SELECT (
              SELECT TOP 1 OrderID
              FROM Orders O2
              WHERE CustomerID = O1.CustomerID
              ORDER BY Inserted
              )
              FROM Orders O1
              GROUP BY CustomerID
              )

              Of course this query relies on the existence of OrderID, a primary key of the Orders table. I didn't define it in my original question but just about every table should have a primary key anyway and just about all my tables usually do :) The great thing about this query is that the outermost query can have a SELECT * and, as you say, could even join the Orders table with any other table that might contain linked information on the orders. Thanks again. It might seem insignificant but you've just helped me solve a problem I've been grappling with for years and never really bothered to definitively put to bed.

              M Offline
              M Offline
              Mycroft Holmes
              wrote on last edited by
              #6

              You are definitely welcome, once you get your head around SQL it can be very rewarding making the dammed thing do what you want. Then the bastards introduce a new way of doing something (CTEs come to mind) and you have to start all over again!

              Never underestimate the power of human stupidity RAH

              1 Reply Last reply
              0
              • D Dewald

                BINGO! You've hit the nail on the head. Thanks. Here is the query that does that:

                SELECT *
                FROM Orders
                WHERE OrderID IN (
                SELECT (
                SELECT TOP 1 OrderID
                FROM Orders O2
                WHERE CustomerID = O1.CustomerID
                ORDER BY Inserted
                )
                FROM Orders O1
                GROUP BY CustomerID
                )

                Of course this query relies on the existence of OrderID, a primary key of the Orders table. I didn't define it in my original question but just about every table should have a primary key anyway and just about all my tables usually do :) The great thing about this query is that the outermost query can have a SELECT * and, as you say, could even join the Orders table with any other table that might contain linked information on the orders. Thanks again. It might seem insignificant but you've just helped me solve a problem I've been grappling with for years and never really bothered to definitively put to bed.

                J Offline
                J Offline
                Jorgen Andersson
                wrote on last edited by
                #7

                <edit>low on caffeine => dysfunctional brain</edit>

                Be excellent to each other. And... PARTY ON, DUDES! Abraham Lincoln

                D 1 Reply Last reply
                0
                • J Jorgen Andersson

                  <edit>low on caffeine => dysfunctional brain</edit>

                  Be excellent to each other. And... PARTY ON, DUDES! Abraham Lincoln

                  D Offline
                  D Offline
                  Dewald
                  wrote on last edited by
                  #8

                  Jörgen Andersson wrote:

                  I believe one subquery is unnecessary. Try:

                  SELECT *
                  FROM Orders
                  WHERE OrderID IN (
                  SELECT TOP 1 OrderID
                  FROM Orders O1
                  GROUP BY CustomerID
                  ORDER BY Inserted
                  )

                  I'm not sure I understand that inner query. For one OrderID in the SELECT clause should surely be part of an aggregate function seeing as it is not in the GROUP BY clause. Also, for Inserted to be contained in the ORDER BY clause it will also have to be part of an aggregate function. What am I missing?

                  J 1 Reply Last reply
                  0
                  • D Dewald

                    Jörgen Andersson wrote:

                    I believe one subquery is unnecessary. Try:

                    SELECT *
                    FROM Orders
                    WHERE OrderID IN (
                    SELECT TOP 1 OrderID
                    FROM Orders O1
                    GROUP BY CustomerID
                    ORDER BY Inserted
                    )

                    I'm not sure I understand that inner query. For one OrderID in the SELECT clause should surely be part of an aggregate function seeing as it is not in the GROUP BY clause. Also, for Inserted to be contained in the ORDER BY clause it will also have to be part of an aggregate function. What am I missing?

                    J Offline
                    J Offline
                    Jorgen Andersson
                    wrote on last edited by
                    #9

                    You're not missing anything, it's me having had to little coffee and a non-functional brain. Sorry 'bout that.

                    Be excellent to each other. And... PARTY ON, DUDES! Abraham Lincoln

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups