Postgresqlproblem mit leeren Arrays

Hallo,

ich hatte vor längerer Zeit eine Funktion geschrieben, um damit die Daten nach Key Value Paaren in der Datenbank zu durchsuchen. Das klappt auch wunderbar. Allerdings bekomme ich immer wieder Fehler, wenn das Array leer ist, da hier kein upperbound (array_upper) gefunden werden kann. Wie kann ich diese Zeilen in der Abfrage gezielt ausschließen, bzw. das in der Funktion abfangen.
If array is not null oder array_upper($1,1) > 1 bzw. array_upper($1,1) < 2 scheinen trotz leeren Arrays immer ein true zu liefern.
in der SQL abfrage “where tags not null” wird als Syntaxfehler angezeigt und nicht ausgeführt. Irgendwie bin ich ratlos.

Ich habe gerade keine PostGIS-DB verfügbar um zu Testen, aber folgende Punkte im Handbuch könnten helfen:

NVL bzw. COALESCE, NULLIF

Nahmd,

Das ist in SQL recht konsequent gelöst: es wird der Sonderwert “NULL” geliefert.

Vielleicht findest Du hier etwas brauchbares?


SELECT id,
   data,
   array_upper(data,1)   AS "au",
   array_upper(data,1)<2 AS "<2",
   array_upper(data,1)>2 AS ">2",
   COALESCE (array_upper(data,1), 0)     AS size,
   COALESCE (array_upper(data,1), 0) < 2 AS "size<2",
   COALESCE (array_upper(data,1), 0) > 2 AS "size>2",
   data IS NOT NULL AS "not null"
FROM test;

 id |  data   | au(1) | <2 | >2 | size | size<2 | size>2 | not null 
----+---------+-------+----+----+------+--------+--------+----------
  1 |         |       |    |    |    0 | t      | f      | f
  2 | {}      |       |    |    |    0 | t      | f      | t
  3 | {1}     |     1 | t  | f  |    1 | t      | f      | t
  4 | {1,2,3} |     3 | f  | t  |    3 | f      | t      | t
(4 Zeilen)

Da fehlte nur das “IS”.

Gruß Wolf

Vielen Dank Mr. Wolf. Die Zeile “size<2” funktioniert jetzt ohne Fehlermeldung.
Damit sieht die Funktion jetzt wie folgt aus:

CREATE OR REPLACE FUNCTION c_k_v(text[], text, text)
  RETURNS boolean AS'

DECLARE

	BEGIN
		if COALESCE(array_upper($1,1),0)<2 THEN
			Return false;
		END IF;
		FOR i IN 1..(array_upper($1,1)) LOOP
			if ($1[i]=$2 and $1[i+1]=$3) Then
				Return true;
			END IF;
			i:=i+1;
		END LOOP;
		Return false;
	END;
'  LANGUAGE plpgsql;

Nahmd,

Bist Du sicher, dass Du “FOR i IN” kombinieren willst mit “i := i +1”? Ob das funktioniert, hängt von der Implementation des “FOR” ab und man kann sich nicht wirklich darauf verlassen.

Wenn Du Schrittweite von zwei haben willst, kannst Du vereinfachen:


CREATE OR REPLACE FUNCTION c_k_v(text[], text, text) RETURNS boolean AS'
DECLARE
	BEGIN
		FOR i IN 1..COALESCE (array_upper($1,1)-1, 0) BY 2 LOOP
			IF ($1[i]=$2 AND $1[i+1]=$3) THEN
				RETURN TRUE;
			END IF;
		END LOOP;
		RETURN FALSE;
	END;
'  LANGUAGE plpgsql;

Gruß Wolf

Die Anzahl der Zeilen ist in Sachsen absolut gleich. Nur die Bearbeitungszeit ist bei deiner Funktion 12 Sekunden geringer. Was natürlich sehr positiv ist.