[SQL] 어떻게 카테고리 별 최신 네 개의 항목을 선택하려면?
SQL어떻게 카테고리 별 최신 네 개의 항목을 선택하려면?
나는 항목의 데이터베이스를 가지고있다. 각 항목은 범주 테이블의 범주 ID로 분류됩니다. 나는 페이지를 나열하는 모든 범주를 만들려고하고, 각 범주 아래에 그 카테고리에서 4 개 최신 항목을 표시합니다.
예를 들면 :
애완 동물 용품
img1
img2
img3
img4
애완 동물 사료
img1
img2
img3
img4
나는 쉽게과 같이 각 범주에 대한 데이터베이스를 조회하여이 문제를 해결할 수 있음을 알고있다 :
SELECT id FROM category
그런 다음 데이터를 반복하고 새로운 항목을 잡아 각 범주에 대한 데이터베이스를 조회 :
SELECT image FROM item where category_id = :category_id ORDER BY date_listed DESC LIMIT 4
난 그냥 한 쿼리를 사용하고 데이터를 모두 잡을 수 있다면 내가 알아 내려고 노력하고있어입니다. 나는 아마도 데이터베이스에 대한 호출의 수를 줄일 것이라고 생각, 그래서 나는 33 종류가 있습니다.
이 가능하면 누구나 알아? 33 호출하는 경우 큰 거래는 난 그냥 쉬운 방법을해야한다고하지 않습니다.
해결법
-
==============================
1.이것은 가장 큰-N 당 그룹 문제이며, 그것은 매우 일반적인 SQL의 질문입니다.
이것은 가장 큰-N 당 그룹 문제이며, 그것은 매우 일반적인 SQL의 질문입니다.
여기에 외부 조인과 나는 그것을 해결하는 방법은 다음과 같습니다
SELECT i1.* FROM item i1 LEFT OUTER JOIN item i2 ON (i1.category_id = i2.category_id AND i1.item_id < i2.item_id) GROUP BY i1.item_id HAVING COUNT(*) < 4 ORDER BY category_id, date_listed;
내가 항목 테이블의 기본 키를 가정하고있어 ITEM_ID이며, 그것은 일정하게 증가하는 pseudokey 있다고. 즉, ITEM_ID에서 큰 값이 항목에서 새로운 행에 대응한다.
여기 그것이 작동하는 방법 : 각 항목에 대해, 새로운 다른 항목 중 일부가 있습니다. 예를 들어, 네 번째 최신 항목보다 새로운 세 가지 항목이 있습니다. 아주 최신 항목보다 새로운 제로 항목이 있습니다. 우리는 새로운이며, I1과 같은 범주를 항목 (I2)의 세트에 각 항목 (I1)를 비교하려는 그래서. 그 새로운 항목의 수가 4보다 작은 경우, I1은 우리가 포함 그 중 하나입니다. 그렇지 않으면, 포함되지 않습니다.
이 솔루션의 장점은 상관없이 얼마나 많은 종류 작동 없다는 것입니다, 당신은 카테고리를 변경하는 경우 작업을 계속합니다. 또한 어떤 종류의 항목 수가 4보다 적은 경우에도 작동합니다.
작동하지만 사용자 변수 기능은 MySQL에 의존하는 또 다른 방법 :
SELECT * FROM ( SELECT i.*, @r := IF(@g = category_id, @r+1, 1) AS rownum, @g := category_id FROM (@g:=null, @r:=0) AS _init CROSS JOIN item i ORDER BY i.category_id, i.date_listed ) AS t WHERE t.rownum <= 3;
MySQL은 8.0.3 SQL 표준 윈도우 함수에 대한 지원을 소개했다. 이제 우리는 문제를 다른 RDBMS가하는 방식의이 종류를 해결할 수 있습니다 :
WITH numbered_item AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY item_id) AS rownum FROM item ) SELECT * FROM numbered_item WHERE rownum <= 4;
-
==============================
2.이 솔루션은 다른 SO 솔루션에서 적응이 관련 / 비슷한 질문을 찾는 당신에게 RageZ 감사합니다.
이 솔루션은 다른 SO 솔루션에서 적응이 관련 / 비슷한 질문을 찾는 당신에게 RageZ 감사합니다.
노트
이 솔루션은 저스틴의 사용 사례에 대한 만족스러운 것 같다. 사용 사례에 따라이 게시물에 빌 Karwin 또는 데이비드 안드레스 '솔루션을 확인 할 수 있습니다. 빌의 솔루션은 내 투표가있다! 나는 다음 서로 두 쿼리를 넣어, 왜 참조 ;-)
내 솔루션의 장점은 CATEGORY_ID 당 하나 개의 레코드 (항목 테이블에서 정보를 원하시면 "롤업"입니다)을 반환합니다. 원하는 행의 수 증가에 따라 내 솔루션의 가장 큰 단점은 가독성의 부족과 그 복잡성이 증가이다 (오히려 6보다 카테고리 당 6 개 행이하는 말). 또한 항목 테이블의 행 수의 성장에 따라 약간 느려질 수 있습니다. (에 관계없이 모든 솔루션은 항목 테이블의 자격 행 적은 수의 더 나은 수행하고,이 중 하나를 주기적으로 삭제하거나 오래된 항목을 이동 및 / 또는 이른 행 아웃 도움말 SQL 필터에 플래그를 소개하는 것이 좋습니다)
첫 번째 시도 (작동하지 않았다!) ...
이 접근 방식의 문제점은 하위 쿼리가 [정당하지만 나쁜 우리가] 자기 조인에 의해 정의 된 직교 제품을 기반으로, 매우 많은 열을 생산하는 것이라고했다 ...
SELECT id, CategoryName(?), tblFourImages.* FROM category JOIN ( SELECT i1.category_id, i1.image as Image1, i2.image AS Image2, i3.image AS Image3, i4.image AS Image4 FROM item AS i1 LEFT JOIN item AS i2 ON i1.category_id = i2.category_id AND i1.date_listed > i2.date_listed LEFT JOIN item AS i3 ON i2.category_id = i3.category_id AND i2.date_listed > i3.date_listed LEFT JOIN item AS i4 ON i3.category_id = i4.category_id AND i3.date_listed > i4.date_listed ) AS tblFourImages ON tblFourImages.category_id = category.id --WHERE here_some_addtional l criteria if needed ORDER BY id ASC;
두 번째 시도. (작품을 좋아!)
나열 된 날짜를 강제 부질 첨가에 절 될 WHERE 최근, 초 최신 thrird lateest 등 각각 (및 대 미만의 4 개 항목이 때 널 경우 허용 I1, I2, I3 등 주어진 카테고리 ID). 또한, 화상이없는 "판매"되는 항목 또는 항목을 도시 방지 무관 필터 절을 첨가 하였다 (추가 조건)
이 논리는 (주어진 CATEGORY_ID에 대한) 중복 날짜 목록에 값이 없음을 가정한다. 이러한 경우가 그렇지 않은 경우 중복 행을 만들 것입니다. 효과적으로 나와있는 날짜의 사용은 단조 증가 기본 키의 빌의 솔루션에서 요구 / 정의 된 것입니다.
SELECT id, CategoryName, tblFourImages.* FROM category JOIN ( SELECT i1.category_id, i1.image as Image1, i2.image AS Image2, i3.image AS Image3, i4.image AS Image4, i4.date_listed FROM item AS i1 LEFT JOIN item AS i2 ON i1.category_id = i2.category_id AND i1.date_listed > i2.date_listed AND i2.sold = FALSE AND i2.image IS NOT NULL AND i1.sold = FALSE AND i1.image IS NOT NULL LEFT JOIN item AS i3 ON i2.category_id = i3.category_id AND i2.date_listed > i3.date_listed AND i3.sold = FALSE AND i3.image IS NOT NULL LEFT JOIN item AS i4 ON i3.category_id = i4.category_id AND i3.date_listed > i4.date_listed AND i4.sold = FALSE AND i4.image IS NOT NULL WHERE NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i1.date_listed) AND (i2.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i2.date_listed AND date_listed <> i1.date_listed))) AND (i3.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i3.date_listed AND date_listed <> i1.date_listed AND date_listed <> i2.date_listed))) AND (i4.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i4.date_listed AND date_listed <> i1.date_listed AND date_listed <> i2.date_listed AND date_listed <> i3.date_listed))) ) AS tblFourImages ON tblFourImages.category_id = category.id --WHERE -- ORDER BY id ASC;
이제 ... 내가 ITEM_ID 키를 소개하는 경우 다음을 비교하고 "외부"쿼리에이 목록을 제공하기 위해 빌의 솔루션을 사용합니다. 빌의 접근 방식이 더 나은 이유를 볼 수 있습니다 ...
SELECT id, CategoryName, image, date_listed, item_id FROM item I LEFT OUTER JOIN category C ON C.id = I.category_id WHERE I.item_id IN ( SELECT i1.item_id FROM item i1 LEFT OUTER JOIN item i2 ON (i1.category_id = i2.category_id AND i1.item_id < i2.item_id AND i1.sold = 'N' AND i2.sold = 'N' AND i1.image <> '' AND i2.image <> '' ) GROUP BY i1.item_id HAVING COUNT(*) < 4 ) ORDER BY category_id, item_id DESC
-
==============================
3.다른 데이터베이스에서 당신은 ROW_NUMBER 함수를 사용하여이 작업을 수행 할 수 있습니다.
다른 데이터베이스에서 당신은 ROW_NUMBER 함수를 사용하여이 작업을 수행 할 수 있습니다.
SELECT category_id, image, date_listed FROM ( SELECT category_id, image, date_listed, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY date_listed DESC) AS rn FROM item ) AS T1 WHERE rn <= 4
불행하게도 MySQL은 ROW_NUMBER 기능을 지원하지 않습니다,하지만 당신은 변수를 사용하여 에뮬레이션 할 수 있습니다 :
SELECT category_id, image, date_listed FROM ( SELECT category_id, image, date_listed, @rn := IF(@prev = category_id, @rn + 1, 1) AS rn, @prev := category_id FROM item JOIN (SELECT @prev := NULL, @rn = 0) AS vars ORDER BY category_id, date_listed DESC ) AS T1 WHERE rn <= 4
온라인으로 작업을 참조하십시오 sqlfiddle를
다음과 같이 작동합니다 :
-
==============================
4.아니 아주 예쁜하지만 :
아니 아주 예쁜하지만 :
SELECT image FROM item WHERE date_listed IN (SELECT date_listed FROM item ORDER BY date_listed DESC LIMIT 4)
-
==============================
5.당신의 범주는 어떻게 일정에 따라, 다음은 간단한 경로입니다
당신의 범주는 어떻게 일정에 따라, 다음은 간단한 경로입니다
SELECT C.CategoryName, R.Image, R.date_listed FROM ( SELECT CategoryId, Image, date_listed FROM ( SELECT CategoryId, Image, date_listed FROM item WHERE Category = 'Pet Supplies' ORDER BY date_listed DESC LIMIT 4 ) T UNION ALL SELECT CategoryId, Image, date_listed FROM ( SELECT CategoryId, Image, date_listed FROM item WHERE Category = 'Pet Food' ORDER BY date_listed DESC LIMIT 4 ) T ) RecentItemImages R INNER JOIN Categories C ON C.CategoryId = R.CategoryId ORDER BY C.CategoryName, R.Image, R.date_listed
-
==============================
6.쇼 아래 코드 루프에서 할 수있는 방법 확실히 편집을 많이 필요하지만 난이 도움이되기를 바랍니다.
쇼 아래 코드 루프에서 할 수있는 방법 확실히 편집을 많이 필요하지만 난이 도움이되기를 바랍니다.
declare @RowId int declare @CategoryId int declare @CategoryName varchar(MAX) create table PART (RowId int, CategoryId int, CategoryName varchar) create table NEWESTFOUR(RowId int, CategoryId int, CategoryName varchar, Image image) select RowId = ROW_NUMBER(),CategoryId,CategoryName into PART from [Category Table] set @PartId = 0 set @CategoryId = 0 while @Part_Id <= --count begin set @PartId = @PartId + 1 SELECT @CategoryId = category_id, @CategoryName = category_name from PART where PartId = @Part_Id SELECT RowId = @PartId, image,CategoryId = @category_id, CategoryName = @category_name FROM item into NEWESTFOUR where category_id = :category_id ORDER BY date_listed DESC LIMIT 4 end select * from NEWESTFOUR drop table NEWESTFOUR drop table PART
-
==============================
7.최근에 나는 데이터베이스에 독립적 인 나를 위해 일한 쿼리를 시도, 비슷한 상황을 가로 질러왔다
최근에 나는 데이터베이스에 독립적 인 나를 위해 일한 쿼리를 시도, 비슷한 상황을 가로 질러왔다
SELECT i.* FROM Item AS i JOIN Category c ON i.category_id=c.id WHERE (SELECT count(*) FROM Item i1 WHERE i1.category_id=i.category_id AND i1.date_listed>=i.date_listed) <=3 ORDER BY category_id,date_listed DESC;
이보다 새로운 항목이 적은 3보다 경우는 루프 2 실행하고 확인하는 것과 같습니다
-
==============================
8.확인을 인터넷 검색 빠른 답변 후 것 그것은 MySQL을 적어도 수는 없습니다
확인을 인터넷 검색 빠른 답변 후 것 그것은 MySQL을 적어도 수는 없습니다
기준이 스레드
어쩌면 서버를 아래로 떨어질 수 있도록하는 것을 두려워하는 경우 해당 쿼리의 결과를 캐시한다 당신은 코드를 더 잘 수행 할
from https://stackoverflow.com/questions/1442527/how-to-select-the-newest-four-items-per-category by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 어떻게 Access에서 서로 다른 상황에서 VBA에서 매개 변수를 사용합니까? (0) | 2020.03.09 |
---|---|
[SQL] MySQL은 : ORDER BY RAND 대안 () (0) | 2020.03.09 |
[SQL] SQL 다중 열 정렬 (0) | 2020.03.09 |
[SQL] 어떻게 MySQL의에서 재귀 SELECT 쿼리를 할까? (0) | 2020.03.09 |
[SQL] 어떻게 시간에 날짜 시간을 캐스팅 (0) | 2020.03.09 |