sql >> Database teknologi >  >> RDS >> PostgreSQL

Forstå forskellen mellem int literal vs int parameter i PL/pgSQL funktion

Hvorfor?

PL/pgSQL udfører SQL-forespørgsler som forberedte sætninger . Manualen om parametersubstitution:

Bemærk udtrykket værdier . Kun aktuelle værdier kan parametreres, men ikke nøgleord, identifikatorer eller typenavne. 32 i bit(32) udseende som en værdi, men modifikationen af ​​en datatype er kun en "værdi" internt og kan ikke parametreres. SQL kræver at kende datatyper på planlægningsstadiet, den kan ikke vente på udførelsesfasen.

Du kunne nå dit mål med dynamisk SQL og EXECUTE . Som proof of concept :

CREATE OR REPLACE FUNCTION lpad_bits(val varbit, sz int = 32, OUT outval varbit) AS
$func$
BEGIN
   EXECUTE format('SELECT $1::bit(%s) >> $2', sz)  -- literal
   USING val, sz - length(val)                     -- values
   INTO outval;
END
$func$  LANGUAGE plpgsql IMMUTABLE;

Ring til:

SELECT lpad_bits(b'1001100111000', 32);  

Bemærk forskellen mellem sz bliver brugt som bogstavelig at bygge sætningen og dens anden forekomst, hvor den bruges som værdi , der kan overføres som parameter.

Hurtigere alternativer

En overlegen løsning til netop denne opgave er at bruge lpad() like @Abelisto foreslog :

CREATE OR REPLACE FUNCTION lpad_bits2(val varbit, sz int = 32)
  RETURNS varbit AS
$func$
SELECT lpad(val::text, sz, '0')::varbit;
$func$  LANGUAGE sql IMMUTABLE;

(Enklere som almindelig SQL-funktion, der også tillader funktionsinlining i forbindelse med ydre forespørgsler.)

Flere gange hurtigere end ovenstående funktion. En mindre fejl:vi skal caste til text og tilbage til varbit . Desværre, lpad() er i øjeblikket ikke implementeret for varbit . Manualen:

overlay() er tilgængelig, kan vi have en billigere funktion:

CREATE OR REPLACE FUNCTION lpad_bits3(val varbit, base varbit = '00000000000000000000000000000000')
  RETURNS varbit AS
$func$
SELECT overlay(base PLACING val FROM bit_length(base) - bit_length(val))
$func$  LANGUAGE sql IMMUTABLE;

Hurtigere, hvis du kan arbejde med varbit værdier til at begynde med. (Fordelen er (delvist) annulleret, hvis du skal caste text til varbit alligevel.)

Ring til:

SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000',  repeat('0', 32)::varbit);

Vi kan overlappe funktionen med en variant, der tager et heltal for at generere base selv:

CREATE OR REPLACE FUNCTION lpad_bits3(val varbit, sz int = 32)
  RETURNS varbit AS
$func$
SELECT overlay(repeat('0', sz)::varbit PLACING val FROM sz - bit_length(val))
$func$  LANGUAGE sql IMMUTABLE;

Ring til:

SELECT lpad_bits3(b'1001100111000', 32;

Relateret:



  1. 12c IDENTITY kolonner

  2. MySQL INDSÆT I VÆLG JOIN

  3. Udfør forespørgsel på SQL Server Analysis Services med IronPython

  4. Omdøb en kolonne i MySQL