PDA

View Full Version : [HyperSQL] somma condizionale (quando la condizione è in alltra tabella)


Chimico_9
13-10-2015, 00:06
Buonasera
per necessità mi sto avvicinando (autonomamente e con quanto trovo in rete) al linguaggio HSQLDB
sono riuscito a scivere una piccola routine ma non riesco a farle fare ancora tutto quello che vorrei.

Vediamo se riesco a farmi capire, semplificando la mia situazione è:
- ho due tabelle A("id", "flag", altro...) B ("id", "articolo", "quantità", altro...)
- id : numero dello scontrino
- il flag è "pagato" "non pagato"

quello che la routine fà (ad ogni nuovo ordine) è : sommare la quantità di un determinato articolo
(nella tabella B succede che: )
(ovviamente lo stesso articolo è ripetuto più volte)
(ovviamente a diversi articoli può corrispondere uno stesso id(n.scontrino) )

quello che vorrei far fare è : sommare la quantità di un determinato articolo se questo è stato pagato
da cui la mia richiesta somma condizionale ma con la condizione in un'altra tabella

ho provato :
SELECT SUM ("quantità") AS nmele FROM B WHERE "articolo" LIKE 'mele' AND "id" = (SELECT "id" FROM A WHERE "flag" = pagato);
più o meno questo è il senso, ma mi restituisce un errore sulla cardinalità

Come andrebbe fatto quello che vorrei fare ?
con le primary_key e foreign_key ?

Prima che vi lanciate in 1000 commenti sappiate che :
- si tratta di un programma java interfacciato ad un database, già fatto, che mi mette a disposizione un database manager (in forma di GUI)
- perciò le possibilità di manovra sono limitate : si puo aggiungere qualcosa ma non modificare

Lato sofware : OS W7x64, java 7.80, HSQLDB v.2.3.0

p.s. per uso privato/non commerciale : qualunque codice verrà fuori dalla discussione NON sarà assolutamente distribuito ad altri
p.s. se non se capisce na mazza... non esitate a dirmelo

EDIT : risolto

Maui78
13-10-2015, 06:53
Ciao
Non è una struttura pulitissima quella che hai. Comunque se sostituisci invece di usare AND "id" = inserisci una condizione di IN funziona.
Ovviamente nella tabella B potresti avere più ID con lo stesso articolo ?

Chimico_9
13-10-2015, 09:10
Ciao
Non è una struttura pulitissima quella che hai.
non è colpa mia :D
Comunque se sostituisci invece di usare AND "id" = inserisci una condizione di IN funziona.
mhmmm l' AND me lo devi lasciare...
ho fatto così e sembra andare:
SELECT SUM ("quantità") AS nmele FROM B WHERE "articolo" LIKE 'mele' AND "id" IN (SELECT "id" FROM A WHERE "flag" = pagato);
Ovviamente nella tabella B potresti avere più ID con lo stesso articolo ?
SI, il che corrisponde a dire : capita persone diverse ordinino uno stesso articolo
(condizione che avevo già posto con il mio (ovviamente lo stesso articolo è ripetuto più volte))

@ coffe_killer : sono subito da te

Chimico_9
13-10-2015, 09:19
Ora, ho tre domande per te:
1) il campo id di B è un id articolo o l'id dello scontrino in cui l'articolo è stato pagato?
2) se non fosse l'id dello scontrino, dov'è la relazione tra le due tabelle?
3) hai nozioni di SQL e teoria dei database?

1 - id di B è il numero progressivo dello scontrino (sia pagati che non)
ed è numericamente uguale a id di A (tabella che raccoglie gli scontrini)
(in realtà gli id hanno nomi diversi, ma li ho scritti uguali per far capire che il valore numerico è lo stesso)

2- SI, la relazione tra le due tabelle è quell'id

