[postgresql] PostgreSQL에서 부호없는 정수를 사용할 수없는 이유는 무엇입니까?

이 게시물 ( MySQL에서 tinyint, smallint, mediumint, bigint 및 int의 차이점은 무엇입니까? )을보고 PostgreSQL이 부호없는 정수를 지원하지 않는다는 것을 깨달았습니다.

누구든지 그 이유를 설명하는 데 도움을 줄 수 있습니까?

대부분의 경우 MySQL에서 자동 증분 기본 키로 부호없는 정수를 사용합니다. 이러한 디자인에서 MySQL에서 PostgreSQL로 데이터베이스를 이식 할 때 어떻게 극복 할 수 있습니까?

감사.



답변

postgresql에 서명되지 않은 유형이없는 이유는 이미 답변되어 있습니다. 그러나 서명되지 않은 유형에는 도메인을 사용하는 것이 좋습니다.

http://www.postgresql.org/docs/9.4/static/sql-createdomain.html

 CREATE DOMAIN name [ AS ] data_type
    [ COLLATE collation ]
    [ DEFAULT expression ]
    [ constraint [ ... ] ]
 where constraint is:
 [ CONSTRAINT constraint_name ]
 { NOT NULL | NULL | CHECK (expression) }

도메인은 유형과 비슷하지만 추가 제약이 있습니다.

구체적인 예를 들어 다음을 사용할 수 있습니다.

CREATE DOMAIN uint2 AS int4
   CHECK(VALUE >= 0 AND VALUE < 65536);

다음은 유형을 남용하려고 할 때 psql이 제공하는 것입니다.

DS1 = # 선택 (346346 :: uint2);

오류 : uint2 도메인의 값이 “uint2_check”검사 제약 조건을 위반합니다.


답변

SQL 표준이 아니므로이를 구현하려는 일반적인 충동은 낮습니다.

다른 정수 유형이 너무 많으면 유형 확인 시스템이 더 취약 해 지므로 혼합에 더 많은 유형을 추가하는 데 약간의 저항이 있습니다.

즉, 할 수없는 이유가 없습니다. 그것은 단지 많은 일입니다.


답변

CHECK 제약 조건을 사용할 수 있습니다. 예 :

CREATE TABLE products (
    product_no integer,
    name text,
    price numeric CHECK (price > 0)
);

또한, PostgreSQL은있다 smallserial, serialbigserial자동 증가에 대한 유형.


답변

DOMAINS에 대한 이야기는 흥미롭지 만 해당 질문의 유일한 출처와 관련이 없습니다. unsigned int에 대한 욕구는 동일한 비트 수로 int의 범위를 두 배로 늘리는 것입니다. 이는 음수를 제외하려는 욕구가 아니라 효율성 인수입니다. 모두가 검사 제약 조건을 추가하는 방법을 알고 있습니다.

누군가가 그것에 대해 물었을 때 , Tome Lane은 다음과 같이 말했습니다.

기본적으로 많은 기존 응용 프로그램을 손상시키지 않는 숫자 프로모션 계층 구조에이를 맞추는 방법을 찾을 수 없으면 이런 일이 발생할 가능성이 없습니다. 우리는 기억이 작용한다면 이것을 한 번 이상 살펴 보았지만 POLA를 위반하지 않는 것처럼 보이는 실행 가능한 디자인을 찾지 못했습니다.

“POLA”는 무엇입니까? Google은 의미없는 10 개의 결과를주었습니다 . 정치적으로 잘못된 생각인지, 따라서 검열되었는지 확실하지 않습니다. 이 검색어가 결과를 산출하지 못하는 이유는 무엇입니까? 도대체 무엇이.

별다른 문제없이 unsigned int를 확장 유형으로 구현할 수 있습니다. C- 함수를 사용하면 성능 저하가 전혀 발생하지 않습니다. PgSQL에는 문자열을 리터럴로 해석하는 쉬운 방법이 있기 때문에 구문 분석기를 확장하여 리터럴을 처리 할 필요가 없습니다. ‘4294966272’:: uint4를 리터럴로 작성하면됩니다. 캐스트도 큰 문제는 아닙니다. 범위 예외를 수행 할 필요조차 없습니다. ‘4294966273’:: uint4 :: int의 의미를 -1024로 처리하면됩니다. 또는 오류를 던질 수 있습니다.

내가 이것을 원했다면 내가했을 것입니다. 그러나 SQL의 반대편에서 Java를 사용하고 있기 때문에 Java에는 부호없는 정수가 없기 때문에 가치가 거의 없습니다. 그래서 나는 아무것도 얻지 못합니다. bigint 열에서 BigInteger를 가져 오면 길이가 길 때 이미 짜증이납니다.

