각 GROUP BY 그룹에서 첫 번째 행을 선택하시겠습니까?
알 수 있듯이, 저는 각 의 첫 GROUP BY
.
내가 '오빠'를 가지고 있다면, '오빠'를 가지고 있다.purchases
츠키다
SELECT * FROM purchases;
마이 출력:
아이디 | 고객. | 총 |
---|---|---|
1 | 조. | 5 |
2 | 샐리 | 3 |
3 | 조. | 2 |
4 | 샐리 | 1 |
i i드니다 for for for for for 。id
산 total
요.customer
다음과 같이 합니다.
SELECT FIRST(id), customer, FIRST(total)
FROM purchases
GROUP BY customer
ORDER BY total DESC;
예상 출력:
첫 번째(ID) | 고객. | 최초(합계) |
---|---|---|
1 | 조. | 5 |
2 | 샐리 | 3 |
DISTINCT ON
Postgre에서 일반적으로 가장 간단하고 빠른 속도입니다.SQL.
(특정 워크로드의 퍼포먼스 최적화에 대해서는, 이하를 참조해 주세요).
SELECT DISTINCT ON (customer)
id, customer, total
FROM purchases
ORDER BY customer, total DESC, id;
또는 출력 열의 서수 개수로 더 짧습니다(명료하지 않은 경우).
SELECT DISTINCT ON (2)
id, customer, total
FROM purchases
ORDER BY 2, 3 DESC, 1;
iftotal
수 있습니다.null
, 더하다NULLS LAST
:
...
ORDER BY customer, total DESC NULLS LAST, id;
어느 쪽이든 작동하지만 기존 인덱스와 일치해야 합니다.
db <>여기에 추가
주요 사항
DISTINCT ON
postgre 입니다.표준 SQL 확장자(단,DISTINCT
SELECT
이치노
때 은 몇 해 주세요.DISTINCT ON
clause. 행 값을 조합하여 중복을 정의합니다.매뉴얼:
두 행이 하나 이상의 열 값에서 다른 경우 분명히 구별되는 행으로 간주됩니다.이 비교에서는 null 값이 동일한 것으로 간주됩니다.
과감하게 강조해 주세요.
DISTINCT ON
와 조합할 수 있습니다.의 선두 표현은ORDER BY
표현 세트 안에 있어야 한다DISTINCT ON
다만, 자유롭게 순서를 변경할 수 있습니다.예.
표현식을 추가할 수 있습니다.ORDER BY
각 피어 그룹에서 특정 행을 선택합니다.또는 매뉴얼에 기재된 바와 같이:
DISTINCT ON
맨 왼쪽에 식과ORDER BY
★★★★ORDER BY
으로 구에는 각DISTINCT ON
syslog.syslog.syslog.
는 ㅇㅇㅇㅇㅇㅇㅇㅇ다를 넣었습니다.id
「 」 「 」 、 「 」
.id
으로부터, 「최고」를 하고 있습니다.total
첫 순서와 하지 않는 방식으로 쿼리로 .ORDER BY
. 예.
iftotal
수 있습니다.null
대부분의 경우 non-timeout 값이 가장 큰 행을 사용합니다.예시와 같이 추가합니다.참조:
리스트는 다음 식에 의해 제약되지 않습니다.DISTINCT ON
★★★★★★★★★★★★★★★★★」ORDER BY
떤떤방방방 :
표현은 에 포함할 필요가 없습니다.
DISTINCT ON
★★★★★★★★★★★★★★★★★」ORDER BY
.다른 표현식을 포함할 수 있습니다.
SELECT
목록. 이것은 복잡한 서브쿼리와 집계/창 기능을 대체하는 데 중요합니다.
Postgres 버전 8.3~15로 테스트했습니다.그러나 이 기능은 적어도 버전 7.1 이후부터 존재하므로 기본적으로 항상 사용할 수 있습니다.
색인
위의 쿼리에 대한 완벽한 인덱스는 일치하는 시퀀스와 일치하는 정렬 순서를 가진 3개 열에 걸쳐 있는 다중 열 인덱스입니다.
CREATE INDEX purchases_3c_idx ON purchases (customer, total DESC, id);
너무 전문화된 것 같습니다.그러나 특정 쿼리에 대한 읽기 성능이 중요한 경우 사용합니다.「 」가 DESC NULLS LAST
쿼리에서 정렬 순서가 일치하고 인덱스가 완벽하게 적용되도록 인덱스에서 동일한 항목을 사용합니다.
효과/퍼포먼스 최적화
각 쿼리에 대한 맞춤형 인덱스를 작성하기 전에 비용과 이점을 평가하십시오.상기 지수의 잠재력은 데이터 분포에 크게 좌우된다.
인덱스는 미리 정렬된 데이터를 전달하기 때문에 사용됩니다.Postgres 9.2 이상에서는 인덱스가 기본 테이블보다 작은 경우에만 인덱스 스캔의 이점을 얻을 수 있습니다.그러나 인덱스는 전체를 스캔해야 합니다.예.
고객 한 명당 몇 줄의 경우(열에서 높은 카디널리티)customer
을 사용하다어쨌든 정렬된 출력이 필요한 경우에는 더욱 그렇습니다.고객 1인당 행 수가 증가함에 따라 이점은 축소됩니다.
이상적으로는 RAM에서 관련된 정렬 단계를 충분히 처리하고 디스크에 흘리지 않는 것이 좋습니다.단, 일반적으로 설정work_mem
너무 높으면 부작용이 생길 수 있습니다.고려하다SET LOCAL
매우 큰 질의에 사용됩니다. find with much much much find much much much find find find find 에서 필요한 것을 찾아보세요.EXPLAIN ANALYZE
. 정렬 단계에서 "Disk:"를 언급하면 다음과 같은 추가 정보가 필요합니다.
고객 1인당 다수의 행(컬럼 내 카디널리티가 낮음)customer
), "인덱스 건너뛰기 스캔" 또는 "인덱스 스캔"이 더 효율적입니다.하지만 Postgres 15까지는 구현되지 않았습니다.어떤 식으로든 이를 구현하기 위한 진지한 작업이 몇 년째 진행 중이지만 아직까지는 성공하지 못했습니다.여기랑 여기 보세요.
현재로서는 이를 대체할 더 빠른 쿼리 기법이 있습니다.특히 개별 고객을 수용하는 별도의 테이블이 있는 경우, 이것이 일반적인 사용 사례입니다.그렇지 않은 경우:
- SELECT DISTINT가 Postgre 테이블에서 예상보다 느립니다.SQL
- GROUP BY 쿼리를 최적화하여 사용자별 최신 행 검색
- 그룹별 최대 쿼리 최적화
- 행당 마지막 N개의 관련 행 쿼리
벤치마크
CTE 및 윈도우 기능을 지원하는 데이터베이스에서는 다음 작업을 수행합니다.
WITH summary AS (
SELECT p.id,
p.customer,
p.total,
ROW_NUMBER() OVER(PARTITION BY p.customer
ORDER BY p.total DESC) AS rank
FROM PURCHASES p)
SELECT *
FROM summary
WHERE rank = 1
모든 데이터베이스에서 지원:
하지만 관계를 끊으려면 논리를 추가해야 합니다.
SELECT MIN(x.id), -- change to MAX if you want the highest
x.customer,
x.total
FROM PURCHASES x
JOIN (SELECT p.customer,
MAX(total) AS max_total
FROM PURCHASES p
GROUP BY p.customer) y ON y.customer = x.customer
AND y.max_total = x.total
GROUP BY x.customer, x.total
벤치마크
가장 흥미로운 후보를 테스트했습니다.
- 처음에는 Postgres 9.4 및 9.5를 사용합니다.
- 나중에 Postgres 13 악센트 테스트 추가.
기본 테스트 셋업
테이블: ★★★★★★★★★★★★★★★★★★★★:purchases
:
CREATE TABLE purchases (
id serial -- PK constraint added below
, customer_id int -- REFERENCES customer
, total int -- could be amount of money in Cent
, some_column text -- to make the row bigger, more realistic
);
더미 데이터(일부 데드 튜플 포함), PK, 인덱스:
INSERT INTO purchases (customer_id, total, some_column) -- 200k rows
SELECT (random() * 10000)::int AS customer_id -- 10k distinct customers
, (random() * random() * 100000)::int AS total
, 'note: ' || repeat('x', (random()^2 * random() * random() * 500)::int)
FROM generate_series(1,200000) g;
ALTER TABLE purchases ADD CONSTRAINT purchases_id_pkey PRIMARY KEY (id);
DELETE FROM purchases WHERE random() > 0.9; -- some dead rows
INSERT INTO purchases (customer_id, total, some_column)
SELECT (random() * 10000)::int AS customer_id -- 10k customers
, (random() * random() * 100000)::int AS total
, 'note: ' || repeat('x', (random()^2 * random() * random() * 500)::int)
FROM generate_series(1,20000) g; -- add 20k to make it ~ 200k
CREATE INDEX purchases_3c_idx ON purchases (customer_id, total DESC, id);
VACUUM ANALYZE purchases;
customer
이 - - - 된쿼쿼쿼쿼쿼다 다다다다다다다
CREATE TABLE customer AS
SELECT customer_id, 'customer_' || customer_id AS customer
FROM purchases
GROUP BY 1
ORDER BY 1;
ALTER TABLE customer ADD CONSTRAINT customer_customer_id_pkey PRIMARY KEY (customer_id);
VACUUM ANALYZE customer;
두 번째 같은 의 고유한 9.5를 사용했습니다.customer_id
행이 적다customer_id
.
" " " "purchases
설정: " " " 내의 20, 행purchases
10,, 10,000 †customer_id
, avg. "1" "20" 입니다.
Postgres 9.5의 경우 86446명의 개별 고객을 대상으로 한 두 번째 테스트를 추가했습니다(고객당 평균 2.3줄).
여기서 가져온 쿼리로 생성됩니다.
Postgres 9.5를 위해 수집:
what | bytes/ct | bytes_pretty | bytes_per_row
-----------------------------------+----------+--------------+---------------
core_relation_size | 20496384 | 20 MB | 102
visibility_map | 0 | 0 bytes | 0
free_space_map | 24576 | 24 kB | 0
table_size_incl_toast | 20529152 | 20 MB | 102
indexes_size | 10977280 | 10 MB | 54
total_size_incl_toast_and_indexes | 31506432 | 30 MB | 157
live_rows_in_text_representation | 13729802 | 13 MB | 68
------------------------------ | | |
row_count | 200045 | |
live_tuples | 200045 | |
dead_tuples | 19955 | |
쿼리
1. row_number()
CTE에서는 (다른 답변 참조)
WITH cte AS (
SELECT id, customer_id, total
, row_number() OVER (PARTITION BY customer_id ORDER BY total DESC) AS rn
FROM purchases
)
SELECT id, customer_id, total
FROM cte
WHERE rn = 1;
2. row_number()
(
SELECT id, customer_id, total
FROM (
SELECT id, customer_id, total
, row_number() OVER (PARTITION BY customer_id ORDER BY total DESC) AS rn
FROM purchases
) sub
WHERE rn = 1;
3. DISTINCT ON
(다른 답변 참조)
SELECT DISTINCT ON (customer_id)
id, customer_id, total
FROM purchases
ORDER BY customer_id, total DESC, id;
와 4. rCTE †LATERAL
서브쿼리(여기를 참조)
WITH RECURSIVE cte AS (
( -- parentheses required
SELECT id, customer_id, total
FROM purchases
ORDER BY customer_id, total DESC
LIMIT 1
)
UNION ALL
SELECT u.*
FROM cte c
, LATERAL (
SELECT id, customer_id, total
FROM purchases
WHERE customer_id > c.customer_id -- lateral reference
ORDER BY customer_id, total DESC
LIMIT 1
) u
)
SELECT id, customer_id, total
FROM cte
ORDER BY customer_id;
5. customer
와 식사하다.LATERAL
(여기를 참조)
SELECT l.*
FROM customer c
, LATERAL (
SELECT id, customer_id, total
FROM purchases
WHERE customer_id = c.customer_id -- lateral reference
ORDER BY total DESC
LIMIT 1
) l;
6. array_agg()
ORDER BY
(다른 답변 참조)
SELECT (array_agg(id ORDER BY total DESC))[1] AS id
, customer_id
, max(total) AS total
FROM purchases
GROUP BY customer_id;
결과.
웜 캐시와 비교하기 위해 를 사용한 위의 쿼리의 실행 시간, 베스트5 실행 중 하나입니다.
모든 쿼리가 인덱스 전용 검색을 사용함purchases2_3c_idx
(서양속담, 돈속담)일부는 지수의 작은 크기에서 이익을 얻을 뿐이고, 다른 일부는 더 효과적이다.
9, 행 수 A당 최대 . 포스트그레스 9.4 (20,000 °C, 20/20 °C)customer_id
1. 273.274 ms
2. 194.572 ms
3. 111.067 ms
4. 92.922 ms -- !
5. 37.679 ms -- winner
6. 189.495 ms
B. Postgres 9.5를 사용하는 A와 동일
1. 288.006 ms
2. 223.032 ms
3. 107.074 ms
4. 78.032 ms -- !
5. 33.944 ms -- winner
6. 211.540 ms
B와 하지만 C당 2 B - 1 - 2 . 3customer_id
1. 381.573 ms
2. 311.976 ms
3. 124.074 ms -- winner
4. 710.631 ms
5. 311.976 ms
6. 421.679 ms
2021-08-11에 Postgres 13을 사용하여 다시 테스트합니다.
셋업:은 없습니다. 행은 삭제되지 않습니다.이유는VACUUM ANALYZE
간단한 경우 테이블을 완전히 청소합니다.
Postgres의 중요한 변경 사항:
- 일반적인 퍼포먼스 향상
- CTE는 Postgres 12 이후 인라인을 사용할 수 있으므로 쿼리 1.과 쿼리 2.는 거의 동일한(같은 쿼리 계획)을 수행합니다.
D. B와 같습니다.고객 ID당 최대 20줄
1. 103 ms
2. 103 ms
3. 23 ms -- winner
4. 71 ms
5. 22 ms -- winner
6. 81 ms
db <>여기에 추가
E. C와 같이 Customer_id당 최대 2.3행
1. 127 ms
2. 126 ms
3. 36 ms -- winner
4. 620 ms
5. 145 ms
6. 203 ms
db <>여기에 추가
Postgres 13을 사용한 악센트 테스트
고객 1인당 10,000 행 대 100 행 대 1.6 행.
F. 고객 1인당 최대 10,000줄
1. 526 ms
2. 527 ms
3. 127 ms
4. 2 ms -- winner !
5. 1 ms -- winner !
6. 356 ms
db <>여기에 추가
G. 고객 1인당 최대 100줄의 행이 있습니다.
1. 535 ms
2. 529 ms
3. 132 ms
4. 108 ms -- !
5. 71 ms -- winner
6. 376 ms
db <>여기에 추가
고객 1인당 최대 1.6줄의 H.
1. 691 ms
2. 684 ms
3. 234 ms -- winner
4. 4669 ms
5. 1089 ms
6. 1264 ms
db <>여기에 추가
결론들
DISTINCT ON
는 인덱스를 효과적으로 사용하며 일반적으로 그룹별로 몇 줄의 행에 대해 최적의 성능을 발휘합니다.또한 그룹당 행이 여러 개라도 성능이 상당히 우수합니다.그룹당 많은 행의 경우 rCTE를 사용하여 인덱스 건너뛰기 스캔을 에뮬레이트하면 별도의 룩업 테이블(사용 가능한 경우)을 사용하는 쿼리 기법 다음으로 성능이 우수합니다.
현재 승인된 답변에서 시연된 기술은 성능 테스트에서 이긴 적이 없습니다.그때는 안 돼, 지금은 안 돼.결코 와는 거리가 멀다
DISTINCT ON
데이터 배포가 후자에 불리한 경우에도 마찬가지입니다.★★★★★★의row_number()
되는 것이 이치노
기타 벤치마크
Postgres 11.5에서는 1,000만 행과 60,000개의 고유 고객으로 구성된 "ogr"에 의한 벤치마크.결과는 지금까지의 결과와 일치합니다.
2011년부터의 오리지널(구식) 벤치마크
Postgre와 세 가지 테스트를 해봤는데65579개의 행과 관련된 각 열의 단일 열 btree 인덱스로 구성된 실제 테이블에서 SQL 9.1을 수행했으며 실행 시간이 5번으로 가장 길었습니다.
@OMGPonies의 첫 번째 쿼리()A
와 위의 솔루션()B
비교:
- 전체 테이블을 선택하면 이 경우 5958 행이 됩니다.
A: 567.218 ms
B: 386.673 ms
- 사용
WHERE customer BETWEEN x AND y
1000달러입니다.
A: 249.136 ms
B: 55.111 ms
- 1개의 .
WHERE customer = x
.
A: 0.143 ms
B: 0.072 ms
다른 답변에 설명된 지수를 사용하여 동일한 테스트를 반복했다.
CREATE INDEX purchases_3c_idx ON purchases (customer, total DESC, id);
1A: 277.953 ms
1B: 193.547 ms
2A: 249.796 ms -- special index not used
2B: 28.679 ms
3A: 0.120 ms
3B: 0.048 ms
이는 그룹당 가장 큰 n개의 일반적인 문제로, 이미 충분히 테스트되고 최적화된 솔루션을 보유하고 있습니다.개인적으로 나는 Bill Karwin의 왼쪽 결합 솔루션을 선호한다(다른 솔루션이 많은 원본 게시물).
MySQL 매뉴얼에는 이 일반적인 문제에 대한 해결책이 나와 있습니다.문제가 MySQL이 아닌 Postgres에 있는 경우에도 대부분의 SQL 변종에서 사용할 수 있습니다.일반 쿼리의 예: 특정 열의 그룹별 최대값을 유지하는 행을 참조하십시오.
에서는 Postgres를 사용할 수 .array_agg
음음음같 뭇매하다
SELECT customer,
(array_agg(id ORDER BY total DESC))[1],
max(total)
FROM purchases
GROUP BY customer
하면 ★★★★★★★★★★★★★★★★★★★★★★★.id
아!
주의사항:
array_agg
에, 「」와 동작합니다.GROUP BY
.array_agg
를 사용하면 전체 쿼리의 구조를 제한하지 않도록 자체 범위로 순서를 지정할 수 있습니다.기본값과 다른 작업을 수행해야 하는 경우 NULL 정렬 방법에 대한 구문도 있습니다.- 어레이를 구축하면 첫 번째 요소를 채택합니다.(Postgres 어레이는 인덱스가0이 아니라 인덱스화 됩니다).
- 하면 .
array_agg
컬럼에서도 할 수 있습니다.max(total)
더 심플합니다. - ★★★★★★★★★★★★★★★와 달리
DISTINCT ON
를 사용합니다.array_agg
「」를 해 둘 수 .GROUP BY
이치노
쿼리:
SELECT purchases.*
FROM purchases
LEFT JOIN purchases as p
ON
p.customer = purchases.customer
AND
purchases.total < p.total
WHERE p.total IS NULL
어떻게 하는 거야! (가봤어!)
우리는 각각의 구매에 대해 가장 높은 합계만을 가지고 있는지 확인하고 싶습니다.
이론적인 내용(쿼리만 이해하려면 이 부분은 생략)
합계를 T(고객, ID) 함수로 합니다.이 함수에 의해 이름과 ID가 지정된 값이 반환됩니다.T(고객, ID)가 최대치임을 증명하려면 다음 중 하나를 증명해야 합니다.
- x x T ( customer , id )> T ( customer , x ) (이 합계는 해당 고객의 다른 합계보다 높습니다)
또는
- ∃xx T ( customer , id )< T ( customer , x ) (그 고객에 대한 합계는 없습니다)
첫 번째 접근법은 내가 별로 좋아하지 않는 그 이름의 모든 기록을 얻어야 합니다.
두 번째는 이것보다 더 높은 기록은 없을 것이라고 말하는 현명한 방법이 필요할 것이다.
SQL로 돌아가기
이름을 사용하여 테이블을 조인하고 합계가 조인된 테이블보다 작을 경우:
LEFT JOIN purchases as p
ON
p.customer = purchases.customer
AND
purchases.total < p.total
같은 사용자가 가입할 수 있도록 합계가 높은 다른 레코드가 있는 모든 레코드가 있는지 확인합니다.
+--------------+---------------------+-----------------+------+------------+---------+
| purchases.id | purchases.customer | purchases.total | p.id | p.customer | p.total |
+--------------+---------------------+-----------------+------+------------+---------+
| 1 | Tom | 200 | 2 | Tom | 300 |
| 2 | Tom | 300 | | | |
| 3 | Bob | 400 | 4 | Bob | 500 |
| 4 | Bob | 500 | | | |
| 5 | Alice | 600 | 6 | Alice | 700 |
| 6 | Alice | 700 | | | |
+--------------+---------------------+-----------------+------+------------+---------+
그러면 그룹화할 필요 없이 각 구매에 대해 최대 합계를 필터링할 수 있습니다.
WHERE p.total IS NULL
+--------------+----------------+-----------------+------+--------+---------+
| purchases.id | purchases.name | purchases.total | p.id | p.name | p.total |
+--------------+----------------+-----------------+------+--------+---------+
| 2 | Tom | 300 | | | |
| 4 | Bob | 500 | | | |
| 6 | Alice | 700 | | | |
+--------------+----------------+-----------------+------+--------+---------+
그게 우리에게 필요한 답이야
SubQ가 존재하기 때문에 이 솔루션은 Erwin이 지적한 것처럼 효율적이지 않습니다.
select * from purchases p1 where total in
(select max(total) from purchases where p1.customer=customer) order by total desc;
이 방법을 사용합니다(postgresql만).https://wiki.postgresql.org/wiki/First/last_%28aggregate%29
-- Create a function that always returns the first non-NULL item
CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $1;
$$;
-- And then wrap an aggregate around it
CREATE AGGREGATE public.first (
sfunc = public.first_agg,
basetype = anyelement,
stype = anyelement
);
-- Create a function that always returns the last non-NULL item
CREATE OR REPLACE FUNCTION public.last_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $2;
$$;
-- And then wrap an aggregate around it
CREATE AGGREGATE public.last (
sfunc = public.last_agg,
basetype = anyelement,
stype = anyelement
);
이 예시는 거의 그대로 동작합니다.
SELECT FIRST(id), customer, FIRST(total)
FROM purchases
GROUP BY customer
ORDER BY FIRST(total) DESC;
경고: NULL 행을 무시합니다.
편집 1 - 대신 postgres 확장자를 사용합니다.
다음 방법을 사용합니다.http://pgxn.org/dist/first_last_agg/
ubuntu 14.04에 설치하려면:
apt-get install postgresql-server-dev-9.3 git build-essential -y
git clone git://github.com/wulczer/first_last_agg.git
cd first_last_app
make && sudo make install
psql -c 'create extension first_last_agg'
처음과 마지막 기능을 제공하는 포스트그레스 확장입니다.상기 방법보다 빠른 것 같습니다.
편집 2 - 주문 및 필터링
다음과 같은 집계 함수를 사용하는 경우 데이터를 이미 정렬할 필요 없이 결과를 정렬할 수 있습니다.
http://www.postgresql.org/docs/current/static/sql-expressions.html#SYNTAX-AGGREGATES
따라서 주문에 대한 동일한 예는 다음과 같습니다.
SELECT first(id order by id), customer, first(total order by id)
FROM purchases
GROUP BY customer
ORDER BY first(total);
물론 집약에 적합하다고 생각되는 대로 정렬하고 필터링할 수 있습니다.이것은 매우 강력한 구문입니다.
SQL Server에서는 다음을 수행할 수 있습니다.
SELECT *
FROM (
SELECT ROW_NUMBER()
OVER(PARTITION BY customer
ORDER BY total DESC) AS StRank, *
FROM Purchases) n
WHERE StRank = 1
설명:여기서 Group by는 고객을 기준으로 한 후 총 주문 후 각 그룹에 StRank로 일련 번호가 부여되며 StRank가 1인 첫 번째 고객 1명을 제외합니다.
ARRAY_AGG
Postgre의 함수SQL, U-SQL, IBM DB2 및 Google BigQuery SQL:
SELECT customer, (ARRAY_AGG(id ORDER BY total DESC))[1], MAX(total)
FROM purchases
GROUP BY customer
매우 빠른 솔루션
SELECT a.*
FROM
purchases a
JOIN (
SELECT customer, min( id ) as id
FROM purchases
GROUP BY customer
) b USING ( id );
테이블이 id로 인덱싱된 경우 매우 빠릅니다.
create index purchases_id on purchases (id);
Snowflake/Teradata는 다음과 같은 절을 지원합니다.HAVING
기능 " " " " : "
SELECT id, customer, total
FROM PURCHASES
QUALIFY ROW_NUMBER() OVER(PARTITION BY p.customer ORDER BY p.total DESC) = 1
포스트그레SQL, 다른 방법으로는 window 기능을 와 조합하여 사용할 수 있습니다.SELECT DISTINCT
:
select distinct customer_id,
first_value(row(id, total)) over(partition by customer_id order by total desc, id)
from purchases;
가 합성물을 요.(id, total)
따라서 두 값은 같은 집계에 의해 반환됩니다. 항상 할 수 .first_value()
번
이 방법은 다음과 같습니다.
SELECT article, dealer, price
FROM shop s1
WHERE price=(SELECT MAX(s2.price)
FROM shop s2
WHERE s1.article = s2.article
GROUP BY s2.article)
ORDER BY article;
각 기사의 최고가 선택
Windows 의 기능을 사용하면, 다음과 같이 할 수 있습니다.
create table purchases (id int4, customer varchar(10), total integer);
insert into purchases values (1, 'Joe', 5);
insert into purchases values (2, 'Sally', 3);
insert into purchases values (3, 'Joe', 2);
insert into purchases values (4, 'Sally', 1);
select ID, CUSTOMER, TOTAL from (
select ID, CUSTOMER, TOTAL,
row_number () over (partition by CUSTOMER order by TOTAL desc) RN
from purchases) A where RN = 1;
승인된 OMG Pornes의 "Supported by any database" 솔루션은 테스트 속도가 좋습니다.
여기에서는, 같은 어프로치를 제공하지만, 보다 완전하고 깨끗한 데이타베이스 솔루션을 제공하고 있습니다.동점(고객당 최대 합계에 대해 여러 레코드가 있는 경우에도 고객당 1줄만 취득할 수 있다고 가정)이 고려되며, 구매 테이블 내의 실제 일치하는 행에 대해 기타 구매 필드(예: purchase_payment_id)가 선택됩니다.
모든 데이터베이스에서 지원:
select * from purchase
join (
select min(id) as id from purchase
join (
select customer, max(total) as total from purchase
group by customer
) t1 using (customer, total)
group by customer
) t2 using (id)
order by customer
특히 구매 테이블에 (고객, 합계)와 같은 복합 인덱스가 있는 경우에는 이 쿼리가 상당히 빠릅니다.
비고:
t1, t2는 데이터베이스에 따라 삭제할 수 있는 서브쿼리 에일리어스입니다
경고:
using (...)
및 .직접 확장해야 합니다.on t2.id = purchase.id
SQLite를 사용하여 MySQL Postgre를 사용합니다.SQL.
집계된 행 세트에서 (특정 조건에 따라) 행을 선택하는 경우.
것을 (</FONT CHANGE:></FONT CHANGE:></FONT CHANGE:>)
sum/avg
의 집약 기능 의 집약 기능max/min
할 수 없습니다.DISTINCT ON
다음 서브쿼리를 사용할 수 있습니다.
SELECT
(
SELECT **id** FROM t2
WHERE id = ANY ( ARRAY_AGG( tf.id ) ) AND amount = MAX( tf.amount )
) id,
name,
MAX(amount) ma,
SUM( ratio )
FROM t2 tf
GROUP BY name
할 수 요.amount = MAX( tf.amount )
다음 한 가지 제한으로 원하는 조건을 모두 충족합니다.는 여러 할 수 .
하지만 만약 당신이 그런 것을 하고 싶다면 당신은 아마도 윈도우 기능을 찾고 있을 것입니다.
SQL Server에서 가장 효율적인 방법은 다음과 같습니다.
with
ids as ( --condition for split table into groups
select i from (values (9),(12),(17),(18),(19),(20),(22),(21),(23),(10)) as v(i)
)
,src as (
select * from yourTable where <condition> --use this as filter for other conditions
)
,joined as (
select tops.* from ids
cross apply --it`s like for each rows
(
select top(1) *
from src
where CommodityId = ids.i
) as tops
)
select * from joined
그리고 사용된 열에 대해 클러스터화된 인덱스를 생성하는 것을 잊지 마십시오.
이는 전체 MAX FUNTION 및 GROUP BY ID 및 고객으로 쉽게 달성할 수 있습니다.
SELECT id, customer, MAX(total) FROM purchases GROUP BY id, customer
ORDER BY total DESC;
창 기능 dbfiddle을 통한 접근법:
- 「」의 할당
row_number
각 at at:row_number() over (partition by agreement_id, order_id ) as nrow
- 첫 합니다.
filter (where nrow = 1)
with intermediate as (select
*,
row_number() over ( partition by agreement_id, order_id ) as nrow,
(sum( suma ) over ( partition by agreement_id, order_id ))::numeric( 10, 2) as order_suma,
from <your table>)
select
*,
sum( order_suma ) filter (where nrow = 1) over (partition by agreement_id)
from intermediate
언급URL : https://stackoverflow.com/questions/3800551/select-first-row-in-each-group-by-group
'programing' 카테고리의 다른 글
문자열 배열에 문자열이 포함되어 있는지 확인하기 위해 C# 사용 (0) | 2023.04.11 |
---|---|
명령어를 WPF 텍스트블록에 추가하려면 어떻게 해야 하나요? (0) | 2023.04.11 |
여러 줄의 bash 코드를 단말기에 붙여넣고 한 번에 실행하려면 어떻게 해야 하나요? (0) | 2023.04.11 |
여러 열에 걸쳐 중복되는 항목을 찾으려면 어떻게 해야 합니까? (0) | 2023.04.11 |
데이터베이스 다이어그램 지원 개체를 설치할 수 없습니다...유효한 소유자가 없습니다. (0) | 2023.04.11 |