3 - la mia letteratura:
http://www.html.it/guide/guida-linguaggio-sql/
http://www.programmingforfuture.com/2010/06/using-hypersql-hsqldb.html
http://hsqldb.org/doc/guide/index.html
(questo è il manuale di HSQLDB, ma dovrebbero scrivere a caratteri cubitali : "only for advance user", così non c'avrei neanche provato...:D )

Maui78
13-10-2015, 09:47
non è colpa mia :D

mhmmm l' AND me lo devi lasciare...
ho fatto così e sembra andare:


Mi sono espresso male io forse, ma era implicito laciare l'AND :)


SI, il che corrisponde a dire : capita persone diverse ordinino uno stesso articolo
(condizione che avevo già posto con il mio (ovviamente lo stesso articolo è ripetuto più volte))



Pardon, mi sono concentrato sulla query e ho tralasciato il resto.

Ciao

Chimico_9
13-10-2015, 15:39
Mi sono espresso male io forse, ma era implicito laciare l'AND :)
sesese... e dillo che l'hai fatto apposta per vedere se ero attento ;)

Pardon, mi sono concentrato sulla query e ho tralasciato il resto.
ma figurati, l'ho scritto subito che se non si capiva di chiedere, hai fatto bene

Chimico_9
14-10-2015, 09:27
allora :
- il costrutto funziona se lanciato manualmente
- messo nel TRIGGER non più :mad:

forse è necessario allargare il discorso, nel trigger faccio qualcosa del tipo :

CREATE TRIGGER "numero_art" AFTER INSERT ON A
BEGIN ATOMIC
DECLARE nmele INTEGER;
SELECT SUM ("quantità") INTO nmele FROM B WHERE "articolo" LIKE 'mele' AND "id" IN (SELECT "id" FROM A WHERE "flag" = pagato);
INSERT INTO mySellTable VALUES (nmele);
END

notare che:
. in grassetto le tabelle
. in corsivo la variabile
. AS è stato sostituito da INTO
. mySellTable è stata precedentemente creata e popolata di qualcosa

risultato : celle vuote in mySellTable

dubbi :
-c'è un limite alla lunghezza (in caratteri) di un singolo comando ?
-l' IN puo restituire TRUE FALSE Null ?
-nel caso sommassi numeri e Null (è da considerarsi come uno 0 ?)

idea : puo avere senso fare una VIEW delle due tabelle?
non so come si faccia ma mi studio la cosa se mi dite che è fattibile

Chimico_9
15-10-2015, 16:26
Vado per punti ma non come li hai messi giù tu :

1 - il dubbio mi è venuto per il fatto che "singolarmente ok, nel trigger K.O."
preciso che il trigger senza il comando IN funziona correttamente (ovviamente non il risultato numerico)

2 - mi sono espresso male : se IN mi restituisce una tupla vuota
poi il SELECT SUM restituisce 0 o null ?

3 - CREATE TABLE "MySellTable" ("nmele" INTEGER, "Ora" TIME);
e quindi poi :
INSERT INTO mySellTable VALUES (nmele, LOCALTIME);
Puo creare problemi la presenza di altre colonne ?
(ovviamemte nell'insert o update ci devono essere tutti i relativi valori)

4 - letteratura giusto sufficiente a capire vagamente come funziona un database;
non ho pretese, vorrei giusto mettere a punto questo script per una mia comodità;

Infatti le prime dritte me le ha datte un amico che ha studiato informatica
ma... alcuni argomenti piacciono, altri no e quindi...

P.s. coffe_killer le tue parole non sono vane, riesco (per il momento) a seguirti.

Chimico_9
16-10-2015, 16:32
1 -
2 - succede propio questo
3 - ho fatto questo controllo :
INSERT INTO mySellTable VALUES (IFNULL(nmele,999), LOCALTIME);
e vien fuori sempre 999 -> deduco che il SUM restituise Null -> deduco che IN mi restituisce una tupla vuota

ora io ti chiedo : perchè ?
Quando lo stesso identico comando (fatta eccezione per INTO sostituito da AS), lanciato "a mano" dalla gui del dbmanager, mi restituisce il valore esatto ???
SELECT SUM ("quantità") AS nmele FROM B WHERE "articolo" LIKE 'mele' AND "id" IN (SELECT "id" FROM A WHERE "flag" = pagato);
restituisce "il valore corretto"

Puo essere che non gradisca il fatto che la clausola IN e sulla tabella A, la stessa che attiva il trigger ?!?
CREATE TRIGGER "numero_art" AFTER INSERT ON A ...etc.

4 - ti fermo subito : nel 1° post ho scritto "per uso personale/non commerciale" quindi escludo già la possibilità che io (:stordita: ) vada in giro a fare consulenza sull'argomento (il che provoca un :rotfl: :rotfl: :rotfl: generale);
non preoccuparti dello sfogo ;) .

Chimico_9
19-10-2015, 14:13
La insert ... vuole ovviamente la variabile nmele valorizzata con la select sum come quella che lanci a mano
al solito mi esprimo male : la INSERT "di check" l'ho inserita nel trigger (vedi il mio post #8) quindi correttamente valorizzata dal SELECT SUM immediatamente prima

Puoi mettere qui tutto il processo completo di valorizzazione con il codice completo? Con tutto il cvodice davanti sicuro ti so dare una risposta definitva
sei sicuro ? guarda che è una mattonata e l'ho molto semplificata per poterne parlare nel forum

Chiedo a chiunque di NON quotare il codice che ora riporto
in quanto poi provvederò a sostituirlo con la versione "edulcorata" quando si troverà la soluzione

codice superfluo eliminato

NOTE:
- potrebbero esserci degli errori di trascrizione e non di codice, fatemeli notare
- ogni "pietanza" puo essere composta da un numero variabile di "pezzi di carne" (salsicce e/o costicine), numero di cui il programma originale non tiene conto
- trigger perchè? voglio una risposta "on-line"
- in allegato ciò che il trigger ora mi restituisce alla prima attivazione

Chimico_9
26-10-2015, 10:11
Forse ho capito cosa non va, ma devi darmi tempo fino a stasera per scriverti una risposta completa.

:cry: dopo questa affermazione non puoi svanirmi nel nulla :cry:

Chimico_9
27-10-2015, 10:37
uffaaaaaaaaaaaaaaaaaaaa altro roba da studiare...:cry:

La mia domanda è: perchè appunto usare il trigger allora?
se la prassi è quella perchè invece non ti crei una procedure che fa ciò che richiedi?
il trigger si attiva da solo (before/after/instead of)
la procedure bisogna chiamarla (call ...) (sbaglio ?)
per integrare un CALL dovrei metter mano al codice del programma, cosa che non mi è concessa.

potrei creare un trigger che chiama un procedure ?
(così il trigger è di 3 righe di codice = a prova di nabbo)
(così la procedure si becca tutta la roba e posso fare il debug dalla GUI semplicemente col comando CALL)

I trigger sono sempre causa di discordia tra gli sviluppatori SQL ... Invece le procedure sono chiare e riesci a vedere in chiaro se ritornano un errore :)
effettivamente molto comodo
al di là delle tue opinioni, il codice che ho postato l'hai analizzato ?
per capire se ho sbagliato qualcosa? se pretendo troppo? se c'è qualche concetto/filosofia dietro ai trigger che impedisce di fare quello che gli chiedo?