또 다른 한가지, 32 비트 또는 64 비트 유형을 저장할 필요가 있다면 PostgreSQL int4 또는 int8을 각각 사용할 수 있습니다. 다만 자연 순서 나 산술이 안정적으로 작동하지 않는다는 점만 기억하면됩니다. 그러나 저장 및 검색은 그 영향을받지 않습니다.


다음은 간단한 unsigned int8을 구현하는 방법입니다.

먼저 사용하겠습니다

CREATE TYPE name (
    INPUT = uint8_in,
    OUTPUT = uint8_out
    [, RECEIVE = uint8_receive ]
    [, SEND = uint8_send ]
    [, ANALYZE = uint8_analyze ]
    , INTERNALLENGTH = 8
    , PASSEDBYVALUE ]
    , ALIGNMENT = 8
    , STORAGE = plain
    , CATEGORY = N
    , PREFERRED = false
    , DEFAULT = null
)

최소 2 개의 기능 uint8_inuint8_out먼저 정의해야합니다.

CREATE FUNCTION uint8_in(cstring)
    RETURNS uint8
    AS 'uint8_funcs'
    LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION uint64_out(complex)
    RETURNS cstring
    AS 'uint8_funcs'
    LANGUAGE C IMMUTABLE STRICT;

이것을 C uint8_funcs.c에서 구현해야합니다. 그래서 여기에서 복잡한 예제를 사용 하여 간단하게 만듭니다.

PG_FUNCTION_INFO_V1(complex_in);

Datum complex_in(PG_FUNCTION_ARGS) {
    char       *str = PG_GETARG_CSTRING(0);
    uint64_t   result;

    if(sscanf(str, "%llx" , &result) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                 errmsg("invalid input syntax for uint8: \"%s\"", str)));

    return (Datum)SET_8_BYTES(result);
}

아 글쎄, 아니면 그냥 이미 끝났어 .


답변

최신 문서에 따르면 singed integer는 지원되지만 테이블에는 unsigned integer가 없습니다. 그러나 직렬 유형은 0이 아닌 1에서 시작한다는 점을 제외하면 unsigned와 유사합니다. 그러나 상한은 singed와 같습니다. 따라서 시스템에는 서명되지 않은 지원이 없습니다. Peter가 지적했듯이 서명되지 않은 버전을 구현할 수있는 문이 열려 있습니다. 코드를 많이 업데이트해야 할 수도 있습니다. C 프로그래밍 작업을 통해 얻은 작업이 너무 많습니다.

https://www.postgresql.org/docs/10/datatype-numeric.html

integer     4 bytes     typical choice for integer  -2147483648 to +2147483647
serial  4 bytes     autoincrementing integer    1 to 2147483647


답변

Postgres에는 많은 사람들에게 알려지지 않은 부호없는 정수 유형이 OID있습니다.

oid유형은 현재 부호없는 4 바이트 정수로 구현됩니다. […]

oid유형 자체는 비교를 제외하고는 몇가지 연산을. 그러나 정수로 캐스트 한 다음 표준 정수 연산자를 사용하여 조작 할 수 있습니다. (이 작업을 수행하는 경우 서명 된 대 서명되지 않은 혼동 가능성에주의하십시오.)

그러나 숫자 유형 이 아니며 산술 (또는 비트 단위 연산)을 수행하려는 시도는 실패 할 것입니다. 또한 4 바이트 ( INTEGER)에 해당하는 8 바이트 ( BIGINT) 부호없는 유형 이 없습니다 .

따라서 이것을 직접 사용하는 것은 좋은 생각이 아니며 Postgresql 데이터베이스 디자인에서 직렬 기본 키에 대해 항상 INTEGER또는 BIGINT열을 사용해야한다는 다른 모든 답변에 동의 합니다. 전체 도메인을 소진하려면 ( ) 을 감싸십시오 .MINVALUECYCLE

그러나 다른 DBMS에서 마이그레이션하는 것과 같이 입력 / 출력 변환에 매우 유용합니다. 2147483648정수 열에 값 을 삽입하면 ” 오류 : 정수 범위를 벗어남 “이 발생하지만 표현식을 사용하면 2147483648::OID잘 작동합니다.
마찬가지로를 사용하여 정수 열을 텍스트로 선택하면 mycolumn::TEXT어느 시점에서 음수 값을 얻지 만 mycolumn::OID::TEXT항상 자연수를 얻습니다.

dbfiddle.uk에서 예제를 참조하십시오 .


답변