문제

나는 뭔가가 필요 유사한 이들 2 도록 질문을 사용하여 Informix SQL 구문입니다.

내 데이터에 다음과 같습니다:

id     codes

63592  PELL
58640  SUBL
58640  USBL
73571  PELL
73571  USBL
73571  SUBL

보고 싶어 그것을 다시 와서 다음과 같다:

id     codes 

63592  PELL
58640  SUBL, USBL
73571  PELL, USBL, SUBL

또한 참조 group_concat()에 Informix.

도움이 되었습니까?

해결책

믿는 당신이 대답이 필요로하는 사용자 정의 집계,이와 유사한 하나:

CREATE FUNCTION gc_init(dummy VARCHAR(255)) RETURNING LVARCHAR;
    RETURN '';
END FUNCTION;

CREATE FUNCTION gc_iter(result LVARCHAR, value VARCHAR(255))
    RETURNING LVARCHAR;
    IF result = '' THEN
        RETURN TRIM(value);
    ELSE
        RETURN result || ',' || TRIM(value);
    END IF;
END FUNCTION;

CREATE FUNCTION gc_comb(partial1 LVARCHAR, partial2 LVARCHAR)
    RETURNING LVARCHAR;
    IF partial1 IS NULL OR partial1 = '' THEN
        RETURN partial2;
    ELIF partial2 IS NULL OR partial2 = '' THEN
        RETURN partial1;
    ELSE
        RETURN partial1 || ',' || partial2;
    END IF;
END FUNCTION;

CREATE FUNCTION gc_fini(final LVARCHAR) RETURNING LVARCHAR;
    RETURN final;
END FUNCTION;

CREATE AGGREGATE group_concat
    WITH (INIT = gc_init, ITER = gc_iter,
          COMBINE = gc_comb, FINAL = gc_fini);

주어진 테이블의 요소(라는 요소는)라는 열 이름을 포함한(충분히 습)요소의 이름을,및 다른 열라고 atomic_number,이 쿼리를 생산하고 이 결과는:

SELECT group_concat(name) FROM elements WHERE atomic_number < 10;

Hydrogen,Helium,Lithium,Beryllium,Boron,Carbon,Nitrogen,Oxygen,Fluorine

에 적용되는 질문,당신이 얻어야 합니다 질문에 답변서:

SELECT id, group_concat(codes)
    FROM anonymous_table
    GROUP BY id;

CREATE TEMP TABLE anonymous_table
(
    id      INTEGER NOT NULL,
    codes   CHAR(4) NOT NULL,
    PRIMARY KEY (id, codes)
);

INSERT INTO anonymous_table VALUES(63592, 'PELL');
INSERT INTO anonymous_table VALUES(58640, 'SUBL');
INSERT INTO anonymous_table VALUES(58640, 'USBL');
INSERT INTO anonymous_table VALUES(73571, 'PELL');
INSERT INTO anonymous_table VALUES(73571, 'USBL');
INSERT INTO anonymous_table VALUES(73571, 'SUBL');
INSERT INTO anonymous_table VALUES(73572, 'USBL');
INSERT INTO anonymous_table VALUES(73572, 'PELL');
INSERT INTO anonymous_table VALUES(73572, 'SUBL');

SELECT id, group_concat(codes)
    FROM anonymous_table
    GROUP BY id
    ORDER BY id;

출력에서는:

58640 SUBL,USBL
63592 PELL
73571 PELL,SUBL,USBL
73572 PELL,SUBL,USBL

추가 데이터 세트를 추가되었는지 여부를 테스트 삽입하는 순서 영향을 받는 결과;그것은 나타나지 않게 할 것(코드는 정렬 순서나는 확신이 있는지 여부를 변경하는 방법-reverse-order).


Notes:

  1. 이 집계해야 사용할 수 있는 어떠한 형식으로 변환할 수 있는 VARCHAR(255)의미하는 어떤 숫자 일시적 또는 유형입니다.긴 CHAR 열고 blob 종류(바이트,텍스트,BLOB,CLOB)가 처리되지 않습니다.
  2. 일반 LVARCHAR 제한 집계 크기 2048 바이트입니다.가 필요하다고 생각되는 경우는 더 이상 길이를 지정 LVARCHAR(10240) (10KiB),예를 들어.
  3. 로 Informix12.10.FC5,최대 길이는 작동하는 것 같 16380;아무것도 더 이상 보 트리거 SQL -528: Maximum output rowsize (32767) exceeded, 는 놀라움으로 나입니다.
  4. 를 제거해야 하는 경우 aggregate 사용할 수 있습니다:

    DROP AGGREGATE IF EXISTS group_concat;
    DROP FUNCTION IF EXISTS gc_fini;
    DROP FUNCTION IF EXISTS gc_init;
    DROP FUNCTION IF EXISTS gc_iter;
    DROP FUNCTION IF EXISTS gc_comb;
    

