보나 관계로 2 열 1 독특한 행(ID&쉼표로 구분된 목록)
-
23-08-2019 - |
문제
나는 뭔가가 필요 유사한 이들 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:
- 이 집계해야 사용할 수 있는 어떠한 형식으로 변환할 수 있는 VARCHAR(255)의미하는 어떤 숫자 일시적 또는 유형입니다.긴 CHAR 열고 blob 종류(바이트,텍스트,BLOB,CLOB)가 처리되지 않습니다.
- 일반 LVARCHAR 제한 집계 크기 2048 바이트입니다.가 필요하다고 생각되는 경우는 더 이상 길이를 지정
LVARCHAR(10240)
(10KiB),예를 들어. - 로 Informix12.10.FC5,최대 길이는 작동하는 것 같 16380;아무것도 더 이상 보 트리거
SQL -528: Maximum output rowsize (32767) exceeded
, 는 놀라움으로 나입니다. 를 제거해야 하는 경우 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
.
의 사용 LVARCHAR
대 SET
요소입니다 사실 처음에 사용 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()
기능.