선택 하위 쿼리에서 여러 열 가져 오기


24
SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
   ( 
       SELECT ps.price 
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS special_price,
   ( 
       SELECT ps.date 
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)

보시다시피 다른 열을 꺼내기 위해 동일한 하위 쿼리를 반복하고 있습니다. 더 좋은 방법이 있는지 궁금합니다.

id 는 두 테이블의 기본 키입니다. 도움이 될 수 있다면 product_special.priority를 고유 하게 만드는 데 아무런 문제가 없습니다 .

답변:


11

조합 product_special.id, product_special.priority이 고유 하다고 가정

 SELECT p.*, special_price,special_date
 FROM product p
 LEFT JOIN 
 (
     SELECT ps.id, ps.price as special_price, ps.`date` as special_date
     FROM product_special ps
     INNER JOIN 
     (
       SELECT id, MIN(priority) as min_priority 
       FROM product_special
       GROUP BY id
     ) ps2 
     ON (ps2.id = ps.id)
 )a ON (a.id=p.id)

5

필드를 special_price.price 및 date.date로 반환하지 않으려는 경우 하위 쿼리 내부의 이름을 별칭으로 지정하지 않는 이유는 무엇입니까? 예 :

SELECT p.*, p.name AS  name, p.image, p.price, ps.*
FROM product p
LEFT JOIN
   (SELECT
      psi.price as special_price, psi.date as my_date 
    FROM product_special psi
    WHERE 
      p.id = psi.id AND
      psi.date < NOW()
    ORDER BY psi.priority ASC, LIMIT 1
   ) AS ps ON
  p.id = ps.id

쿼리 언어에 FIRST () 집계 함수가 있습니까? product_special의 PK를 id와 우선 순위 (ASC 정렬 둘 다)의 복합으로 만들 수 있는지 여부를 모르고 ORDER 절을GROUP BY id, psi.priority

ORDER BY 절을 완전히 제거하고 사용할 수 있습니다. HAVING MIN(psi.priority)


2

SQL Server의 "교차 적용"메커니즘으로이를 해결할 수 있지만 PostgreSQL에서는 사용할 수 없습니다. 기본적으로 FROM 절에서 매개 변수 (현재 테이블 식 외부의 열을 참조하는 경향이 있음)를 테이블식이라고하는 함수에 전달하는 방법에 대한 솔루션이었습니다. 그러나 다른 수준의 하위 쿼리 중첩을 피하거나 FROM 절에서 SELECT 절로 항목을 이동하지 않으려는 모든 상황에 유용합니다. PostgreSQL은 일종의 예외를 만들어이를 가능하게했습니다. 표현식이 단순한 함수 호출이지만 내장 된 SELECT를 엄격하게 말하지 않는 경우와 같은 매개 변수를 전달할 수 있습니다. 그래서

left join highestPriorityProductSpecial(p.id) on true

괜찮아요

left join (select * from product_special ps where ps.id = p.id order by priority desc limit 1) on true

함수의 정의는 정확하게 그 말이지 만.

따라서 그것은 실제로 편리한 솔루션입니다 (적어도 9.1). 함수 내부에서 한계를 수행하여 가장 우선 순위가 높은 행을 추출하는 함수를 만듭니다.

그러나 함수에는 쿼리 계획에서 어떤 일이 일어나고 있는지 보여주지 않을 것이라는 단점이 있으며, 최선의 방법이 아닐지라도 항상 중첩 루프 조인을 선택한다고 생각합니다.


6
cross apply 입니다 9.3로 시작하는 포스트 그레스에서 사용할 수 (2013 년 발표)하지만 그들은 SQL 표준을 준수 표준 사용하기로 결정했습니다 lateral연산자를. 두 번째 쿼리 left join에서left join lateral
a_horse_with_no_name으로

2

다음 SQL 명령을 시도하십시오.

SELECT p.name,p.image,p.price,pss.price,pss.date
FROM Product p OUTER APPLY(SELECT TOP(1)* 
FROM ProductSpecial ps
WHERE p.Id = ps.Id ORDER BY ps.priority )as pss

1
답변에 더 많은 정보를 추가
해주시겠습니까?

문제가되는 코드 LIMIT는 DBMS를 사용 하고 태그되지 않습니다 (따라서 MySQL, Postgres 또는 SQLite 또는 다른 DBMS 일 수 있음). 응답 용도의 코드 OUTER APPLYTOP그것을 그래서 그것은이없는 SQL 서버 전용 (사이베이스)에서 작동합니다 LIMIT.
ypercubeᵀᴹ

이것은 select 문 내에서 내부 쿼리를 사용할 수있는 다른 데이터베이스의 경우에만 SQL Server에 적용됩니다.
SANTOSH APPANA

포스트 그레스에서이없는 OUTER APPLY,하지만이 측면 동일해야. 사용 예 : stackoverflow.com/a/47926042/4850646
Lucas

2

dezso의 답변 /dba//a/222471/127433 에서 영감을 얻었습니다 .PostgreSQL에서 다음 과 같이 배열을 사용하여 문제를 해결하고 있습니다.

SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
   ( 
       SELECT ARRAY[ps.price, ps.date]
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS special_price_and_date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)

분명히 그것은 여전히 ​​하나의 열이지만 내 코드에서는 두 값에 쉽게 액세스 할 수 있습니다. 그것이 당신에게도 효과가 있기를 바랍니다.


1

하나 이상의 다른 답변을 지원하지 않는 데이터베이스 엔진을 사용하는 모든 사람들을 위해 이것을 최후의 수단으로 여기에 넣고 싶습니다 ...

다음과 같은 것을 사용할 수 있습니다.

SELECT (col1 || col2) as col3 

구분 기호를 사용하거나 col1 및 col2를 특정 길이로 형식화합니다. 나중에 하위 문자열을 사용하여 데이터를 그립니다.

누군가가 유용하다고 생각합니다.


0

z / OS 용 DB2에서 packunpack기능을 사용 하여 부속 선택에서 여러 열을 리턴하십시오.

SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
    unpack((select PACK (CCSID 1028,
               ps.price,
               ps.date)
         FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1)) .* AS (SPECIAL_PRICE double, DATE date)
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.