Trovare record nel database partendo da id non sequenziali

MarcoGrazia

Utente Attivo
15 Dic 2009
852
20
28
63
Udine
www.stilisticamente.com
Ciao,
come da titolo, sto cercando una soluzione semplice ad un problema complesso, cioè devo estrarre da una tabella, alcuni record non sequenziali non a caso, sarebbe facile, ma con determinati ID.

In pratica ho costruito un problema di news per un sito interno alla nostra intranet, in prima stesura funzionava bene ma non mi permetteva di gestire correttamente le news, cioè selezionavo tutte quelle da leggere e lui non me le faceva più leggere una volta selezionate appunto. Tutte quelle da una certa data!

A me serve invece che l'utente legge anche quelle vecchie se non selezionate e così ho creato nel record utente un campo json, in cui ci sono gli ID di tutte le news che lui ha già letto.

Perfetto!

E no, perché in pratica queste non hanno un ID sequenziale ma casuale, stabilito da quelle che lui ha selezionato come lette.

Un po' come quando in un client di posta uno segna come lette certe email ed altre no.

In realtà la differenza è che alla prossima apertura del programma, io voglio fargli vedere solo quelle che non ha ancora letto, mentre le altre no. E siccome la selezione di quelle già viste è casuale, come faccio la query al database?

In pratica e semplicemente, estraggo il json memorizzato nel campo utente, in questo ci sono memorizzati gli ID delle news già lette, facciamo per esempio che lui ha già letto la 1, la 5 e la 12 io a questo punto devo estrarre la 2, la 3, la 4, la 6, la 7, eccetera.

Ma non so come fare la query, dovrei forse interagire tramite gli insiemi? O bo!
 
json, in cui ci sono gli ID di tutte le news che lui ha già letto.
trasforma questo json in una stringa fatta da ID separati da una virgola e poi fai una select con clausola where campo not in (stringa)
ovvero,
select * from news where IDnews not in (1, 5, 12)
quindi estraendo solo i record non letti

1642244381461.png
 

Allegati

  • 1642244298766.png
    1642244298766.png
    9,6 KB · Visite: 162
Ultima modifica:
Come immaginavo, dovevo interagire con gli insiemi.

Bene funziona ma ho un problema, costruisco la stringa CSV che è una stringa appunto, come la metto nella query?
Cioè se la passo con PDO essendo una stringa mi viene inserita come tale e non va bene, dato che i parametri devono essere interi.

Per ora ho realizzata una porcata invereconda, cioè ho inserito direttamente nella query la stringa contenente il CSV, non c'è un problema di sicurezza dato che comunque i dati provengono direttamente dal database e non possono essere manipolati dall'esterno, ma non mi piace.
 
se anziché un campo json avessi una tabella delle news lette per utente, potresti fare la stessa cosa con
select .... where IDnews not in (select ..... where IDuser = :IDuser)
evitando limiti sugli elementi memorizzabili

i dati provengono direttamente dal database e non possono essere manipolati dall'esterno
oppure, .... accontentati
 
  • Wow
Reactions: MarcoGrazia
vedi se qui trovi una soluzione,
"Prepared statements and IN clause"
 
  • Like
Reactions: MarcoGrazia
vedi se qui trovi una soluzione,
"Prepared statements and IN clause"
Sì è interessante ma presuppone che io abbia una array, mentre ho una stringa CSV come partenza.
JSON l'avevo utilizzato perché volevo o meglio pensavo di dover manipolare i dati dopo averli inseriti e json è facilmente trasformarlo in un array e viceversa anche in PHP, ma poi ho modificata la struttura del programma e quindi uso un VARCHAR in cui inserisco il CSV che poi passo direttamente all'istruzione SQL, come dicevo lo passo con una semplice assegnazione, senza un effettivo controllo, perché avevo provato a effettuare il binding ma non c'è verso di passarlo senza che il PDO lo tratti come stringa, poi l'istruzione IN dell'SQL non lo accetta, perché vuole una sequenza di interi.

Ho provato a trasformarlo in un array, ma è pur sempre un'istruzione in più che non ritenevo necessaria.
PHP:
$listaID = explode(',', $newsLette['news_lette']);
$sql = 'SELECT N.*, U.nome, U.cognome FROM news AS N ';
$sql .= 'LEFT JOIN utenti AS U ON U.id_ute = N.id_ute ';
$sql .= 'WHERE N.visibile = 1 AND N.id_news NOT IN ( ? ) ORDER BY N.data_inserimento DESC; --';
$handle = $pdo->prepare($sql);
$handle->execute($listaID);
//  Poi prosegue con la lettura

Alla fine, dato che il programma è in una LAN alquanto protetta dall'esterno, e il dato proviene direttamente da un database ho preferito alleggerire il codice il più possibile inserendo direttamente la stringa CSV nella QUERY SQL con un'assegnazione PHP.
Così il tutto è diventato:
PHP:
$sql = 'SELECT N.*, U.nome, U.cognome FROM news AS N ';
$sql .= 'LEFT JOIN utenti AS U ON U.id_ute = N.id_ute ';
$sql .= 'WHERE N.visibile = 1 AND N.id_news NOT IN ( ' . $newsLette['news_lette'] . ' ) ORDER BY N.data_inserimento DESC; --';
$handle = $pdo->prepare($sql);
$handle->execute();
e funziona.
Probabilmente perché alla fine l'SQL vede tutta la stringa $sql come un'unica istruzione e non distingue più tra stringhe di caratteri o valori interi. E' una mia opinione, ma penso sia questo il motivo, solo non è ne sicura al 100% ( e chi lo è mai ) ne elegante.

PS conoscevo il sito dei delusi dal PHP, anche se non ci andavo più da anni in effetti, ma ho anche letto cose che... se un'istruzione esiste in SQL è meglio usare quella piuttosto che aumentare il numero di istruzioni in PHP, per esempio con il LIKE una volta anche io costruivo la stringa da passare con il PHP come mostrato nel sito, ora uso l'istruzione SQL CONCAT.
SQL:
SELECT nome FROM utenti WHERE nome LIKE CONCAT( "%", :frase, "%") LIMIT 1 ; --
ma sono solo metodi di programmazione, non il vangelo :)
 
  • Like
Reactions: marino51

Discussioni simili