2010-12-07 2 views
4

아래 표를 예제로 사용하고 나열된 쿼리를 기본 쿼리로 사용하여 최대 ID가있는 행만 선택할 수있는 방법을 추가하고 싶습니다! 두 번째 쿼리를 수행하지 않고도! MySQL이 최대 ID 및 다른 조건과 일치하는 행 선택

TABLE VEHICLES 

id  vehicleName 
----- -------- 
1  cool car 
2  cool car 
3  cool bus 
4  cool bus 
5  cool bus 
6  car 
7  truck 
8  motorcycle 
9  scooter 
10  scooter 
11  bus 

TABLE VEHICLE NAMES 

nameId vehicleName 
------ ------- 
1  cool car 
2  cool bus 
3  car 
4  truck 
5  motorcycle 
6  scooter 
7  bus 

TABLE VEHICLE ATTRIBUTES 

nameId attribute 
------ --------- 
1  FAST 
1  SMALL 
1  SHINY 
2  BIG 
2  SLOW 
3  EXPENSIVE 
4  SHINY 
5  FAST 
5  SMALL 
6  SHINY 
6  SMALL 
7  SMALL 

그리고 기본 쿼리

select a.* 
    from vehicle   a 
    join vehicle_names b using(vehicleName) 
    join vehicle_attribs c using(nameId) 
where c.attribute in('SMALL', 'SHINY') 
and a.vehicleName like '%coo%' 
group 
    by a.id 
having count(distinct c.attribute) = 2; 

그래서 내가 무엇을 달성하고자하는 것은 ID입니다 이름 만 일치하는 각 이름에 대해 하나의 항목과 일치 특정 속성을 가진 행을 선택하는 것입니다 최고!

그래서이 예에서 작업 솔루션은 아래의 행을 반환 :

id  vehicleName 
----- -------- 
2  cool car 
10  scooter 

이 순간에 ID

에 최대의 일종을 사용하는 경우 내가 멋진 차를 위해 모든 항목을 얻을 스쿠터.

내 실제 데이터베이스는 비슷한 구조를 따르고 그 중 수천 개의 항목이 10 개이므로 위와 같은 쿼리를 사용하면 쉽게 3000+ 결과를 반환 할 수 있습니다. 결과가 내 사이트의 검색에 사용됨에 따라 실행 시간을 낮게 유지하기 위해 결과를 100 행으로 제한합니다. 내가 같은 이름이지만 다른 ID만을 가진 "차량"을 반복하는 이유는 새 모델이 지속적으로 추가된다는 것입니다. 그러나 나는 그 모델을 파헤 치고 자하는 사람들을 위해 나이 든 모델을 계속 유지합니다! 그러나 차 이름으로 검색 할 때 가장 오래된 ID 카드를 최신 ID 카드로 반환하고 싶지 않습니다!

정답은 내가 위에 사용하는 쿼리를 적용하여 이름이 일치하는 행만 반환하지만 가장 높은 ID를 갖습니다.

이것이 가능하지 않은 경우 검색 실행 시간을 크게 늘리지 않고 원하는 것을 얻을 수있는 방법에 대한 제안을 보내 주시면 감사하겠습니다.

select max(id), vehicleName 
from VEHICLES 
group by vehicleName 
having count(*)>=2; 
+0

당신이'(nameId, 속성)'에'vehicle_attribs'에 인덱스가 수행
update vehicle a inner join vehicle_names b using (vehicleName) set a.vehicleName = b.nameId; alter table vehicle change column vehicleName nameId int; create table attribs ( attribId int auto_increment primary key, attribute varchar(20), unique key attribute (attribute) ); insert into attribs (attribute) select distinct attribute from vehicle_attribs; update vehicle_attribs a inner join attribs b using (attribute) set a.attribute=b.attribId; alter table vehicle_attribs change column attribute attribId int; 

0 다음 쿼리 주도 무엇입니까? LIKE '% cool %'을 (를) 사용하여 vehicle_names를 검색하면 색인이 사용되지 않습니다. – ajreal

+0

@ajreal vehicle_attribs의 (nameId, attribute)에 PRIMARY KEY가 있습니다. – Tristan

답변

4

, 여기에 내가 어떻게 할 것인지 :

select a.* 
from vehicle a 
    left join vehicle a2 on (a.vehicleName = a2.vehicleName and a.id < a2.id) 
    join vehicle_names b on (a.vehicleName = b.vehicleName) 
    join vehicle_attribs c using(nameId) 
where c.attribute in('SMALL', 'SHINY') 
    and a.vehicleName like '%coo%' 
    and a2.id is null 
group by a.id 
having count(distinct c.attribute) = 2;

수율

: 다른 말했듯이

+----+-------------+ 
| id | vehicleName | 
+----+-------------+ 
| 2 | cool car | 
| 10 | scooter  | 
+----+-------------+ 
2 rows in set (0.00 sec) 

, 정상화는 몇 수준에서 수행 할 수

현재 vehicle_names 테이블을 기본 조회 테이블로 유지하면 다음과 같이 변경됩니다.

