문제

결합된 2개의 열이 모두 다른 테이블에서 모든 행을 검색해야 합니다.그래서 같은 날 같은 가격으로 발생한 다른 판매가 없는 모든 판매를 원합니다.요일 및 가격을 기준으로 고유한 판매가 활성 상태로 업데이트됩니다.

그래서 나는 생각하고 있습니다 :

UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
             FROM sales
             HAVING count = 1)

하지만 그 이상으로 나아가면 내 뇌가 아프다.

도움이 되었습니까?

해결책

SELECT DISTINCT a,b,c FROM t

~이다 대충 다음과 같습니다:

SELECT a,b,c FROM t GROUP BY a,b,c

GROUP BY 구문이 더 강력하므로 익숙해지는 것이 좋습니다.

귀하의 문의사항에 대해서는 다음과 같이 하겠습니다.

UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
    SELECT id
    FROM sales S
    INNER JOIN
    (
        SELECT saleprice, saledate
        FROM sales
        GROUP BY saleprice, saledate
        HAVING COUNT(*) = 1 
    ) T
    ON S.saleprice=T.saleprice AND s.saledate=T.saledate
 )

다른 팁

지금까지의 답변을 종합하고 정리하고 개선하면 다음과 같은 우수한 쿼리에 도달하게 됩니다.

UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );

어느 것이 많이 둘 중 누구보다 빠릅니다.현재 허용되는 답변의 성능을 10 - 15 요소로 누크합니다(PostgreSQL 8.4 및 9.1에 대한 테스트에서).

그러나 이는 여전히 최적과는 거리가 멀다.사용 NOT EXISTS 더 나은 성능을 위한 (안티)세미 조인. EXISTS 표준 SQL은 영원히 존재해 왔으며(적어도 이 질문이 제기되기 오래 전인 PostgreSQL 7.2 이후) 제시된 요구 사항에 완벽하게 맞습니다.

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT FROM sales s1                     -- SELECT list can be empty for EXISTS
   WHERE  s.saleprice = s1.saleprice
   AND    s.saledate  = s1.saledate
   AND    s.id <> s1.id                     -- except for row itself
   )
AND    s.status IS DISTINCT FROM 'ACTIVE';  -- avoid empty updates. see below

DB<>바이올린 여기
이전 SQL 바이올린

행을 식별하는 고유 키

테이블에 대한 기본 키 또는 고유 키가 없는 경우(id 예에서는 시스템 열로 대체할 수 있습니다. ctid 이 쿼리의 목적에 따라(다른 목적에는 적용되지 않음):

   AND    s1.ctid <> s.ctid

모든 테이블에는 기본 키가 있어야 합니다.아직 없는 경우 추가하세요.나는 제안한다 serial 또는 IDENTITY Postgres 10+의 열.

관련된:

어떻게 이게 더 빨라?

하위 쿼리는 EXISTS anti-semi-join은 첫 번째 속임수가 발견되는 즉시 평가를 중지할 수 있습니다(더 이상 살펴볼 필요가 없음).중복이 거의 없는 기본 테이블의 경우 이는 약간 더 효율적입니다.중복이 많으면 이렇게 됩니다. 방법 더 효율적입니다.

빈 업데이트 제외

이미 있는 행의 경우 status = 'ACTIVE' 이 업데이트는 아무 것도 변경하지 않지만 여전히 전체 비용으로 새 행 버전을 삽입합니다(사소한 예외가 적용됨).일반적으로 사용자는 이를 원하지 않습니다.다른 것을 추가하세요 WHERE 이를 방지하고 더욱 빠르게 만들려면 위에서 설명한 것과 같은 조건을 사용하세요.

만약에 status 정의된다 NOT NULL, 다음과 같이 단순화할 수 있습니다.

AND status <> 'ACTIVE';

NULL 처리의 미묘한 차이

이 쿼리는 ( 현재 Joel의 답변이 허용되었습니다.)는 NULL 값을 동일하게 취급하지 않습니다.다음 두 행은 (saleprice, saledate) "뚜렷한" 것으로 간주됩니다(인간의 눈과 동일하게 보임에도 불구하고).

(123, NULL)
(123, NULL)

또한 NULL 값은 SQL 표준에 따라 동일하게 비교되지 않기 때문에 고유 인덱스 및 거의 모든 곳에서 전달됩니다.보다:

오토, GROUP BY, DISTINCT 또는 DISTINCT ON () NULL 값을 동일하게 취급합니다.달성하려는 목표에 따라 적절한 쿼리 스타일을 사용하십시오.이 더 빠른 쿼리를 계속 사용할 수 있습니다. IS NOT DISTINCT FROM 대신에 = NULL 비교를 동일하게 만들기 위한 일부 또는 모든 비교.더:

비교되는 모든 열이 정의된 경우 NOT NULL, 이견의 여지가 없습니다.

쿼리의 문제점은 GROUP BY 절(기본적으로 구별을 사용하여 수행)을 사용할 때 그룹화 기준 또는 집계 함수를 사용하는 열만 사용할 수 있다는 것입니다.잠재적으로 다른 값이 있으므로 열 ID를 사용할 수 없습니다.귀하의 경우 HAVING 절로 인해 항상 하나의 값만 있지만 대부분의 RDBMS는 이를 인식할 만큼 똑똑하지 않습니다.

그러나 이것은 작동해야 하며 조인이 필요하지 않습니다.

UPDATE sales
SET status='ACTIVE'
WHERE id IN (
  SELECT MIN(id) FROM sales
  GROUP BY saleprice, saledate
  HAVING COUNT(id) = 1
)

MIN 대신 MAX 또는 AVG를 사용할 수도 있습니다. 일치하는 행이 하나만 있는 경우 열 값을 반환하는 함수를 사용하는 것이 중요합니다.

'GrondOfLucht' 열에서 고유한 값을 선택하고 싶지만 '정렬' 열에 지정된 순서대로 정렬해야 합니다.다음을 사용하여 단 하나의 열의 고유 값을 얻을 수 없습니다.

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

또한 '정렬' 열이 제공되며 'GrondOfLucht' AND '정렬'이 고유하지 않기 때문에 결과는 모든 행이 됩니다.

GROUP을 사용하여 'GrondOfLucht'의 레코드를 'sortering'에 지정된 순서대로 선택합니다.

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)

DBMS가 다음과 같은 여러 열이 있는 구별을 지원하지 않는 경우:

select distinct(col1, col2) from table

일반적으로 다중 선택은 다음과 같이 안전하게 실행할 수 있습니다.

select distinct * from (select col1, col2 from table ) as x

이는 대부분의 DBMS에서 작동할 수 있으며 그룹화 기능을 피하므로 솔루션별 그룹보다 더 빠를 것으로 예상됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top