programing

SQL Join: 1대 다 관계에서 마지막 레코드 선택

elseif 2023. 4. 14. 21:17

SQL Join: 1대 다 관계에서 마지막 레코드 선택

고객 테이블과 구매 테이블이 있다고 가정해 봅시다.각 구매는 한 명의 고객에게 귀속됩니다.모든 를 한 하고 싶습니다.SELECT. 어떤 방법인가요?스트트 ?? ?? ?? ?? ? ???인인작 성한 ?한? 언? ???

답변에는 다음 표/열 이름을 사용하십시오.

  • ★★★★★★★★★★★★★★id,name
  • ★★★★★★★id,customer_id,item_id,date

또한 더 복잡한 상황에서는 마지막으로 구입한 제품을 고객 테이블에 올려 데이터베이스를 정규화하는 것이 (퍼포먼스 면에서) 유리할까요?

(입))의 id할 수 있는데, 이렇게 할 수 요? 문장을 다음과 같은 방법으로 단순화할 수 있습니까?LIMIT 1

이 바로 '하다'의 입니다.greatest-n-per-groupStack Overflow 입니다.

이 문제를 해결하는 방법은 다음과 같습니다.

SELECT c.*, p1.*
FROM customer c
JOIN purchase p1 ON (c.id = p1.customer_id)
LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND 
    (p1.date < p2.date OR (p1.date = p2.date AND p1.id < p2.id)))
WHERE p2.id IS NULL;

: 행 : " "p1.p2 및 그의 날짜넥타이의 , 그 의 날짜)를 경우.id 그 이 맞다.p1는 그 고객의 최신 구매품입니다.

