source

첫 번째 줄에 가입하는 방법

ittop 2023. 4. 7. 21:57
반응형

첫 번째 줄에 가입하는 방법

구체적인 예를 들겠습니다만, 하지만 가정적인 예를 들겠습니다.

주문에는 보통 한의 항목만 포함됩니다.

주문:

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

라인 항목:

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

주문하신 상품을 1개만 보여드리고 싶습니다.그러나 이 주문에는 2개 이상의 아이템이 포함되어 있기 때문에 주문이 중복되어 표시됩니다.

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 Server는 다음 중 하나를 선택하기만 하면 됩니다.

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

하지만 그 결과 다음과 같은 오류가 발생합니다.

'Orders' 열 또는 접두사는
테이블명 또는 에일리어스명과 일치하다
쿼리에서 사용됩니다.

아마도 내부 선택에서 외부 테이블을 볼 수 없기 때문일 것입니다.

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 Server 2005 이상에서는 다음 명령어를 대체할 수 있습니다.INNER JOIN와 함께CROSS APPLY:

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

주의하시기 바랍니다.TOP 1없이.ORDER BY이 쿼리는 확정적이지 않습니다.이 쿼리는 주문당 한 줄의 아이템을 얻을 수 있지만 어떤 아이템이 될지는 정의되어 있지 않습니다.

쿼리를 여러 번 호출하면 기본 항목이 변경되지 않았더라도 동일한 순서에 대해 서로 다른 행 항목을 제공할 수 있습니다.

결정론적 순서를 원할 경우 다음 순서를 추가해야 합니다.ORDER BY가장 안쪽 쿼리에 대한 절입니다.

샘플 sqlfiddle

조금 전에 이 질문에 답한 것은 알고 있습니다만, 대량의 데이터 세트를 취급할 때는, 네스트 된 쿼리에 코스트가 드는 경우가 있습니다.다음은 반환되는 각 행이 아닌 중첩된 쿼리를 한 번만 실행하는 다른 솔루션입니다.

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

@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

경우에 따라서는 어떤 쿼리가 더 나은 성능을 제공하는지만 테스트해야 할 수도 있습니다.

다음과 같은 작업을 할 수 있습니다.

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안 그러면 느려요.

SQL Server 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

, 공통 테이블 표현을 사용하는 다른 aproach:

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

상관된 하위 쿼리는 외부 쿼리에 따라 달라지는 하위 쿼리입니다.SQL의 for 루프와 같습니다.하위 쿼리는 외부 쿼리의 각 행에 대해 한 번 실행됩니다.

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
)

이 쿼리를 실행하는 가장 좋은 방법은 존재하지 않는 절을 사용하는 것입니다.저는 이것이 이런 종류의 쿼리를 실행하는 가장 효율적인 방법이라고 생각합니다.

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
    )

그러나 나는 이 방법을 여기에 제시된 다른 방법과 비교해서 테스트하지 않았다.

됐어, 콰스누이가 더 좋은 대답을 했어.

SQL2000의 경우 다음과 같습니다.

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

십자가를 긋고, 잘 작동하지만, 조금 더 오래 걸립니다.최대값과 추가된 그룹이 속도를 유지하고 추가 레코드를 드롭하도록 라인 열을 조정했습니다.

다음은 조정된 쿼리입니다.

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

언급URL : https://stackoverflow.com/questions/2043259/how-to-join-to-first-row

반응형