sql >> Database >  >> RDS >> PostgreSQL

Het verschil begrijpen tussen int letterlijke versus int-parameter in de PL / pgSQL-functie

Waarom?

PL/pgSQL voert SQL-query's uit zoals voorbereide instructies . De handleiding over parametervervanging:

Let op de term waarden . Alleen werkelijke waarden kunnen worden geparametriseerd, maar geen trefwoorden, identifiers of typenamen. 32 in bit(32) kijkt zoals een waarde, maar de modifier van een gegevenstype is intern slechts een "waarde" en kan niet worden geparametriseerd. SQL vereist om gegevenstypen te kennen in de planningsfase, het kan niet wachten op de uitvoeringsfase.

Je zou bereik je doel met dynamische SQL en EXECUTE . Als 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;

Bel:

SELECT lpad_bits(b'1001100111000', 32);  

Let op het onderscheid tussen sz wordt gebruikt als letterlijk om de instructie en de tweede instantie op te bouwen waar deze wordt gebruikt als waarde , die als parameter kan worden doorgegeven.

Sneller alternatieven

Een superieure oplossing voor deze specifieke taak is om gewoon lpad() . te gebruiken like @Abelisto stelde voor :

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;

(Eenvoudiger als gewone SQL-functie, die ook function inlining mogelijk maakt in de context van uiterlijke vragen.)

Meerdere malen sneller dan bovenstaande functie. Een kleine fout:we moeten casten naar text en terug naar varbit . Helaas, lpad() is momenteel niet geïmplementeerd voor varbit . De handleiding:

overlay() beschikbaar is, kunnen we een goedkopere functie hebben:

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;

Sneller als je kunt werken met varbit waarden om mee te beginnen. (Het voordeel vervalt (deels) als je text moet casten naar varbit hoe dan ook.)

Bel:

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

We kunnen overbelasten de functie met een variant die een geheel getal neemt om base te genereren zelf:

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;

Bel:

SELECT lpad_bits3(b'1001100111000', 32;

Gerelateerd:



  1. Gebruikers alleen-lezen toegang verlenen tot alle databases

  2. MySQL-databasefout:constante, willekeurige of tijdzoneafhankelijke expressies in de (sub)partitioneringsfunctie zijn niet toegestaan

  3. Wat doet een transactie rond een enkel overzicht?

  4. Luister naar aflevering 2 van de Microsoft Access Podcast