복붙노트

[SQL] 다른 열을 기준 서열의 PostgreSQL

SQL

다른 열을 기준 서열의 PostgreSQL

내가 같은 테이블이 있다고 가정하자 :

Column   |     Type    |                        Notes
---------+------------ +----------------------------------------------------------
 id      | integer     | An ID that's FK to some other table
 seq     | integer     | Each ID gets its own seq number
 data    | text        | Just some text, totally irrelevant.

SEQ ID +가 결합 열쇠이다.

내가보고 싶은 것은 :

ID  | SEQ   |                        DATA
----+------ +----------------------------------------------
 1  | 1     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 1  | 2     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 1  | 3     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 1  | 4     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 2  | 1     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 1     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 2     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 3     | Quick brown fox, lorem ipsum, lazy dog, etc etc.
 3  | 4     | Quick brown fox, lorem ipsum, lazy dog, etc etc.

당신이 볼 수 있듯이, ID와 서열의 조합은 고유합니다.

나는 확실하지 내 테이블을 설정하는 방법에있어 (또는 삽입 문을?)이 작업을 수행 할 수 있습니다. I 이드에 따라 서브 서열 인 서열 결과 삽입 ID 및 데이터 싶다.

해결법

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

    1.문제 없어요! 우리는 두 개의 테이블, 사물과 물건을 만들 것입니다. 물건은 당신이 당신의 질문에 설명하는 테이블이 될 것, 사물은 참조하는 하나입니다 :

    문제 없어요! 우리는 두 개의 테이블, 사물과 물건을 만들 것입니다. 물건은 당신이 당신의 질문에 설명하는 테이블이 될 것, 사물은 참조하는 하나입니다 :

    CREATE TABLE things (
        id serial primary key,
        name text
    );
    
    CREATE TABLE stuff (
        id integer references things,
        seq integer NOT NULL,
        notes text,
        primary key (id, seq)
    );
    

    그리고 우리는 새로운 순서를 행이 만들어 질 때마다 생성됩니다 트리거와 함께 일을 설정합니다 :

    CREATE FUNCTION make_thing_seq() RETURNS trigger
        LANGUAGE plpgsql
        AS $$
    begin
      execute format('create sequence thing_seq_%s', NEW.id);
      return NEW;
    end
    $$;
    
    CREATE TRIGGER make_thing_seq AFTER INSERT ON things FOR EACH ROW EXECUTE PROCEDURE make_thing_seq();
    

    이제 우리는 등 thing_seq_1, thing_seq_2, 등, 될 겁니다 ...

    이제 물건을 다른 트리거 있도록 올바른 순서 각 시간을 사용 :

    CREATE FUNCTION fill_in_stuff_seq() RETURNS trigger
        LANGUAGE plpgsql
        AS $$
    begin
      NEW.seq := nextval('thing_seq_' || NEW.id);
      RETURN NEW;
    end
    $$;
    
    CREATE TRIGGER fill_in_stuff_seq BEFORE INSERT ON stuff FOR EACH ROW EXECUTE PROCEDURE fill_in_stuff_seq();
    

    즉 행이 물건에 갈 때, ID 열에는 NEXTVAL에 전화를 올바른 순서를 찾는 데 사용되어 있는지 확인합니다.

    여기 데모입니다 :

    test=# insert into things (name) values ('Joe');
    INSERT 0 1
    test=# insert into things (name) values ('Bob');
    INSERT 0 1
    test=# select * from things;
     id | name
    ----+------
      1 | Joe
      2 | Bob
    (2 rows)
    
    test=# \d
                  List of relations
     Schema |     Name      |   Type   |  Owner
    --------+---------------+----------+----------
     public | stuff         | table    | jkominek
     public | thing_seq_1   | sequence | jkominek
     public | thing_seq_2   | sequence | jkominek
     public | things        | table    | jkominek
     public | things_id_seq | sequence | jkominek
    (5 rows)
    
    test=# insert into stuff (id, notes) values (1, 'Keychain');
    INSERT 0 1
    test=# insert into stuff (id, notes) values (1, 'Pet goat');
    INSERT 0 1
    test=# insert into stuff (id, notes) values (2, 'Family photo');
    INSERT 0 1
    test=# insert into stuff (id, notes) values (1, 'Redundant lawnmower');
    INSERT 0 1
    test=# select * from stuff;
     id | seq |        notes
    ----+-----+---------------------
      1 |   1 | Keychain
      1 |   2 | Pet goat
      2 |   1 | Family photo
      1 |   3 | Redundant lawnmower
    (4 rows)
    
    test=#
    
  2. ==============================

    2.당신은 당신의 서열 값을 할당하는 윈도우 함수를 사용할 수 있습니다, 같은 :

    당신은 당신의 서열 값을 할당하는 윈도우 함수를 사용할 수 있습니다, 같은 :

    INSERT INTO YourTable
        (ID, SEQ, DATA)
        SELECT ID, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY DATA), DATA
            FROM YourSource
    
  3. ==============================

    3.서열은 행이 삽입되는 순서를 반영 (또는 반영해야한다) 경우, 차라리 자동으로 입력됩니다 타임 스탬프를 사용하는 것 등) (ROW_NUMBER를 사용하여 행을 선택하면 즉석에서 일련 번호를 생성합니다 :

    서열은 행이 삽입되는 순서를 반영 (또는 반영해야한다) 경우, 차라리 자동으로 입력됩니다 타임 스탬프를 사용하는 것 등) (ROW_NUMBER를 사용하여 행을 선택하면 즉석에서 일련 번호를 생성합니다 :

    create table some_table
    ( 
      id          integer   not null,
      inserted_at timestamp not null default current_timestamp,
      data text
    );
    

    는 서열 열을 얻으려면, 당신은 할 수 있습니다 :

    select id,  
           row_number() over (partition by id order by inserted_at) as seq,
           data
    from some_table
    order by id, seq;
    

    선택하지만 (특히 ID에 대한 인덱스, 배열)와 영구 서열 열을 사용하는 것에 비해 다소 느리게 될 것이다.

    그건 당신이 중 하나가보기를 구체화하여, 또는 서열 열을 추가하고 정기적으로 업데이트로 볼 수 문제가 될 경우 (I는 성능상의 이유로 트리거에서이 작업을 수행 할 것입니다).

    SQLFiddle 예 : http://sqlfiddle.com/#!15/db69b/1

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

    4.그냥 추측.

    그냥 추측.

    INSERT INTO TABLE (ID, SEQ, DATA)
    VALUES
    (
     IDVALUE,
     (SELECT max(SEQ) +1 FROM TABLE WHERE ID = IDVALUU),
     DATAVALUE
    );
    
  5. ==============================

    5.다음은 표준 SQL을 사용하여 간단한 방법입니다 :

    다음은 표준 SQL을 사용하여 간단한 방법입니다 :

    INSERT INTO mytable (id, seq, data)
    SELECT << your desired ID >>,
           COUNT(*) + 1,
           'Quick brown fox, lorem ipsum, lazy dog, etc etc.'
    FROM mytable
    WHERE id = << your desired ID (same as above) >>;
    

    SQL 바이올린 데모를 참조하십시오.

    (당신이 삽입 직후 같은 방법을 사용하여 행을 업데이트하는 트리거를 만드는 것이 좋습니다 수있는 비트 영리가되고 싶어합니다.)

  6. ==============================

    6.나는 dynamicaly A가 트리 구조, 한 번에 모든 ID를 추가하지 저장할 같은 요구를했다. 이들의 수천이있을 수 있기 때문에 나는 각 그룹에 대해 순서 표를 사용하지 선호합니다. 이 경쟁 조건이 증명되어야한다, 그래서 그것은 집중적 인 멀티 프로세싱 환경에서 실행됩니다. 여기에 수준 1 삽입 fonction. 다른 레벨은 동일한 원리를 따릅니다.

    나는 dynamicaly A가 트리 구조, 한 번에 모든 ID를 추가하지 저장할 같은 요구를했다. 이들의 수천이있을 수 있기 때문에 나는 각 그룹에 대해 순서 표를 사용하지 선호합니다. 이 경쟁 조건이 증명되어야한다, 그래서 그것은 집중적 인 멀티 프로세싱 환경에서 실행됩니다. 여기에 수준 1 삽입 fonction. 다른 레벨은 동일한 원리를 따릅니다.

    각 그룹은 독립적으로 재사용 불가능한 ID를두고 순차적으로, 기능은 그룹 이름 및 하위 그룹의 이름을 수신하면 기존의 ID를 제공하거나 생성 및 새로운 ID를 반환한다. 나는 하나의 선택을 가지고 루프를 시도했지만 코드는 긴 및 열심히 읽기가 같습니다.

    CREATE OR REPLACE FUNCTION getOrInsert(myGroupName TEXT, mySubGroupName TEXT)
      RETURNS INT AS
    $BODY$
    DECLARE
       myId INT;
    BEGIN -- 1st try to get it if it already exists
       SELECT id INTO myId FROM myTable
          WHERE groupName=myGroupName AND subGroupName=mySubGroupName;
       IF NOT FOUND THEN
          -- Only 1 session can get it but others can read
          LOCK TABLE myTable IN SHARE ROW EXCLUSIVE MODE; 
          -- 2nd try in case of race condition
          SELECT id INTO myId FROM myTable
             WHERE groupName=myGroupName AND subGroupName=mySubGroupName;
          IF NOT FOUND THEN -- Doesn't exist. Get next ID for this group.
             SELECT COALESCE(MAX(id), 0)+1 INTO myId FROM myTable
                WHERE groupName=myGroupName;
             INSERT INTO myTable (groupName, id, subGroupName)
                VALUES (myGroupName, myId, mySubGroupName);
          END IF;
       END IF;
       RETURN myId;
    END;
    $BODY$
      LANGUAGE plpgsql VOLATILE COST 100;
    

    그것을 시도하려면 :

    CREATE TABLE myTable (GroupName TEXT, SubGroupName TEXT, id INT);
    SELECT getOrInsert('groupA', 'subgroupX'); -- Returns 1
    ...
    SELECT * FROM myTable;
     groupname | subgroupname | id 
    -----------+--------------+----
     groupA    | subgroupX    |  1
     groupA    | subgroupY    |  2
     groupA    | subgroupZ    |  3
     groupB    | subgroupY    |  1
    
  7. ==============================

    7.PostgreSQL의 지원과 같은 고유의 열을 그룹화 :

    PostgreSQL의 지원과 같은 고유의 열을 그룹화 :

    CREATE TABLE example (
        a integer,
        b integer,
        c integer,
        UNIQUE (a, c)
    );
    

    PostgreSQL의 문서를 참조하십시오 - 5.3.3 항을

    쉬운 :-)

  8. ==============================

    8.나는 어떤 PostgreSQL을 특정 경험이없는,하지만 당신은 삽입 문에서 하위 쿼리를 사용할 수 있습니까? Mysqlish처럼 뭔가,

    나는 어떤 PostgreSQL을 특정 경험이없는,하지만 당신은 삽입 문에서 하위 쿼리를 사용할 수 있습니까? Mysqlish처럼 뭔가,

    INSERT INTO MYTABLE SET 
       ID=4, 
       SEQ=(  SELECT MAX(SEQ)+1 FROM MYTABLE WHERE ID=4  ),
       DATA="Quick brown fox, lorem ipsum, lazy dog, etc etc."
    
  9. from https://stackoverflow.com/questions/6821871/postgresql-sequence-based-on-another-column by cc-by-sa and MIT license