Raggruppamento di valori booleani correlati per un database SQLite o per mantenerli separati?

2

Sto scrivendo un promemoria in cui è possibile visualizzare i promemoria o meno per ogni giorno della settimana (simile a Google Calendar). Quindi mi piacerebbe memorizzare quanto segue nel mio database SQLite:

  • Lunedì: vero o falso
  • Martedì: vero o falso
  • ecc. per tutti i sette giorni della settimana

Potrei semplicemente memorizzare un valore True / False per ogni giorno della settimana. SQLite non ha un tipo di dati booleano , quindi dovrei archiviarlo come numeri interi in questo caso.

Un'alternativa potrebbe essere quella di memorizzare un singolo intero compreso tra 0 e 127 (000 0000 e 111 1111 in binario).

Normalmente preferirei la prima soluzione dal momento che è più diretta, ma, quando ci sono tanti valori booleani, non sarebbe meglio raggrupparli insieme?

Cosa devo considerare quando scelgo tra questi approcci? C'è un'alternativa migliore?

    
posta sunyata 11.08.2017 - 01:46
fonte

3 risposte

4

Ci sono un paio di vantaggi nel memorizzare il giorno della settimana come un bitarray.

  • Meno risorse: come hai detto, ci sarebbero 7 colonne integer per supportare uno schema del giorno della settimana separato. Questo probabilmente non sarà un grosso problema in un piccolo database come quello che stai descrivendo. Non prenderei una decisione su questo vantaggio da solo.
  • Facile interrogazione - Penso che questo sia il motivo più convincente per usare l'array di bit. Con l'array di bit è possibile utilizzare operatori bit a bit per identificare rapidamente e facilmente i promemoria per la data corrente utilizzando il numero del giorno della settimana. Se si memorizza ogni giorno separatamente, diventa molto più difficile interrogare i promemoria per giorno della settimana. Avresti bisogno di una query dinamica che è costruita in modo diverso a seconda della data corrente o avresti bisogno di una query un po 'complessa in grado di gestire qualsiasi giorno della settimana.

Esiste un approccio alternativo in cui invece di avere una colonna per ogni giorno puoi normalizzare i giorni con un'altra tabella:

Dove una riga in reminder_day indica che il promemoria è attivo per quel giorno.

Puoi eseguire una query in questo modo:

select
  a.*
from
  reminder a inner join
  reminder_day b on a.id = b.reminder_id
where
  day_of_week = 1 // find reminders for Sunday

Questo non è necessariamente un risultato migliore o un risparmio di spazio, ma è facile da interrogare e potrebbe essere più facile da comprendere per gli altri che usare un array di bit.

    
risposta data 11.08.2017 - 05:07
fonte
3

@ La risposta di Samuel va bene, tuttavia mi piace fare l'avvocato del diavolo qui e discutere per un punto di vista leggermente diverso. IMHO

È - più o meno - una questione di gusti.

  • Se memorizzi uno o sette interi per record in un database sarà probabilmente trascurabile per qualsiasi tipo di applicazione del mondo reale, a patto che non ti aspetti di gestire diversi miliardi di promemoria, quindi "Risorse" è non proprio rilevante qui (nota, per questo specifico caso d'uso, è molto probabile che il numero di valori booleani rimarrà 7, per l'intera durata della tua applicazione).

  • Le query per un giorno della settimana dato dinamicamente quando si usa una colonna al giorno ottengono un po ' longish , ma non molto più complex di quando si usa un array di bit. Una query come

    SELECT * FROM reminders WHERE Monday=:x1 AND Tuesday=:x2 AND Wednesday=:x3 AND ... Sunday =:x7

è ovviamente più lungo di SELECT * FROM reminders WHERE DaysArray=:x , e devi inizializzare gli argomenti booleano / intero da x1 a x7 nel codice ai valori corretti per un dato giorno della settimana, tuttavia, non lo chiamo "più complesso". In effetti, una colonna di bitarray non è al 100% autodocumentante, dal momento che non è ovvio se i giorni sono ordinati da sinistra a destra o da destra a sinistra, o se il primo si riferisce alla domenica o al lunedì.

  • utilizzando una tabella aggiuntiva 'reminder_days' consente query più brevi rispetto a una soluzione con sette colonne individuali, ma queste sono più complesse che per gli altri due approcci. Sarebbe chiaramente preferibile se ci fosse una possibilità che i record di "reminder_day" diventassero soggetti a cambiamenti, ma per questo caso, penso che anche questa sarà solo una questione di gusti.

Quindi, se ho tre soluzioni quasi equivalenti, probabilmente preferirei usare quella in cui ho il minor numero di codice da digitare, dato che sono un tipo pigro e sono abituato ai bitarray. Ma altre persone potrebbero pensare in modo diverso e preferire una soluzione in cui i nomi dei giorni della settimana si verificano esplicitamente come nomi di colonna o record nel database.

Quindi non c'è ovviamente una soluzione "migliore", nessuno dei tre funzionerà, e ognuno di essi ha alcuni pro e contro. Scegli la tua scelta.

    
risposta data 11.08.2017 - 08:16
fonte
2

Un'altra possibilità è adottare un approccio ibrido utilizzando una vista per integrare la tabella:

CREATE TABLE Reminders (
    ReminderID   INTEGER PRIMARY KEY,
    Description  VARCHAR,
    WeekdayFlags INTEGER
);

CREATE VIEW RemindersByWeekday AS
SELECT
    ReminderID,
    Description,
    (WeekdayFlags & 1) != 0 AS Sunday,
    (WeekdayFlags & 2) != 0 AS Monday,
    (WeekdayFlags & 4) != 0 AS Tuesday,
    (WeekdayFlags & 8) != 0 AS Wednesday,
    (WeekdayFlags & 16) != 0 AS Thursday,
    (WeekdayFlags & 32) != 0 AS Friday,
    (WeekdayFlags & 64) != 0 AS Saturday
FROM Reminders;

In questo modo, ottieni l'efficienza dello spazio di avere tutti i tuoi flag impacchettati in una singola colonna, ma puoi facilmente scrivere query che funzionano su singoli giorni della settimana.

    
risposta data 12.08.2017 - 01:06
fonte

Leggi altre domande sui tag