SELECT variabile in PostgreSQL

di il
23 risposte

23 Risposte - Pagina 2

  • Re: SELECT variabile in PostgreSQL

    Il problema è che con java si scrive:
    return jdbcTemplate.query(sql, new NotiziaRowMapper(), ... parametri ... );
    quei parametri non devono essere nulli. Se i parametri sono molti c'è da piangere... codice chilometrico... confuso... no no...
    Molto meglio PostgreSQL!
  • Re: SELECT variabile in PostgreSQL

    Se i parametri non devono essere nulli, allora lanci l'eccezione specificando quale parametro sia nullo, altrimenti poi piange l'utente a capire cosa ha sbagliato in mezzo a mille parametri...
  • Re: SELECT variabile in PostgreSQL

    E' l'utente che sceglie i parametri che vuole inserire. Se l'utente lascia il campo 'titolo' vuoto e riempe il campo 'descrizione' è implicito che desidera fare una ricerca sul campo descrizione. Ho testato ora il tuo codice e funziona alla perfezione, ti ringrazio davvero molto. L'unica cosa che vorrei modificare, se possibile, è evitare di dover digitare due volte il '?' altrimenti poi in java ho un metodo con un'infinità di parametri. Dovrebbe risolversi impostando delle variabili ma ottengo questo errore:
    
    DO $$
        DECLARE
            input_id BIGINT = 7;
            input_titolo VARCHAR(150) = 'farfalla';
        BEGIN
            SELECT notizie.* FROM notizie
            WHERE 1=1
              AND ((input_id IS NULL) OR (notizie.id <= input_id))
              AND ((input_titolo IS NULL) OR (LOWER(notizie.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
            ORDER BY notizie.data ASC;
        END
    $$;
    
    
    [42601] ERRORE: la query non ha una destinazione per i dati restituiti Suggerimento: Se vuoi scartare i risultati di una SELECT, utilizza PERFORM. Dove: funzione PL/pgSQL inline_code_block riga 6 a istruzione SQL
    
    Se lancio questo con il query tools:
    
        DECLARE
            input_id BIGINT = 7;
            input_titolo VARCHAR(150) = 'farfalla';
        BEGIN
            SELECT eventi.* FROM eventi
            WHERE 1=1
              AND ((input_id IS NULL) OR (eventi.id <= input_id))
              AND ((input_titolo IS NULL) OR (LOWER(eventi.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
            ORDER BY eventi.data ASC;
        END
    
    
    [42601] ERRORE: errore di sintassi a o presso "BIGINT" Posizione: 27
    
    
    CREATE TABLE IF NOT EXISTS notizie (
        id BIGSERIAL NOT NULL,
        id_utente BIGINT NOT NULL,
        titolo VARCHAR(150) NOT NULL,
        descrizione TEXT NOT NULL,
        luogo VARCHAR(100) NOT NULL,
        data TIMESTAMP WITH TIME ZONE NOT NULL,
        stato VARCHAR(100) NOT NULL,
        dettagli TEXT NOT NULL,
        CONSTRAINT notizie_fka_utenti FOREIGN KEY (id_utente) REFERENCES utenti (id) ON DELETE CASCADE,
        CONSTRAINT notizie_uk UNIQUE (titolo, descrizione, luogo, data),
        CONSTRAINT notizie_pk PRIMARY KEY(id)
    );
    
  • Re: SELECT variabile in PostgreSQL

    Dovresti fare qualcosa tipo
    
    CREATE OR REPLACE FUNCTION myquery(input_id integer)
    RETURNS SETOF notizie
    AS 
    $$
            SELECT notizie.* FROM notizie
            WHERE 1=1
              AND ((input_id IS NULL) OR (notizie.id <= input_id))
              -- altre condizioni...
            ORDER BY notizie.data ASC;
    $$ LANGUAGE sql;
    
    e a questo punto chiamare
    
    select myquery(2);
    
    oppure
    
    select myquery(NULL);
    
    Comunque la mia te l'ho già detta. Buono studio
  • Re: SELECT variabile in PostgreSQL

    Grazie mille Weierstrass! Sei magnifico!
    La tua funzione è spettacolare, è esattamente quello che serve a me.
    Appena finisco questa esercitazione mi compro un bel libro su PostgreSQL e me lo leggo con cura, è troppo importante conoscere questo linguaggio nel dettaglio. Sembra anche più facile di Java.
    Ci sono ancora alcune cose che ti volevo chiedere:
    1) Non riesco a comprendere bene questo pezzo di codice:
    RETURNS SETOF notizie
    AS
    $$
    $$ LANGUAGE sql;
    in particolare AS, $$, SETOF ed sql/plpgsql (ho letto qualcosa ma ho dei bubbi).
    Il codice dai primi test sembra funzionare molto bene ma ci sono alcuni problemini.
    2) Il risultato della query non è una tabella con le colonne di notizie ma una tabella con una sola colonna con alias coincidente con il nome della funzione. Nelle celle i dati sono separati da una virgola come nei file csv.
    Esempio:
     (94,4,p,"pp ","ppp  ","2555-01-01 00:56:00+00",programmato,assenti)
    3) Quando aggiungo un semplice ciclo IF il query tools mi dice che c’è un errore di sintassi ma a me sembra tutto corretto. Dentro $$ $$ posso aggiungere tutti i cicli IF che desidero, giusto?
    [42601] ERRORE: errore di sintassi a o presso "IF" Posizione: 284
    Questo è il codice con il problema 2:
    
    CREATE OR REPLACE FUNCTION cercanotizie(
    input_id INTEGER,
    input_nome VARCHAR(100),
    input_titolo VARCHAR(150),
    input_descrizione TEXT,
    input_luogo VARCHAR(100),
    input_data_inf TIMESTAMP,
    input_data_sup TIMESTAMP,
    input_stato VARCHAR(100)
    )
        RETURNS SETOF notizie
    AS
    $$
    SELECT notizie.* FROM notizie, utenti
    WHERE 1=1
      AND ((input_id IS NULL) OR (notizie.id_utente = input_id))
      AND ((input_nome IS NULL) OR (utenti.nome = input_nome AND notizie.id_utente = utenti.id))
      AND ((input_titolo IS NULL) OR (LOWER(notizie.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
      AND ((input_descrizione IS NULL) OR (LOWER(notizie.descrizione) LIKE LOWER(CONCAT('%',input_descrizione,'%'))))
      AND ((input_luogo IS NULL) OR (LOWER(notizie.luogo) LIKE LOWER(CONCAT('%',input_luogo,'%'))))
      AND ((input_data_inf IS NULL) OR (notizie.data >= input_data_inf))
      AND ((input_data_sup IS NULL) OR (notizie.data < input_data_sup ))
      AND ((input_stato IS NULL) OR (notizie.stato = input_stato))
    ORDER BY notizie.data ASC;
    $$ LANGUAGE sql;
    SELECT cercanotizie(
                   null,
                   null,
                   'p',
                   null,
                   null,
                   null,
                   null,
                   null
               );
    
    Questo è il codice con il problema 2 e 3:
    
    CREATE OR REPLACE FUNCTION cercanotizie(
    input_id INTEGER,
    input_nome VARCHAR(100),
    input_titolo VARCHAR(150),
    input_descrizione TEXT,
    input_luogo VARCHAR(100),
    input_data_inf TIMESTAMP,
    input_data_sup TIMESTAMP,
    input_stato VARCHAR(100)
    )
        RETURNS SETOF notizie
    AS
    $$
    IF (input_nome IS NULL) THEN
        SELECT notizie.* FROM notizie
        WHERE 1=1
          AND ((input_id IS NULL) OR (notizie.id_utente = input_id))
          AND ((input_titolo IS NULL) OR (LOWER(notizie.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
          AND ((input_descrizione IS NULL) OR (LOWER(notizie.descrizione) LIKE LOWER(CONCAT('%',input_descrizione,'%'))))
          AND ((input_luogo IS NULL) OR (LOWER(notizie.luogo) LIKE LOWER(CONCAT('%',input_luogo,'%'))))
          AND ((input_data_inf IS NULL) OR (notizie.data >= input_data_inf))
          AND ((input_data_sup IS NULL) OR (notizie.data < input_data_sup ))
          AND ((input_stato IS NULL) OR (notizie.stato = input_stato))
        ORDER BY notizie.data ASC;
    ELSE
        SELECT notizie.* FROM notizie, utenti
        WHERE 1=1
          AND ((input_id IS NULL) OR (notizie.id_utente = input_id))
          AND ((input_nome IS NULL) OR (utenti.nome = input_nome AND notizie.id_utente = utenti.id))
          AND ((input_titolo IS NULL) OR (LOWER(notizie.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
          AND ((input_descrizione IS NULL) OR (LOWER(notizie.descrizione) LIKE LOWER(CONCAT('%',input_descrizione,'%'))))
          AND ((input_luogo IS NULL) OR (LOWER(notizie.luogo) LIKE LOWER(CONCAT('%',input_luogo,'%'))))
          AND ((input_data_inf IS NULL) OR (notizie.data >= input_data_inf))
          AND ((input_data_sup IS NULL) OR (notizie.data < input_data_sup ))
          AND ((input_stato IS NULL) OR (notizie.stato = input_stato))
        ORDER BY notizie.data ASC;
    END IF;
    
    $$ LANGUAGE sql;
    SELECT cercanotizie(
                   null,
                   null,
                   'p',
                   null,
                   null,
                   null,
                   null,
                   null
               );
    
    
  • Re: SELECT variabile in PostgreSQL

    SETOF è un tipo di return value, se vuoi una tabella metti RETURNS TABLE(...parametri della tabella su cui operi...)
    AS fa parte della dichiarazione di una funzione
    $$ ti serve per evitare di scrivere le sequenze di escape dentro una funzione quando devi scrivere ' oppure \
    LANGUAGE ti specifica il linguaggio usato per la funzione

    Se non mi ricordo male IF non esiste in sql - ci dovrebbe essere in plpgsql da usare assieme a BEGIN e END (non mi ricordo come, i miei database sono minimali e non ho approfondito)

    Secondo me basta leggersi bene tutti i capitoli del tutorial
  • Re: SELECT variabile in PostgreSQL

    Sempre grazie, siete davvero disponibilissimi.
    1) Weierstrass, ti volevo fare una domanda, ma proprio a te che sei un grande matematico. Concordi con me che l’espressione:
    and ((input_id is null) or (eventi.id_utente = input_id))
    sia quanto di più illogico si possa scrivere?
    In matematica l'intersezione di due insiemi di cui uno è vuoto, è l'insieme vuoto mentre in informatica, con la funzione 'select' l'intersezione di due insiemi di cui uno è vuoto, è l'insieme pieno.
    2) returns table obbliga alla funzione select la restituzione di una tabella. Si oppone al comando returns setof che restituisce una tabella in cui i valori di uno stesso record appartenenti a colonne diverse risiedono in un’unica cella separati da una virgola. Con setof le tabelle con N colonne vengono trasformate in tabelle con 1 solo colonna. Dato che il mio obiettivo è passare il risultato della query a java devo evitare setof, giusto?
    3) plpgsql è molto più potente di sql oppure è semplicemente diverso?
    4) Altra cosa che non capisco è l’assegnazione delle variabili che definiscono un numero intero. Se nello schema del database scrivo ‘id bigserial not null’ nella funzione che sto scrivendo cosa devo usare? E’ giusto scrivere ‘id bigint’ oppure devo scrivere ‘id integer’? Se nello schema ho ‘titolo varchar(150) not null,’ nella funzione cosa devo usare? E’ giusto/utile/conveniente riportare quel 150 anche nella funzione?
    5) Ho provato a correggere il vostro codice per ottenere la tabella ma sql mi premia con un errore?
    [42601] ERRORE: la query non ha una destinazione per i dati restituiti Suggerimento: Se vuoi scartare i risultati di una SELECT, utilizza PERFORM. Dove: funzione PL/pgSQL g(integer,character varying,character varying,text,character varying,timestamp without time zone,timestamp without time zone,character varying) riga 5 a istruzione SQL
    create or replace function g (
        input_id integer,
        input_nome character varying,
        input_titolo character varying,
        input_descrizione text,
        input_luogo character varying,
        input_data_inf timestamp without time zone,
        input_data_sup timestamp without time zone,
        input_stato character varying
    )
        returns table (
                          id integer,
                          id_utente integer,
                          titolo character varying,
                          descrizione text,
                          luogo character varying,
                          data timestamp without time zone,
                          stato character varying
                      )
        language plpgsql
    as $$
    declare
    -- variabili usate nel codice
    begin
        select notizie.* from notizie, utenti
        where 1=1
          and ((input_id is null) or (notizie.id_utente = input_id))
          and ((input_nome is null) or (utenti.nome = input_nome and notizie.id_utente = utenti.id))
          and ((input_titolo is null) or (lower(notizie.titolo) like lower(concat('%',input_titolo,'%'))))
          and ((input_descrizione is null) or (lower(notizie.descrizione) like lower(concat('%',input_descrizione,'%'))))
          and ((input_luogo is null) or (lower(notizie.luogo) like lower(concat('%',input_luogo,'%'))))
          and ((input_data_inf is null) or (notizie.data >= input_data_inf))
          and ((input_data_sup is null) or (notizie.data < input_data_sup ))
          and ((input_stato is null) or (notizie.stato = input_stato))
        order by notizie.data asc;
    end; $$
    select g (
                   null,
                   null,
                   'p',
                   null,
                   null,
                   null,
                   null,
                   null
               );
    Qualcuno sa dirmi dove sbaglio?
    Se vi state chiedendo perché uso plpgsql la ragione è semplice, vorrei aggiungere un paio di cicli if.
    Questo codice qui sotto funziona ma ha 2 problemi:
    1) non ritorna una tabella;
    2) nella risposta ci sono record ripetuti e questo mi risulta assolutamente incomprensibile.
    
    CREATE OR REPLACE FUNCTION g2(
        input_id INTEGER,
        input_nome VARCHAR(100),
        input_titolo VARCHAR(150),
        input_descrizione TEXT,
        input_luogo VARCHAR(100),
        input_data_inf TIMESTAMP,
        input_data_sup TIMESTAMP,
        input_stato VARCHAR(100)
    )
        RETURNS SETOF notizie
    AS
    $$
    SELECT notizie.* FROM notizie, utenti
    WHERE 1=1
      AND ((input_id IS NULL) OR (notizie.id_utente = input_id))
      AND ((input_nome IS NULL) OR (utenti.nome = input_nome AND notizie.id_utente = utenti.id))
      AND ((input_titolo IS NULL) OR (LOWER(notizie.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
      AND ((input_descrizione IS NULL) OR (LOWER(notizie.descrizione) LIKE LOWER(CONCAT('%',input_descrizione,'%'))))
      AND ((input_luogo IS NULL) OR (LOWER(notizie.luogo) LIKE LOWER(CONCAT('%',input_luogo,'%'))))
      AND ((input_data_inf IS NULL) OR (notizie.data >= input_data_inf))
      AND ((input_data_sup IS NULL) OR (notizie.data < input_data_sup ))
      AND ((input_stato IS NULL) OR (notizie.stato = input_stato))
    ORDER BY notizie.data ASC;
    $$ LANGUAGE sql;
    
    SELECT g2(
                   null,
                   null,
                   'p',
                   null,
                   null,
                   null,
                   null,
                   null
               );
    
    Altro test:
    
    create or replace function g3 (
        input_id integer,
        input_nome character varying,
        input_titolo character varying,
        input_descrizione text,
        input_luogo character varying,
        input_data_inf timestamp without time zone,
        input_data_sup timestamp without time zone,
        input_stato character varying
    )
        returns table (
                          id integer,
                          id_utente integer,
                          titolo character varying,
                          descrizione text,
                          luogo character varying,
                          data timestamp without time zone,
                          stato character varying
                      )
        language plpgsql
    as $$
    declare
    -- variabili usate nel codice
    begin
        if (input_nome is null) then
            select notizie.* from notizie
            where 1=1
              and ((input_id is null) or (notizie.id_utente = input_id))
              and ((input_titolo is null) or (lower(notizie.titolo) like lower(concat('%',input_titolo,'%'))))
              and ((input_descrizione is null) or (lower(notizie.descrizione) like lower(concat('%',input_descrizione,'%'))))
              and ((input_luogo is null) or (lower(notizie.luogo) like lower(concat('%',input_luogo,'%'))))
              and ((input_data_inf is null) or (notizie.data >= input_data_inf))
              and ((input_data_sup is null) or (notizie.data < input_data_sup ))
              and ((input_stato is null) or (notizie.stato = input_stato))
            order by notizie.data asc;
        else
            select notizie.* from notizie, utenti
            where 1=1
              and ((input_id is null) or (notizie.id_utente = input_id))
              and ((input_nome is null) or (utenti.nome = input_nome and notizie.id_utente = utenti.id))
              and ((input_titolo is null) or (lower(notizie.titolo) like lower(concat('%',input_titolo,'%'))))
              and ((input_descrizione is null) or (lower(notizie.descrizione) like lower(concat('%',input_descrizione,'%'))))
              and ((input_luogo is null) or (lower(notizie.luogo) like lower(concat('%',input_luogo,'%'))))
              and ((input_data_inf is null) or (notizie.data >= input_data_inf))
              and ((input_data_sup is null) or (notizie.data < input_data_sup ))
              and ((input_stato is null) or (notizie.stato = input_stato))
            order by notizie.data asc;
        end if;
    end; $$
    select g3 (
                   null,
                   null,
                   'p',
                   null,
                   null,
                   null,
                   null,
                   null
               );
    
    
    
    [42601] ERRORE: la query non ha una destinazione per i dati restituiti Suggerimento: Se vuoi scartare i risultati di una SELECT, utilizza PERFORM. Dove: funzione PL/pgSQL g3(integer,character varying,character varying,text,character varying,timestamp without time zone,timestamp without time zone,character varying) riga 6 a istruzione SQL
    
  • Re: SELECT variabile in PostgreSQL

    Oggi avevo un po' di tempo e ho letto la guida consigliata da Weierstrass e sono riuscito a scrivere un codice che mi fornisce quello di cui ho bisogno. Ho anche ascoltato il vostro suggerimento ovvero usare RETURNS TABLE ma questo maledetto database mi restituisce una tabella con una sola colonna dove i valori sono separati da virgole.
    Ho creato una nuova tabella con nome "eventi" ma è identica alla precedente "notizie" solo per una questione di comodità (di questo non preoccupatevene).
    Ecco il codice:
    
    CREATE TABLE IF NOT EXISTS utenti (
        id BIGSERIAL NOT NULL,
        nome VARCHAR(100) NOT NULL,
        password VARCHAR(255) NOT NULL,
        CONSTRAINT utenti_pk PRIMARY KEY(id),
        CONSTRAINT utenti_uk UNIQUE (nome)
    );
    
    
    CREATE TABLE IF NOT EXISTS eventi (
        id BIGSERIAL NOT NULL,
        id_utente BIGINT NOT NULL,
        titolo VARCHAR(150) NOT NULL,
        descrizione TEXT NOT NULL,
        luogo VARCHAR(100) NOT NULL,
        data TIMESTAMP WITH TIME ZONE NOT NULL,
        stato VARCHAR(100) NOT NULL,
        CONSTRAINT eventi_fka_utenti FOREIGN KEY (id_utente) REFERENCES utenti (id) ON DELETE CASCADE,
        CONSTRAINT eventi_uk UNIQUE (titolo, descrizione, luogo, data),
        CONSTRAINT eventi_pk PRIMARY KEY(id)
    );
    
    
    CREATE OR REPLACE FUNCTION cercaeventi10 (
        input_id BIGINT,
        input_nome CHARACTER VARYING,
        input_titolo CHARACTER VARYING,
        input_descrizione TEXT,
        input_luogo CHARACTER VARYING,
        input_data_inf TIMESTAMP WITH TIME ZONE,
        input_data_sup TIMESTAMP WITH TIME ZONE,
        input_stato CHARACTER VARYING
    )
        RETURNS TABLE (
                          output_id_evento BIGINT,
                          output_id_utente BIGINT,
                          --output_nome_utente CHARACTER VARYING,
                          output_titolo CHARACTER VARYING,
                          output_descrizione TEXT,
                          output_luogo CHARACTER VARYING,
                          output_data TIMESTAMP WITH TIME ZONE,
                          output_stato CHARACTER VARYING
                      )
        LANGUAGE PLPGSQL
    AS
        $$
    BEGIN
        RETURN QUERY
            SELECT DISTINCT eventi.* FROM eventi, utenti
            WHERE 1=1
              AND ((input_id IS NULL) OR (eventi.id_utente = input_id))
              AND ((input_nome IS NULL) OR (utenti.nome = input_nome AND eventi.id_utente = utenti.id))
              AND ((input_titolo IS NULL) OR (LOWER(eventi.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
              AND ((input_descrizione IS NULL) OR (LOWER(eventi.descrizione) LIKE LOWER(CONCAT('%',input_descrizione,'%'))))
              AND ((input_luogo IS NULL) OR (LOWER(eventi.luogo) LIKE LOWER(CONCAT('%',input_luogo,'%'))))
              AND ((input_data_inf IS NULL) OR (eventi.data >= input_data_inf))
              AND ((input_data_sup IS NULL) OR (eventi.data < input_data_sup ))
              AND ((input_stato IS NULL) OR (eventi.stato = input_stato))
            ORDER BY eventi.data ASC;
    END;
        $$;
    select cercaeventi10 (
                   null,
                   null,
                   'p',
                   null,
                   null,
                   null,
                   null,
                   null
               );
    
    Funziona ma non mi fornisce questa maledetta tabella!
  • Re: SELECT variabile in PostgreSQL

    Ho risolto ma perché gli alias non funzionano?
    Come titolo della colonna leggo "output_id_evento" invece di "Id evento". Non riesco neppure ad impostare gli alias dentro RETURNS TABLE().
    
    CREATE OR REPLACE FUNCTION cercaeventi(
        input_id BIGINT,
        input_nome CHARACTER VARYING,
        input_titolo CHARACTER VARYING,
        input_descrizione TEXT,
        input_luogo CHARACTER VARYING,
        input_data_inf TIMESTAMP WITH TIME ZONE,
        input_data_sup TIMESTAMP WITH TIME ZONE,
        input_stato CHARACTER VARYING
    )
        RETURNS TABLE (
                          output_id_evento BIGINT,
                          output_id_utente BIGINT,
                          output_nome_utente CHARACTER VARYING,
                          output_titolo CHARACTER VARYING,
                          output_descrizione TEXT,
                          output_luogo CHARACTER VARYING,
                          output_data TIMESTAMP WITH TIME ZONE,
                          output_stato CHARACTER VARYING
                      )
        LANGUAGE PLPGSQL
    AS
    $$
    BEGIN
        RETURN QUERY
            SELECT eventi.id AS "Id evento",
                   eventi.id_utente AS "Id utente",
                   utenti.nome AS "Nome utente",
                   eventi.titolo AS "Titolo evento",
                   eventi.descrizione AS "Descrizione evento",
                   eventi.luogo AS "Luogo evento",
                   eventi.data AS "Data evento",
                   eventi.stato AS "Stato evento"
            FROM eventi
            INNER JOIN utenti ON eventi.id_utente = utenti.id
            WHERE 1=1
              AND ((input_id IS NULL) OR (eventi.id_utente = input_id))
              AND ((input_nome IS NULL) OR (utenti.nome = input_nome AND eventi.id_utente = utenti.id))
              AND ((input_titolo IS NULL) OR (LOWER(eventi.titolo) LIKE LOWER(CONCAT('%',input_titolo,'%'))))
              AND ((input_descrizione IS NULL) OR (LOWER(eventi.descrizione) LIKE LOWER(CONCAT('%',input_descrizione,'%'))))
              AND ((input_luogo IS NULL) OR (LOWER(eventi.luogo) LIKE LOWER(CONCAT('%',input_luogo,'%'))))
              AND ((input_data_inf IS NULL) OR (eventi.data >= input_data_inf))
              AND ((input_data_sup IS NULL) OR (eventi.data < input_data_sup ))
              AND ((input_stato IS NULL) OR (eventi.stato = input_stato))
            ORDER BY eventi.data ASC;
    END;
    $$;
    SELECT * FROM cercaeventi(
                   null,
                   null,
                   'p',
                   null,
                   null,
                   null,
                   null,
                   null
    );
    
Devi accedere o registrarti per scrivere nel forum
23 risposte