복붙노트

[SQL] SQL 서버 : 어떻게 첫 번째 행에 가입하세요

SQL

SQL 서버 : 어떻게 첫 번째 행에 가입하세요

나는 콘크리트,하지만 가상의 예를 사용합니다.

각각의 주문은 일반적으로 하나의 라인 항목이 있습니다 :

명령:

OrderGUID   OrderNumber
=========   ============
{FFB2...}   STL-7442-1      
{3EC6...}   MPT-9931-8A

LineItems :

LineItemGUID   Order ID Quantity   Description
============   ======== ========   =================================
{098FBE3...}   1        7          prefabulated amulite
{1609B09...}   2        32         spurving bearing

그러나 때때로이 개 광고 항목 순서가있을 것입니다 :

LineItemID   Order ID    Quantity   Description
==========   ========    ========   =================================
{A58A1...}   6,784,329   5          pentametric fan
{0E9BC...}   6,784,329   5          differential girdlespring 

일반적으로 사용자에게 주문을 보여줄 때 :

SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
    INNER JOIN LineItems 
    ON Orders.OrderID = LineItems.OrderID

나는 순서에 단일 항목을 보여주고 싶어요. 그러나이 가끔 순서가 항목을 두를 포함하는 (또는 그 이상)과 함께 주문이 중복 될 나타날 것입니다 :

OrderNumber   Quantity   Description
===========   ========   ====================
STL-7442-1    7          prefabulated amulite
MPT-9931-8A   32         spurving bearing
KSG-0619-81   5          panametric fan
KSG-0619-81   5          differential girdlespring

내가 진정으로 원하는 것은 충분한 것으로 SQL 서버는 단지 하나를 선택하는 것입니다 :

OrderNumber   Quantity   Description
===========   ========   ====================
STL-7442-1    7          prefabulated amulite
MPT-9931-8A   32         differential girdlespring
KSG-0619-81   5          panametric fan

나는 모험을 얻는 경우에, 나는보다 더있어 것을 나타 내기 위해서 (때문에), 줄임표를 사용자에게 표시 할 수 있습니다 :

OrderNumber   Quantity   Description
===========   ========   ====================
STL-7442-1    7          prefabulated amulite
MPT-9931-8A   32         differential girdlespring
KSG-0619-81   5          panametric fan, ...

문제는 방법 중 하나에 그래서

내 첫 순진 시도는 단지 "TOP 1"라인 항목에 가입했다 :

SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
    INNER JOIN (
       SELECT TOP 1 LineItems.Quantity, LineItems.Description
       FROM LineItems
       WHERE LineItems.OrderID = Orders.OrderID) LineItems2
    ON 1=1

하지만 그 오류를 제공합니다 :

아마도 내부를 선택하기 때문에 외부 테이블이 표시되지 않습니다.