select a.id, b.vehicleName 
from vehicle a 
    left join vehicle a2 on (a.nameId = a2.nameId and a.id < a2.id) 
    join vehicle_names b on (a.nameId = b.nameId) 
    join vehicle_attribs c on (a.nameId=c.nameId) 
    inner join attribs d using (attribId) 
where d.attribute in ('SMALL', 'SHINY') 
    and b.vehicleName like '%coo%' 
    and a2.id is null 
group by a.id 
having count(distinct d.attribute) = 2;
+0

각 그룹에서 하나의 레코드가 필요할 때 순위를 매기는 방법을 생각하지 않았습니다. 변수를 가진 솔루션을 제안 하겠지만 쿼리 결과가 쿼리 캐시에 캐시 될 수 있으므로이 방법이 훨씬 좋습니다. – newtover

3

표는 정규화 것 같다하지 않습니다, 그러나 이것은 당신이이 일을 용이하게합니다. 첫 번째 하위 쿼리는 차량의 최신 버전을 찾습니다. 두 번째 쿼리는 "and"조건을 만족시킵니다. 그런 다음 vehiclename에 대한 쿼리에 참여합니다 (키가 무엇입니까?). 이 "최신 차량"논리가 당신을 많이 할 필요가 뭔가 경우

select a.id 
     ,a.vehiclename 
    from (select a.vehicleName, max(id) as id 
      from vehicle a 
     where vehicleName like '%coo%' 
     group by vehicleName 
     ) as a 
    join (select b.vehiclename 
      from vehicle_names b 
      join vehicle_attribs c using(nameId) 
     where c.attribute in('SMALL', 'SHINY') 
     group by b.vehiclename 
     having count(distinct c.attribute) = 2 
     ) as b on (a.vehicleName = b.vehicleName); 

는 작은 제안은 각 차량의 최신 버전을 반환합니다 (아래 참조) 뷰를 생성하는 것입니다. 그런 다음 find-max-query 대신보기를 사용할 수 있습니다. 이 기능은 사용하기 쉽기 때문에 성능상의 이점을 제공하지 않습니다. 당신은 당신이

1) 열을 추가 할 수 있습니다 모델의 적절한 재 설계에 가지 않고

select * 
    from vehicle a 
where id = (select max(b.id) 
       from vehicle b 
       where a.vehiclename = b.vehiclename); 
+0

테이블은 실제와 완전히 다른 샘플입니다! 그룹이 최대 인에게 중요한가? 하지만 내가 대답 한 후에 정말로 최대 행을 선택하기 위해 위에 제공된 쿼리에 무엇을 추가 할 것인가? 감사합니다 – Tristan

1

내가 완전히 모델을 이해 모르겠지만, 그들이 서로 다음 쿼리는 사용자의 요구 사항을 만족 :

+0

보기는 색인이 생성되지 않으므로 OP에있는 레코드의 양으로 쿼리 결과를 가속화하지 못할 수 있습니다. – Danosaure

+0

@Danosaure : 제 제안은 사용 편의성을 높이기위한 것이란 점을 명확히하기 위해 답을 편집하겠습니다. – Ronnis

0

는 응용 프로그램이 관리 할 수 ​​있음을 IsLatest.

이것은 당신이 트랜잭션에 같은

UPDATE a 
SET IsLatest = 0 
WHERE IsLatest = 1 

INSERT new a 

UPDATE a 
SET IsLatest = 1 
WHERE nameId = @last_inserted_id 

를 쿼리를 실행할 수있는 새로운 항목을 추가 할 때 당신이 필요가 완벽하지 않지만 (다음 문제가 해결 될 때까지, 마지막에하지 참조) 질문 만족 당신이 실행하기 전에 또는 트리거

2) 또는 당신은 당신은 하나의 S에 그것을 할 수 있습니다) 쿼리

SELECT MAX(nameId) 
FROM a 
WHERE vehicleName = @name 

3 max_id을 찾을 수 있습니다 QL, 그리고 실제로 나는 당신의 GROUP BY 및 HAVING 제거한

select a.* 
    from vehicle   a 
    join vehicle_names b ON a.vehicleName = b.vehicleName 
    join vehicle_attribs c ON b.nameId = c.nameId AND c.attribute = 'SMALL' 
    join vehicle_attribs d ON b.nameId = c.nameId AND d.attribute = 'SHINY' 
    join vehicle   notmax ON a.vehicleName = b.vehicleName AND a.nameid < notmax.nameid 
where a.vehicleName like '%coo%' 
     AND notmax.id IS NULL 

으로 괜찮은 속도를 가지고 서로를 교체해야한다 (vehicleName, nameId)에 대한 인덱스를 제공 (nameId 당 하나의 속성이 가능하다고 가정)에 가입 .

또한 그룹당 최대 값을 찾는 방법 중 하나를 사용했는데 그 값은 테이블 자체를 조인하고 같은 이름에 대해 더 큰 ID를 가진 레코드가없는 행을 걸러내는 것입니다.

다른 방법으로 'max per group sql'을 검색하십시오. 완료되지는 않았지만 here을 참조하십시오. 당신이 당신의 논리를 유지하려면

+0

니스, 나는 "작고 반짝"을 조인으로 생각하지 않았다. – Ronnis

관련 문제