purchase columns( ( ( ( ) )customer_id,date,id이렇게 하면 커버링 인덱스를 사용하여 외부 결합을 수행할 수 있습니다.최적화는 구현에 따라 다르므로 반드시 플랫폼에서 테스트하십시오.RDBMS: 예:EXPLAINMySQL my my my my my 。


위에서 설명한 솔루션 대신 서브쿼리를 사용하는 사람도 있지만, 저는 이 솔루션을 통해 관계를 쉽게 해결할 수 있다고 생각합니다.

하위 선택을 사용하여 이 작업을 시도할 수도 있습니다.

SELECT  c.*, p.*
FROM    customer c INNER JOIN
        (
            SELECT  customer_id,
                    MAX(date) MaxDate
            FROM    purchase
            GROUP BY customer_id
        ) MaxDates ON c.id = MaxDates.customer_id INNER JOIN
        purchase p ON   MaxDates.customer_id = p.customer_id
                    AND MaxDates.MaxDate = p.date

선택 항목은 모든 고객과 마지막 구매 날짜에 참여해야 합니다.

하나의 은 '먹다'를 입니다.NOT EXISTS가입 조건의 조건을 설정하여 나중에 구입하기 위해 테스트합니다.

SELECT *
FROM customer c
LEFT JOIN purchase p ON (
       c.id = p.customer_id
   AND NOT EXISTS (
     SELECT 1 FROM purchase p1
     WHERE p1.customer_id = c.id
     AND p1.id > p.id
   )
)

Postgre Postgre를 하는 SQL을 사용할 수 .DISTINCT ON그룹 내 첫 번째 행을 찾습니다.

SELECT customer.*, purchase.*
FROM customer
JOIN (
   SELECT DISTINCT ON (customer_id) *
   FROM purchase
   ORDER BY customer_id, date DESC
) purchase ON purchase.customer_id = customer.id

PostgreSQL 문서 - 고유 온

에 주의:DISTINCT ON--여기서 customer_id의 끝.ORDER BY절을 클릭합니다.

경고: 이것은 비표준 조항입니다.

데이터베이스를 지정하지 않았습니다.분석 기능을 사용할 수 있는 경우 GROUP BY 방식보다 이 방식을 사용하는 것이 더 빠를 수 있습니다(Oracle에서는 확실히 더 빠르며 SQL Server 최신 버전에서는 가장 빠를 수 있으며 다른 방법을 알 수 없습니다).

SQL Server의 구문은 다음과 같습니다.

SELECT c.*, p.*
FROM customer c INNER JOIN 
     (SELECT RANK() OVER (PARTITION BY customer_id ORDER BY date DESC) r, *
             FROM purchase) p
ON (c.id = p.customer_id)
WHERE p.r = 1

나는 내 문제의 해결책으로 이 실을 찾았다.

그런데 막상 해보니까 성능이 떨어졌어요.Bellow는 더 나은 성과를 위한 나의 제안이다.

With MaxDates as (
SELECT  customer_id,
                MAX(date) MaxDate
        FROM    purchase
        GROUP BY customer_id
)

SELECT  c.*, M.*
FROM    customer c INNER JOIN
        MaxDates as M ON c.id = M.customer_id 

이것이 도움이 되기를 바랍니다.

이거 드셔보세요, 도움이 될 거예요.

나는 이것을 내 프로젝트에 사용했다.

SELECT 
*
FROM
customer c
OUTER APPLY(SELECT top 1 * FROM purchase pi 
WHERE pi.customer_id = c.Id order by pi.Id desc) AS [LastPurchasePrice]

SQLite에서 테스트 완료:

SELECT c.*, p.*, max(p.date)
FROM customer c
LEFT OUTER JOIN purchase p
ON c.id = p.customer_id
GROUP BY c.id

max()aggregate 함수는 각 그룹에서 최신 구매가 선택되었음을 확인합니다(단, date 컬럼은 max()가 최신을 제공하는 형식이라고 가정합니다.일반적으로 이 형식입니다).같은 날짜의 구매를 처리하려면 다음을 사용할 수 있습니다.max(p.date, p.id).

인덱스에 관해서는 구매 시 인덱스를 사용하고 싶습니다(고객 ID, 날짜, 기타 선택하신 구매란).

LEFT OUTER JOIN(과 반대로)INNER JOIN)는, 구입을 실시하지 않은 고객도 포함한 것을 확인합니다.

SQL Server에서는 다음을 사용할 수 있습니다.

SELECT *
FROM customer c
INNER JOIN purchase p on c.id = p.customer_id
WHERE p.id = (
    SELECT TOP 1 p2.id
    FROM purchase p2
    WHERE p.customer_id = p2.customer_id
    ORDER BY date DESC
)

SQL Server Fidle: http://sqlfiddle.com/ #! 18/262g/2

MySQL에서는 다음을 사용할 수 있습니다.

SELECT c.name, date
FROM customer c
INNER JOIN purchase p on c.id = p.customer_id
WHERE p.id = (
    SELECT p2.id
    FROM purchase p2
    WHERE p.customer_id = p2.customer_id
    ORDER BY date DESC
    LIMIT 1
)

MySQL 바이올린: http://sqlfiddle.com/ #!9/202613/7

몇 년이 지났지만 당신이 필요로 하는 것이 필요했고, 가장 인기 있는 두 가지 답을 시도했다.이것들은 원하는 열매를 맺지 못했다.그래서 이게 내가 제안해야 할...확실히 하기 위해 몇 가지 이름을 바꿨어요.

SELECT 
  cc.pk_ID AS pk_Customer_ID, 
  cc.Customer_Name AS Customer_Name, 
  IFNULL(pp.pk_ID, '') AS fk_Purchase_ID,
  IFNULL(pp.fk_Customer_ID, '') AS fk_Customer_ID,
  IFNULL(pp.fk_Item_ID, '') AS fk_Item_ID,
  IFNULL(pp.Purchase_Date, '') AS Purchase_Date
FROM customer cc
LEFT JOIN purchase pp ON (
  SELECT zz.pk_ID 
  FROM purchase zz 
  WHERE cc.pk_ID = zz.fk_Customer_ID 
  ORDER BY zz.Purchase_Date DESC LIMIT 1) = pp.pk_ID
ORDER BY cc.pk_ID;

이거 드셔보세요.

SELECT 
c.Id,
c.name,
(SELECT pi.price FROM purchase pi WHERE pi.Id = MAX(p.Id)) AS [LastPurchasePrice]
FROM customer c INNER JOIN purchase p 
ON c.Id = p.customerId 
GROUP BY c.Id,c.name;

코드를 먼저 입력하지 않고 논리/알고리즘은 다음과 같습니다.

  1. 로 이동합니다.transaction같은 레코드가 여러 개 있는 테이블client.

  2. 레코드 선택clientID및 그latestDate클라이언트 액티비티의group by clientID그리고.max(transactionDate)

       select clientID, max(transactionDate) as latestDate 
       from transaction 
       group by clientID
    
  3. inner jointransaction스텝 2의 결과를 표로 작성하면, 다음의 모든 기록을 얻을 수 있습니다.transaction테이블에는 각 클라이언트의 최신 레코드만 기재되어 있습니다.

       select * from 
       transaction t 
       inner join (
         select clientID, max(transactionDate) as latestDate
         from transaction 
         group by clientID) d 
       on t.clientID = d.clientID and t.transactionDate = d.latestDate) 
    
  4. 순서 3 의 결과를 사용하고, 다른 결과를 얻을 수 있는 임의의 테이블을 결합할 수 있습니다.

표:

Customer => id, name
Purchase => id, customer_id, item_id, date

쿼리:

SELECT C.id, C.name, P.id, P.date
  FROM customer AS C
  LEFT JOIN purchase AS P ON 
    (
      P.customer_id = C.id 
      AND P.id IN (
        SELECT MAX(PP.id) FROM purchase AS PP GROUP BY PP.customer_id
      )
    )

또, 다음의 몇개의 조건을 지정할 수도 있습니다.sub select질문하다

언급URL : https://stackoverflow.com/questions/2111384/sql-join-selecting-the-last-records-in-a-one-to-many-relationship