Waarom is een geheel getal zonder teken niet beschikbaar in PostgreSQL?

Ik kwam dit bericht tegen (Wat is het verschil tussen tinyint, smallint, mediumint, bigint en int in MySQL?) en realiseerde me dat PostgreSQL geen geheel getal zonder teken ondersteunt.

Kan iemand helpen uitleggen waarom dit zo is?

Meestal gebruik ik unsigned integer als automatisch oplopende primaire sleutel in MySQL. Hoe kan ik dit in zo’n ontwerp ondervangen als ik mijn database van MySQL naar PostgreSQL port?

Bedankt.


Antwoord 1, autoriteit 100%

Het zit niet in de SQL-standaard, dus de algemene drang om het te implementeren is lager.

Het hebben van te veel verschillende typen integers maakt het typeresolutiesysteem kwetsbaarder, dus er is enige weerstand om meer typen aan de mix toe te voegen.

Dat gezegd hebbende, is er geen reden waarom het niet zou kunnen. Het is gewoon veel werk.


Antwoord 2, autoriteit 55%

Het is al beantwoord waarom postgresql niet-ondertekende typen mist. Ik zou echter willen voorstellen om domeinen te gebruiken voor niet-ondertekende typen.

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) }

Domein is als een type, maar met een extra beperking.

Voor een concreet voorbeeld zou je kunnen gebruiken

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

Dit is wat psql geeft als ik het type probeer te misbruiken.

DS1=# select (346346 :: uint2);

ERROR: waarde voor domein uint2 schendt controlebeperking “uint2_check”


Antwoord 3, autoriteit 43%

U kunt een CHECK-beperking gebruiken, bijvoorbeeld:

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

Bovendien heeft PostgreSQL de typen serial, smallserialen bigserialvoor automatisch verhogen.


Antwoord 4, autoriteit 24%

Het gepraat over DOMEINEN is interessant, maar niet relevant voor de enige mogelijke oorsprong van die vraag. De wens voor niet-ondertekende ints is om het bereik van ints te verdubbelen met hetzelfde aantal bits, het is een efficiëntieargument, niet de wens om negatieve getallen uit te sluiten, iedereen weet hoe een controlebeperking moet worden toegevoegd.

Wanneer door iemand ernaar wordt gevraagd, Tome Lane verklaarde:

Kortom, er is nul kans dat dit gebeurt, tenzij je kunt vinden
een manier om ze in te passen in de numerieke promotiehiërarchie die dat niet doet
veel bestaande applicaties breken. We hebben hier meer dan naar gekeken
een keer, als het geheugen dient, en er niet in slaagde een werkbaar ontwerp te bedenken
dat leek de POLA niet te schenden.

Wat is de “POLA”? Google gaf me tien resultaten die nietszeggend zijn. Ik weet niet zeker of het politiek incorrecte gedachte is en daarom gecensureerd. Waarom zou deze zoekterm geen resultaat opleveren? Wat dan ook.

Je kunt niet-ondertekende ints als extensietypes implementeren zonder al te veel moeite. Als je het met C-functies doet, zijn er zo goed als geen prestatieboetes. U hoeft de parser niet uit te breiden om met letterlijke waarden om te gaan, omdat PgSQL zo’n gemakkelijke manier heeft om strings als letterlijke waarden te interpreteren, schrijf gewoon ‘4294966272’::uint4 als uw letterlijke waarden. Casts zouden ook niet zo’n groot probleem moeten zijn. U hoeft zelfs geen bereikuitzonderingen te doen, u kunt de semantiek van ‘4294966273’::uint4::int gewoon behandelen als -1024. Of je kunt een foutmelding geven.

Als ik dit had gewild, had ik het gedaan. Maar aangezien ik Java aan de andere kant van SQL gebruik, heeft het voor mij weinig waarde, aangezien Java die niet-ondertekende gehele getallen ook niet heeft. Ik win dus niets. Ik ben al geïrriteerd als ik een BigInteger uit een bigint-kolom krijg, terwijl het in lang zou moeten passen.

Nog iets, als ik 32-bits of 64-bits typen moet opslaan, kan ik respectievelijk PostgreSQL int4 of int8 gebruiken, waarbij ik me bedenk dat de natuurlijke volgorde of rekenkunde niet betrouwbaar zal werken. Maar daar heeft het opslaan en ophalen geen invloed op.


Hier is hoe ik een eenvoudige niet-ondertekende int8 kan implementeren:

Eerst gebruik ik

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
)

de minimaal 2 functies uint8_inen uint8_outdie ik eerst moet definiëren.

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;

moet dit implementeren in C uint8_funcs.c. Dus ik gebruik het complexe voorbeeld van hieren maak het simpel:

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);
}

ach ja, of je kunt het gewoon al gedaan vinden.


Antwoord 5, autoriteit 2%

Volgens de laatste documentatie wordt het ondertekende gehele getal ondersteund, maar geen geheel getal zonder teken in de tabel. Het seriële type lijkt echter een beetje op unsigned, behalve dat het begint bij 1 en niet bij nul. Maar de bovengrens is hetzelfde als getekend. Het systeem heeft dus echt geen ongetekende ondersteuning. Zoals Peter opmerkte, staat de deur open om de niet-ondertekende versie te implementeren. De code moet misschien veel worden bijgewerkt, gewoon te veel werk vanuit mijn ervaring met C-programmeren.

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

Antwoord 6

Postgres heeft een niet-ondertekend geheel getal dat velen niet kennen: oid.

Het type oidis momenteel geïmplementeerd als een niet-ondertekend geheel getal van vier bytes. […]

Het type oidzelf heeft weinig bewerkingen die niet te vergelijken zijn. Het kan zijn
cast echter naar integer en vervolgens gemanipuleerd met behulp van de standaard
gehele operatoren. (Pas op voor mogelijke verwarring tussen ondertekend en niet-ondertekend)
als je dit doet.)

Het is echter geen numeriek type, en proberen er rekenkundige (of zelfs bitsgewijze bewerkingen) mee uit te voeren, zal mislukken. Het is ook slechts 4 bytes (INTEGER), er is geen corresponderend 8-byte (BIGINT) niet-ondertekend type.

Het is dus niet echt een goed idee om dit zelf te gebruiken, en ik ben het eens met alle andere antwoorden dat je in een Postgresql-databaseontwerp altijd een INTEGERof BIGINTkolom voor uw serialprimaire sleutel – met het negatieve begin (MINVALUE) of laat het rondlopen (CYCLE) als je het volledige domein wilt uitputten.

Het is echter heel handig voor input/output-conversie, zoals uw migratie van een ander DBMS. Het invoegen van de waarde 2147483648in een integer-kolom zal leiden tot een “ERROR: integer out of range“, terwijl de uitdrukking 2147483648::OIDwordt gebruikt werkt prima.
Evenzo, wanneer u een integerkolom als tekst selecteert met mycolumn::TEXT, krijgt u op een bepaald moment negatieve waarden, maar met mycolumn::OID::TEXTkrijgt u altijd een natuurlijk getal krijgen.

Bekijk een voorbeeld op dbfiddle.uk.

Other episodes