해결법

  1. ==============================

    1.

    SELECT   Orders.OrderNumber, LineItems.Quantity, LineItems.Description
    FROM     Orders
    JOIN     LineItems
    ON       LineItems.LineItemGUID =
             (
             SELECT  TOP 1 LineItemGUID 
             FROM    LineItems
             WHERE   OrderID = Orders.OrderID
             )
    

    위의 SQL 서버 2005에서는, 당신은 단지 INNER을 대체 할 수있는 적용 CROSS에 가입 :

    SELECT  Orders.OrderNumber, LineItems2.Quantity, LineItems2.Description
    FROM    Orders
    CROSS APPLY
            (
            SELECT  TOP 1 LineItems.Quantity, LineItems.Description
            FROM    LineItems
            WHERE   LineItems.OrderID = Orders.OrderID
            ) LineItems2
    

    이 쿼리는 당신에게 주문 당 한 줄의 항목을 얻을 것이다, 그러나 하나가 될 것이다 정의되지 않은 : 참고 ORDER BY없이 TOP 1은 결정되지하시기 바랍니다.

    쿼리의 다중 호출은 기본이 변경되지 않은 경우에도 같은 순서로 당신에게 다른 광고 항목에 제공 할 수 있습니다.

    당신이 결정 주문을하려는 경우, 당신은 가장 안쪽 쿼리에 ORDER BY 절을 추가해야합니다.

  2. ==============================

    2.나는이 질문에 얼마 전에 대답했다 알지만, 대용량 데이터 세트를 처리 할 때, 중첩 된 쿼리는 비용이 많이들 수 있습니다. 여기에 대신 각 행이 반환을 위해의 중첩 된 쿼리가 한 번만 실행 된 것입니다 다른 솔루션이다.

    나는이 질문에 얼마 전에 대답했다 알지만, 대용량 데이터 세트를 처리 할 때, 중첩 된 쿼리는 비용이 많이들 수 있습니다. 여기에 대신 각 행이 반환을 위해의 중첩 된 쿼리가 한 번만 실행 된 것입니다 다른 솔루션이다.

    SELECT 
      Orders.OrderNumber,
      LineItems.Quantity, 
      LineItems.Description
    FROM 
      Orders
      INNER JOIN (
        SELECT
          Orders.OrderNumber,
          Max(LineItem.LineItemID) AS LineItemID
        FROM
          Orders INNER JOIN LineItems
          ON Orders.OrderNumber = LineItems.OrderNumber
        GROUP BY Orders.OrderNumber
      ) AS Items ON Orders.OrderNumber = Items.OrderNumber
      INNER JOIN LineItems 
      ON Items.LineItemID = LineItems.LineItemID
    
  3. ==============================

    3.당신은 할 수 있습니다 :

    당신은 할 수 있습니다 :

    SELECT 
      Orders.OrderNumber, 
      LineItems.Quantity, 
      LineItems.Description
    FROM 
      Orders INNER JOIN LineItems 
      ON Orders.OrderID = LineItems.OrderID
    WHERE
      LineItems.LineItemID = (
        SELECT MIN(LineItemID) 
        FROM   LineItems
        WHERE  OrderID = Orders.OrderID
      )
    

    이 인덱스 (또는 기본 키) LineItems.LineItemID에와 LineItems.OrderID에 인덱스를 필요로하거나 속도가 느려질 수 있습니다.

  4. ==============================

    4.@Quassnoi 대답은 경우 (외부 테이블이 큰 특히 경우),보다 효율적인 쿼리가 다음과 같이 윈도우 잉 기능을 사용하여 수도에 좋다 :

    @Quassnoi 대답은 경우 (외부 테이블이 큰 특히 경우),보다 효율적인 쿼리가 다음과 같이 윈도우 잉 기능을 사용하여 수도에 좋다 :

    SELECT  Orders.OrderNumber, LineItems2.Quantity, LineItems2.Description
    FROM    Orders
    LEFT JOIN 
            (
            SELECT  LineItems.Quantity, LineItems.Description, OrderId, ROW_NUMBER()
                    OVER (PARTITION BY OrderId ORDER BY (SELECT NULL)) AS RowNum
            FROM    LineItems
    
            ) LineItems2 ON LineItems2.OrderId = Orders.OrderID And RowNum = 1
    

    가끔은 그냥 쿼리가 더 나은 성능을 제공합니다 테스트해야합니다.

  5. ==============================

    5.공통 테이블 식을 사용하는 또 다른 방법을 :

    공통 테이블 식을 사용하는 또 다른 방법을 :

    with firstOnly as (
        select Orders.OrderNumber, LineItems.Quantity, LineItems.Description, ROW_NUMBER() over (partiton by Orders.OrderID order by Orders.OrderID) lp
        FROM Orders
            join LineItems on Orders.OrderID = LineItems.OrderID
    ) select *
      from firstOnly
      where lp = 1
    

    또는, 결국 어쩌면 당신은 가입 모든 행을 표시 하 고 싶습니다?

    쉼표는 여기 버전을 분리 :

      select *
      from Orders o
        cross apply (
            select CAST((select l.Description + ','
            from LineItems l
            where l.OrderID = s.OrderID
            for xml path('')) as nvarchar(max)) l
        ) lines
    
  6. ==============================

    6.SQL 서버 2012 및 이후 나는이 트릭을 할 것입니다 생각 :

    SQL 서버 2012 및 이후 나는이 트릭을 할 것입니다 생각 :

    SELECT DISTINCT
        o.OrderNumber ,
        FIRST_VALUE(li.Quantity) OVER ( PARTITION BY o.OrderNumber ORDER BY li.Description ) AS Quantity ,
        FIRST_VALUE(li.Description) OVER ( PARTITION BY o.OrderNumber ORDER BY li.Description ) AS Description
    FROM    Orders AS o
        INNER JOIN LineItems AS li ON o.OrderID = li.OrderID
    
  7. ==============================

    7.상관 관계 서브 쿼리는 외부 쿼리에 따라 서브 쿼리이다. 그것은 SQL 루프에 대한 같아요. 하위 쿼리는 외부 쿼리의 각 행에 대해 한 번 실행됩니다 :

    상관 관계 서브 쿼리는 외부 쿼리에 따라 서브 쿼리이다. 그것은 SQL 루프에 대한 같아요. 하위 쿼리는 외부 쿼리의 각 행에 대해 한 번 실행됩니다 :

    select * from users join widgets on widgets.id = (
        select id from widgets
        where widgets.user_id = users.id
        order by created_at desc
        limit 1
    )
    
  8. ==============================

    8.편집 : 신경 끄시 고, Quassnoi 더 나은 답을 가지고있다.

    편집 : 신경 끄시 고, Quassnoi 더 나은 답을 가지고있다.

    SQL2K,이 같은 경우 :

    SELECT 
      Orders.OrderNumber
    , LineItems.Quantity
    , LineItems.Description
    FROM (  
      SELECT 
        Orders.OrderID
      , Orders.OrderNumber
      , FirstLineItemID = (
          SELECT TOP 1 LineItemID
          FROM LineItems
          WHERE LineItems.OrderID = Orders.OrderID
          ORDER BY LineItemID -- or whatever else
          )
      FROM Orders
      ) Orders
    JOIN LineItems 
      ON LineItems.OrderID = Orders.OrderID 
     AND LineItems.LineItemID = Orders.FirstLineItemID
    
  9. ==============================

    9.하지 않은 절을 존재와이 쿼리를 실행하는 나의 마음에 드는 방법입니다. 나는이 쿼리의 종류를 실행하는 가장 효율적인 방법이라고 생각 :

    하지 않은 절을 존재와이 쿼리를 실행하는 나의 마음에 드는 방법입니다. 나는이 쿼리의 종류를 실행하는 가장 효율적인 방법이라고 생각 :

    select o.OrderNumber,
           li.Quantity,
           li.Description
    from Orders as o
    inner join LineItems as li
    on li.OrderID = o.OrderID
    where not exists (
        select 1
        from LineItems as li_later
        where li_later.OrderID = o.OrderID
        and li_later.LineItemGUID > li.LineItemGUID
        )
    

    하지만 여기에 제안 다른 방법에 대해이 방법을 테스트하지 않았습니다.

  10. ==============================

    10.십자가 시도, 잘 작동하지만 약간 더 오래 걸립니다. 조정 선 열이 속도를 유지하고 여분의 기록을 떨어 최대 및 추가 그룹이 있습니다.

    십자가 시도, 잘 작동하지만 약간 더 오래 걸립니다. 조정 선 열이 속도를 유지하고 여분의 기록을 떨어 최대 및 추가 그룹이 있습니다.

    여기 조정 된 쿼리는 다음과 같습니다

    SELECT Orders.OrderNumber, max(LineItems.Quantity), max(LineItems.Description)
    FROM Orders
        INNER JOIN LineItems 
        ON Orders.OrderID = LineItems.OrderID
    Group by Orders.OrderNumber
    
  11. ==============================

    11.이 시도

    이 시도

    SELECT
       Orders.OrderNumber,
       LineItems.Quantity, 
       LineItems.Description
    FROM Orders
       INNER JOIN (
          SELECT
             Orders.OrderNumber,
             Max(LineItem.LineItemID) AS LineItemID
           FROM Orders 
              INNER JOIN LineItems
              ON Orders.OrderNumber = LineItems.OrderNumber
           GROUP BY Orders.OrderNumber
       ) AS Items ON Orders.OrderNumber = Items.OrderNumber
       INNER JOIN LineItems 
       ON Items.LineItemID = LineItems.LineItemID
    
  12. from https://stackoverflow.com/questions/2043259/sql-server-how-to-join-to-first-row by cc-by-sa and MIT license