복붙노트

[SQL] 하나 개의 테이블에 여러 계급

SQL

하나 개의 테이블에 여러 계급

나는 다음 필요 캔 사람이 나를 그렇게 도와주세요.

Rank   Cust_Type   Cust_Name   Revenue
1      Top         A           10000
2      Top         B           9000
3      Top         C           8000
1      Bottom      X           5000
2      Bottom      Y           6000
3      Bottom      Z           7000

나는 상부 및 하부 Cust_Type에 대해 별도의 대열에 필요한 모든이의 MySQL입니다.

해결법

  1. ==============================

    1.이것은 조금 까다 롭습니다. 당신은 다음 예제와 같이 변수를 사용할 수 있습니다 :

    이것은 조금 까다 롭습니다. 당신은 다음 예제와 같이 변수를 사용할 수 있습니다 :

    SELECT    ( 
                CASE cust_type 
                WHEN @curType 
                THEN @curRow := @curRow + 1 
                ELSE @curRow := 1 AND @curType := cust_type END
              ) + 1 AS rank,
              cust_type,
              cust_name,
              revenue
    FROM      sales,
              (SELECT @curRow := 0, @curType := '') r
    ORDER BY  cust_type DESC, revenue DESC;
    

    제 (SELECT @curRow = 0 @curType = ') R 부는 별도 SET 명령을 필요로하지 않고, 변수를 초기화 할 수있다.

    테스트 케이스 :

    CREATE TABLE sales (cust_type varchar(10), cust_name varchar(10), revenue int);
    
    INSERT INTO sales VALUES ('Top', 'A', 10000);
    INSERT INTO sales VALUES ('Top', 'B', 9000);
    INSERT INTO sales VALUES ('Top', 'C', 8000);
    INSERT INTO sales VALUES ('Bottom', 'X', 5000);
    INSERT INTO sales VALUES ('Bottom', 'Y', 6000);
    INSERT INTO sales VALUES ('Bottom', 'Z', 7000);
    

    결과:

    +------+-----------+-----------+---------+
    | rank | cust_type | cust_name | revenue |
    +------+-----------+-----------+---------+
    |    1 | Top       | A         |   10000 |
    |    2 | Top       | B         |    9000 |
    |    3 | Top       | C         |    8000 |
    |    1 | Bottom    | Z         |    7000 |
    |    2 | Bottom    | Y         |    6000 |
    |    3 | Bottom    | X         |    5000 |
    +------+-----------+-----------+---------+
    6 rows in set (0.00 sec)
    

    또 다른 테스트 케이스 :

    CREATE TABLE sales (cust_type varchar(10), cust_name varchar(10), revenue int);
    
    INSERT INTO sales VALUES ('Type X', 'A', 7000);
    INSERT INTO sales VALUES ('Type X', 'B', 8000);
    INSERT INTO sales VALUES ('Type Y', 'C', 5000);
    INSERT INTO sales VALUES ('Type Y', 'D', 6000);
    INSERT INTO sales VALUES ('Type Y', 'E', 4000);
    INSERT INTO sales VALUES ('Type Z', 'F', 4000);
    INSERT INTO sales VALUES ('Type Z', 'G', 3000);
    

    결과:

    +------+-----------+-----------+---------+
    | rank | cust_type | cust_name | revenue |
    +------+-----------+-----------+---------+
    |    1 | Type Z    | F         |    4000 |
    |    2 | Type Z    | G         |    3000 |
    |    1 | Type Y    | D         |    6000 |
    |    2 | Type Y    | C         |    5000 |
    |    3 | Type Y    | E         |    4000 |
    |    1 | Type X    | B         |    8000 |
    |    2 | Type X    | A         |    7000 |
    +------+-----------+-----------+---------+
    7 rows in set (0.00 sec)
    

    당신은 분명히 내림차순 대신 오름차순에서 cust_type을 주문할 수 있습니다. 난 그냥 원래 테스트 케이스의 바닥 전에 탑을 가지고 내림차순으로 사용됩니다.

  2. ==============================

    2.나는 CASE, @curRow 및 @curType를 사용하여 솔루션에 문제가 있음을 발견했다. 그것은 MySQL이 쿼리를 처리하는 데 사용하는 실행 계획에 따라 달라집니다. 예를 들어, 당신이 쿼리에 조인 추가하는 경우 표시됩니다. 그런 다음 순위를 올바르게 계산하는 것입니다 않는다는 보장은 없습니다.

    나는 CASE, @curRow 및 @curType를 사용하여 솔루션에 문제가 있음을 발견했다. 그것은 MySQL이 쿼리를 처리하는 데 사용하는 실행 계획에 따라 달라집니다. 예를 들어, 당신이 쿼리에 조인 추가하는 경우 표시됩니다. 그런 다음 순위를 올바르게 계산하는 것입니다 않는다는 보장은 없습니다.

    대답에 약간의 변화를 만들기 :

    CREATE TABLE sales (cust_type_id int, cust_name varchar(10), revenue int);
    CREATE TABLE cust_type (cust_type_id int, type_name varchar(10));
    
    INSERT INTO cust_type VALUES (1, 'Bottom');
    INSERT INTO cust_type VALUES (2, 'Top');
    
    INSERT INTO sales VALUES (2, 'A', 10000);
    INSERT INTO sales VALUES (2, 'B', 9000);
    INSERT INTO sales VALUES (2, 'C', 8000);
    INSERT INTO sales VALUES (1, 'X', 5000);
    INSERT INTO sales VALUES (1, 'Y', 6000);
    INSERT INTO sales VALUES (1, 'Z', 7000);
    

    난 단지 판매 테이블을 쿼리하면 나는 올바른 순서로 순위를 얻을,하지만 난 cust_type 테이블에 가입하면 순위 값은 더 이상 정확

    SELECT    ( 
                CASE s.cust_type_id 
                WHEN @curType 
                THEN @curRow := @curRow + 1 
                ELSE @curRow := 1 AND @curType := s.cust_type_id END
              ) AS rank,
              t.type_name,
              s.cust_name,
              s.revenue
    FROM      sales s,
              cust_type t,
              (SELECT @curRow := 0, @curType := 0) r
    WHERE s.cust_type_id = t.cust_type_id 
    ORDER BY  t.type_name DESC, s.revenue DESC;
    

    결과:

    +------+-----------+-----------+---------+
    | rank | type_name | cust_name | revenue |
    +------+-----------+-----------+---------+
    |    1 | Top       | A         |   10000 |
    |    2 | Top       | B         |    9000 |
    |    3 | Top       | C         |    8000 |
    |    3 | Bottom    | Z         |    7000 |
    |    2 | Bottom    | Y         |    6000 |
    |    1 | Bottom    | X         |    5000 |
    +------+-----------+-----------+---------+
    

    MySQL은 임시 테이블에 초기 쿼리를 실행하고, 순위가 이미 계산 된 후 다음 ORDER BY는 임시 테이블에 대해 실행됩니다.

  3. ==============================

    3.이것은 토마스의 대답과 비슷하지만 조금 더 간단 :

    이것은 토마스의 대답과 비슷하지만 조금 더 간단 :

    SELECT (SELECT COUNT(Cust_Type) FROM sales 
               WHERE Cust_Type = S.Cust_Type AND Revenue >= S.Revenue) AS Rank,
            Cust_Type,
            Cust_Name,
            Revenue 
      FROM sales AS S
      ORDER BY Cust_Type DESC, Rank;
    

    나는 성능이 특히 매우 큰 데이터 세트에, 다니엘의 솔루션과 비교하지 않도록 어떻게 해요, 또는 사용할 경우 복잡한 조인.

  4. ==============================

    4.무엇 정확하게 명확하지 것은 (나는 수익으로 가정) 또는 당신이 모든 값을 원하는 가정 있도록 여부에만 값의 특정 숫자 (예를 들어, 상위 3 개 및 하단 3) 당기는 항목이 평가되는 방법입니다. 그 가정을 감안할 때,

    무엇 정확하게 명확하지 것은 (나는 수익으로 가정) 또는 당신이 모든 값을 원하는 가정 있도록 여부에만 값의 특정 숫자 (예를 들어, 상위 3 개 및 하단 3) 당기는 항목이 평가되는 방법입니다. 그 가정을 감안할 때,

    Select Cust_Name, Cust_Type
        , (Select Count(*)
            From Table As T1
            Where T1.Revenue > T.Revenue ) + 1 As Rank
    From Table As T
    Where Cust_Type = 'Top'
    Union All
    Select Cust_Name, Cust_Type
        , (Select Count(*)
            From Table As T1
            Where T1.Revenue < T.Revenue ) + 1 As Rank
    From Table As T
    Where Cust_Type = 'Bottom'
    

    당신은 당신이 할 수있는 쿼리 하나의 비 노조에서이 작업을 수행하려고 한 경우 :

    Select Cust_Name, Cust_Type
        , Case Z.Cust_Type
            When 'Top' Then Z.TopRank
            Else Z.BottomRank
            End As Rank
    From    (
            Select Cust_Name, Cust_Type
                , (Select Count(*)
                    From Table As T1
                    Where T1.Revenue > T.Revenue ) + 1 As TopRank
                , (Select Count(*)
                    From Table As T1
                    Where T1.Revenue < T.Revenue ) + 1 As BottomRank
            From Table As T
            ) As Z
    
  5. ==============================

    5.판매 수익의 순위 및 별도의 주문을 유지함으로써 나를 위해이 작동합니다.

    판매 수익의 순위 및 별도의 주문을 유지함으로써 나를 위해이 작동합니다.

    SELECT 
             (Select count(s1.revenue)+1 from sales s1 where s.cust_type_id = s1.cust_type_id and s1.revenue > s.revenue) 
              As rank,
    t.type_name,
              s.cust_name,
              s.revenue
    FROM      sales s LEFT JOIN 
              cust_type t USING(cust_type_id)
              Group by t.type_name,s.cust_name,s.revenue DESC order by s.revenue DESC;
    
  6. ==============================

    6.테이블 문제를 가입하기 위해, 나는 해결책을 찾아 냈다.

    테이블 문제를 가입하기 위해, 나는 해결책을 찾아 냈다.

    내가 임시 테이블을 만들고, 나는 순위에 원하는 값의 순서를 유지 MySQL을 이런 식으로.

    DROP TEMPORARY TABLE IF EXISTS tmp_mytable;
    
    CREATE TEMPORARY TABLE tmp_mytable ENGINE = MEMORY
        SELECT mytable.id AS id,
               mytable.login AS Login,
               cliente.myrank_id AS id_myrank,
               mytable.rankvalue AS rankvalue
        FROM mytable
       INNER JOIN myjoin ON (mytable.id_myjoin = myjoin.id)
        ORDER BY 3, 4 DESC;
    
    SELECT id, login, IFNULL(id_myrank, 0) AS id_myrank, rankvalue,
           @rank := IF(@prev_born = IFNULL(id_myrank, 0), @rank + 1, 1) AS ranking,
           @prev_Born := IFNULL(id_myrank, 0) AS fake_field
    FROM tmp_mytable, (select @prev_born := 0, @rank := 0) r
    -- HAVING ranking < 20;
    

    * PS : 내가보기 창조했지만, 너무 작동하지 않습니다.

  7. from https://stackoverflow.com/questions/3162389/multiple-ranks-in-one-table by cc-by-sa and MIT license