다른 팁

Informix SQL에 대해서는 잘 모르겠지만 MSSQL 또는 Oracle에서는이 작업을 수행 할 수 있습니다.

함께 연결하여 디코딩 또는 케이스 키워드. 그러나이를 위해서는 모든 잠재적 값을 미리 알아야합니다.

Keyword가 마음에 들지 않는 이유는 Informix가 지원하지 않기 때문입니까?

Oracle은 또한 작동하는 키워드 별 연결을 지원하지만 작동하지만 Informix는 다시 지원하지 않을 수 있습니다.

아마도 가장 좋은 대답은 쿼리 후 클라이언트/데이터 계층 에이 출력을 구축하는 것입니다. 이것이 쿼리에서 수행되어야하는 특별한 이유가 있습니까?

또한 Informix를 사용하면 사용자 기능을 만들 수 있으면 연결된 값으로 문자열을 반환 한 함수를 만들 수 있습니다.

건설에 조나단 Leffler 예고에 RET 에 대한 의견의 순서는 연결된 값을 사용하여,Informix12.10FC8DE,나는 다음과 같은 사용자 aggregate:

CREATE FUNCTION mgc_init
(
    dummy VARCHAR(255)
)
RETURNING
    SET(LVARCHAR(2048) NOT NULL);

    RETURN SET{}::SET(LVARCHAR(2048) NOT NULL);

END FUNCTION;

CREATE FUNCTION mgc_iter
(
    p_result SET(LVARCHAR(2048) NOT NULL)
    , p_value VARCHAR(255)
)
RETURNING
    SET(LVARCHAR(2048) NOT NULL);

    IF p_value IS NOT NULL THEN
        INSERT INTO TABLE(p_result) VALUES (TRIM(p_value));
    END IF;

    RETURN p_result;

END FUNCTION;

CREATE FUNCTION mgc_comb
(
    p_partial1 SET(LVARCHAR(2048) NOT NULL)
    , p_partial2 SET(LVARCHAR(2048) NOT NULL)
)
RETURNING
    SET(LVARCHAR(2048) NOT NULL);

    INSERT INTO TABLE(p_partial1)
        SELECT vc1 FROM TABLE(p_partial2)(vc1);

    RETURN p_partial1;

END FUNCTION;

CREATE FUNCTION mgc_fini
(
    p_final SET(LVARCHAR(2048) NOT NULL)
)
RETURNING
    LVARCHAR;

    DEFINE l_str LVARCHAR(2048);
    DEFINE l_value LVARCHAR(2048);

    LET l_str = NULL;

    FOREACH SELECT vvalue1 INTO l_value FROM TABLE(p_final) AS vt1(vvalue1) ORDER BY vvalue1
        IF l_str IS NULL THEN
            LET l_str = l_value;
        ELSE
            LET l_str = l_str || ',' || l_value;
        END IF;
    END FOREACH;

    RETURN l_str;

END FUNCTION;
GRANT EXECUTE ON mgc_fini TO PUBLIC;

CREATE AGGREGATE m_group_concat
WITH
(
    INIT = mgc_init
    , ITER = mgc_iter
    , COMBINE = mgc_comb
    , FINAL = mgc_fini
);

연결된 값이 없을 것이 중복될 것입니다.

내가 사용하는 Informix collections, 즉 SET 을 허용하지 않는 값이 중복되을 유지하려고하는 코드는 다소 간단합니다.

이 방법을 사용하는 것입 SET's 을 유지하는 중간 결과(고 제거하는 중복)와 끝에서 빌드를 연결 문자열 정렬 값은 최종 SET.

의 사용 LVARCHARSET 요소입니다 사실 처음에 사용 VARCHAR 그러나 메모리 사용량이 매우 높습니다.문서 힌트를 내부적으로 Informix 될 수 있습 캐스팅 VARCHAR 하기 CHAR.나 변경하고 그것이 실제로 더 낮은 메모리 사용량(지만 그것은 여전히 높).

그러나,이것은 메모리 집계 소비는 주변에 2 개의 주문 크기보다 더 높은 요나단의 약 2 시간 느린 테스트에 나가 실시(테이블을 사용하여 약 300 000 행).

그래서 치료와 함께 사용합니다.그것은 메모리를 많이 소모하고 그것은 광범위하게 테스트(수 있 메모리 누수가 어딘가에).

편집 1:

나의 코드여야 합 누출 메모리 구조를 어딘가(또는 내부적으로 Informix 유지 컬렉션은 파생된 테이블 주위에,그리고 생성할 수 있습 많은 사람들의).