mi metto al lavoro

Chimico_9
27-10-2015, 16:58
ho fatto ciò :
CREATE PROCEDURE "num_cost_sals"()
MODIFIES SQL DATA
BEGIN ATOMIC

"gli stessi comandi del trigger"

END
poi l'ho lanciato con :
CALL "num_cost_sals"();
ottenendo lo stesso identico risultato del trigger : tabella con valori null (spazio bianco)
e nessun errore o warning

se invece faccio :
INSERT INTO "PUBLIC"."myTempTable" VALUES (
(SELECT SUM ("ITEM_QT") FROM "PUBLIC"."TICKETITEM" WHERE "ITEM_ART" = 16 AND "ITEM_TICKET" IN (SELECT "TICKET_KEY" FROM "PUBLIC"."TICKET" WHERE "TICKET_STUS" = 20)),
"il resto delle voci necessarie a popolare la tebella"
);
la tabella è popolata con un valore corretto (e reale)

deduco che c'è un'incompatibilità tra il comando SET ed IN ?!?!?!?!?!

Chimico_9
27-10-2015, 23:26
L'unica cosa che mi verrebbe da consigliarti a questo punto è monitorare i valori delle variabili in ogni punto delle procedure

e come faccio ?

che poi l'unico punto da monitorare è il SELECT SUM etc. IN etc.
e quello è piuttosto evidente che mi restituisca null :mc:

Chimico_9
28-10-2015, 13:24
Come facevo nel trigger:
SELECT SUM ("quantità") INTO nmele FROM B WHERE "articolo" LIKE 'mele' AND "id" IN (SELECT "id" FROM A WHERE "flag" = pagato);
risultato : null

Come andrebbe fatto :
SET nmele = (SELECT SUM ("quantità") FROM B WHERE "articolo" LIKE 'mele' AND "id" IN (SELECT "id" FROM A WHERE "flag" = pagato));
risultato : quello tanto agoniato

EDIT :
ringrazio Maui78 e coffe_killer per essere intervenuti
ed al tempo stesso li rimproverò per non avermi suggerito quest'altro modo di valorizzare le variabili

Chimico_9
28-10-2015, 15:50
tranqui ! Era per fare una battuta ;)

rimanete sintonizzati che ho un'altra cosa da chiedere
ma prima me la devo studiare un pò...

Chimico_9
30-10-2015, 18:08
rieccociquà! l' "altra cosa da chiedere" si è rilevata più semplice del previsto (aveva a che fare col formato TIME)

ma non preoccupatevi, ne ho un'altra di riserva :

c'è un modo per eseguire del codice SQL (es.: di una procedure)
ad intervalli di tempo prestabiliti, non legati ad alcun evento
che agisca "in background" senza inficiare altre operazioni sul database ???
(es. c'è attiva questa temporalizzazione, vengono eseguite operazioni sul database, scatta il timer e viene eseguito il mio codice, riprendono le operazioni sul database fino al prossimo timer)

se non si fosse capito, quello che vorrei è fare un check periodico su alcuni valori ed eventualmente intraprendere delle azioni

o il fatto di lavorare con un database implica che "non ha senso compiere un'azione se il database non è stato prima modificato" ?

p.s. mi andrebbe bene anche un trigger con un delay (es.1 secondo), giusto il tempo che il database venga aggiornato dall'azione in corso

p.s. al solito : se non mi son fatto capire ditelo apertamente ;)

Chimico_9
03-11-2015, 17:28
UP

Chimico_9
03-11-2015, 23:40
Allora, premesso che i trigger non andrebbero praticamente mai usati...
va bene, ho capito : da piccoli tu e il trigger avete litigato e da allora...:D
si scherza
purtroppo ho le mani legate, il programma non posso toccarlo, cos'altro potrei usare per fare quello che devo fare ?
il trigger è uno solo -> se qualcosa va in vacca sò con chi prendermela

intraprendere delle azioni ad orari prestabiliti basterebbe creare un Job che esegue la procedure, e schedularlo ad un orario preciso. in HyperSQL esistono cose simili?
allora, chiariamo : IO sono quello ignorante che fa le domande
:D
ho trovato questo
http://hsqldb.org/doc/2.0/util-guide/sqltool-chapt.html#N10AA5
e mi sembra che questo sqltool si appoggia ad un "modulo" esterno (AutoSys, Quartz, ...) per questa funzione
il modulo è a sua volta programmabile in Java
...
la cosa sta diventando esponenzialmente sempre più complessa
mi fermo qui

mi accontento di eseguire il trigger ad ogni insert nella tabella d'interesse
sperando che questo non mandi in crisi il database manager
(si tenga conto che ho solo 2 tabelle "attive" con al massimo 2000 righe : non dovrebbe essere un problema gestirle... vero?)
poi con una IF ho fatto in modo che lo script mi aggiorni solo se sono passati più di 10min dall'ultimo aggiornamento

Chimico_9
04-11-2015, 09:47
ok coffe_killer
grazie per l'aiuto e la pazienza

mi confermi che un DBmanager riesce a gestire cose ben peggiori
di 2 tabelle con 2000 righe e 1 routine ?

ora ho un problema con Java (eseguire .jnlp con una particolare versione)
ma credo sia meglio aprire un nuovo thread