그래서,여전히 노력하는 것을 피하기 위해 코드 집계에서 기능 C 여기에 또 다른 대안을 사용하여,Informix BSON 기반의 인터페이스를 제공하는 것을 사용하여 많은 메모리를 적게 될 수 있습니다.

CREATE FUNCTION m2gc_init
(
    dummy VARCHAR(255)
)
RETURNING
    BSON;

    RETURN '{"terms":[]}'::JSON::BSON;

END FUNCTION;

CREATE FUNCTION m2gc_iter
(
    p_result BSON
    , p_value VARCHAR(255)
)
RETURNING
    BSON;

    DEFINE l_add_array_element LVARCHAR(2048);

    IF p_value IS NOT NULL THEN
        LET l_add_array_element = '{ $addToSet: { terms: "' || TRIM(p_value) || '" } }';
        LET p_result = BSON_UPDATE(p_result, l_add_array_element);
    END IF;

    RETURN p_result;

END FUNCTION;

CREATE FUNCTION m2gc_comb
(
    p_partial1 BSON
    , p_partial2 BSON
)
RETURNING
    BSON;

    DEFINE l_array_elements LVARCHAR(2048);
    DEFINE l_an_element LVARCHAR(2048);
    DEFINE l_guard INTEGER;

    LET l_array_elements = NULL;
    LET l_guard = BSON_SIZE(p_partial2, 'terms.0');

    IF l_guard > 0 THEN
        WHILE l_guard > 0
            LET l_an_element = BSON_VALUE_LVARCHAR(p_partial2, 'terms.0');
            IF l_array_elements IS NULL THEN
                LET l_array_elements = '"' || l_an_element || '"';
            ELSE
                LET l_array_elements = l_array_elements || ', "' || l_an_element || '"';
            END IF;
            LET p_partial2 = BSON_UPDATE(p_partial2, '{ $pop: { terms: -1 } }');
            LET l_guard = BSON_SIZE(p_partial2, 'terms.0');
        END WHILE;
        LET l_array_elements = '{ $addToSet: { terms: { $each: [ ' || l_array_elements || ' ] } } }';        
        LET p_partial1 = BSON_UPDATE(p_partial1, l_array_elements);
    END IF;

    RETURN p_partial1;

END FUNCTION;


CREATE FUNCTION m2gc_fini
(
    p_final BSON
)
RETURNING
    LVARCHAR;

    DEFINE l_str_agg LVARCHAR(2048);
    DEFINE l_an_element LVARCHAR(2048);
    DEFINE l_iter_int INTEGER;
    DEFINE l_guard INTEGER;

    LET l_str_agg = NULL;
    LET l_guard = BSON_SIZE(p_final, 'terms.0');

    IF l_guard > 0 THEN
        LET p_final = BSON_UPDATE(p_final, '{ $push: { terms: { $each: [], $sort: 1 } } }');    
        LET l_iter_int = 0;
        WHILE l_guard > 0
            LET l_an_element = BSON_VALUE_LVARCHAR(p_final, 'terms.' || l_iter_int);
            IF l_str_agg IS NULL THEN
                LET l_str_agg = TRIM(l_an_element);
            ELSE
                LET l_str_agg = l_str_agg || ',' || TRIM(l_an_element);
            END IF;
            LET l_iter_int = l_iter_int + 1;
            LET l_guard = BSON_SIZE(p_final, 'terms.' || l_iter_int);
        END WHILE;
    END IF;
    RETURN l_str_agg;

END FUNCTION;

CREATE AGGREGATE m2_group_concat
WITH
(
    INIT = m2gc_init
    , ITER = m2gc_iter
    , COMBINE = m2gc_comb
    , FINAL = m2gc_fini
)
;

집계된다는 것입니다 주문과 중복되지 않.

다시,이것이 제대로 테스트됩니다.그것은 단지 POC.

문제 중 하나가지 않았는지 살균 입력 값입니다.의 일부 BSON 조작 기능을 받는 매개변수가 되는 문자열을 연결하여 및 비출 수 있는 캐릭터 휴식을 사람들 매개 변수입니다.예를 들어,문자열 값으로 따옴표에 그것: 'I"BrokeIt')을 자극 할 수 있습니다 다양의 오류(주장한 오류 포함)입니다.

고 나는 다른 문제입니다.

그러나 메모리를 소모의 이 구현에서는 동일한 크기의 순서로 요나단의 예에서며 약 60%정도 늦(다만,매우 기초적인 테스트가 수행되었).

나는 당신을 가리키고 싶습니다 이 답변 스택 오버플로에서 또 다른 유사한 질문에. 당신은 mysql과 같은 것을 찾고 있습니다 group_concat() 기능.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top