Mysql
 sql >> Database >  >> RDS >> Mysql

Come selezionare i post creati da me o dai miei amici in un feed di notizie?

So che hai già accettato una risposta, ma stavo scrivendo questo a metà quindi ho deciso di pubblicarlo comunque.

Tornerò un po' indietro prima di rispondere, spero, alla tua domanda. Quando sviluppi applicazioni e costruisci database, dovresti SEMPRE cerca di strutturare le cose nel modo più descrittivo e compatto possibile. Sarebbe davvero imbarazzante avere una variabile/colonna denominata color e memorizza lì le password utente crittografate (strano, giusto?). Esistono alcune convenzioni di denominazione dei database standard che, se seguite, rendono la vita molto più semplice, specialmente quando si sviluppano applicazioni complicate. Ti consiglierei di leggere alcuni blog riguardanti le convenzioni di denominazione. Un buon punto di partenza potrebbe essere questo uno.

Mi rendo perfettamente conto che con le modifiche suggerite di seguito potresti dover riscrivere parzialmente/completamente il codice dell'applicazione che hai scritto finora, ma sta a te se vuoi davvero che le cose funzionino meglio.

Cominciamo col correggere la struttura del database. A quanto pare, stai facendo un'applicazione simile al newsfeed di Facebook. In questo caso, utilizzando FOREIGN KEYS è praticamente obbligatorio in modo da poter garantire una certa coerenza dei dati. Lo schema del database di esempio riportato di seguito mostra come puoi ottenerlo.

-- Application users are stored here.
CREATE TABLE users (
  user_id      INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  first_name   VARCHAR(255),
  last_name    VARCHAR(255),
  profile_name VARCHAR(255)
) ENGINE=InnoDb;

-- User friendship relations go here
CREATE TABLE friends (
  friend_id   INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  profile_one INT NOT NULL,
  profile_two INT NOT NULL,
  FOREIGN KEY (profile_one) REFERENCES users (user_id),
  FOREIGN KEY (profile_two) REFERENCES users (user_id)
) ENGINE=InnoDb;

-- User status updates go here
-- This is what will be displayed on the "newsfeed"
CREATE TABLE statuses (
  status_id    INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  author_id    INT NOT NULL,
  recipient_id INT NOT NULL,
  message      TEXT,
  -- created date ?
  -- last updated date ?
  FOREIGN KEY (author_id)    REFERENCES users (user_id),
  FOREIGN KEY (recipient_id) REFERENCES users (user_id)
) ENGINE=InnoDb;

-- Replies to user statuses go here. (facebook style..)
-- This will be displayed as the response of a user to a certain status
-- regardless of the status's author.
CREATE TABLE replies (
  reply_id  INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  status_id INT NOT NULL,
  author_id INT NOT NULL,
  message   TEXT,
  FOREIGN KEY (status_id) REFERENCES statuses (status_id),
  FOREIGN KEY (author_id) REFERENCES users    (user_id)
) ENGINE=InnoDb;

Ora che il problema è stato risolto, possiamo procedere con il passaggio successivo:selezionare il newsfeed per john123 (che ha user_id=1 ). Questo può essere ottenuto con la query seguente:

SET @search_id:=1; -- this variable contains the currently logged in user_id so that we don't need to replace the value more than once in the whole query.

SELECT 
    statuses.*,
    author.first_name     AS author_first_name,
    author.last_name      AS author_last_name,
    recipient.first_name  AS recipient_first_name,
    recipient.last_name   AS recipient_last_name
FROM statuses
JOIN users AS author      ON author.user_id    = statuses.author_id
JOIN users AS recipient   ON recipient.user_id = statuses.recipient_id
WHERE (statuses.author_id = @search_id OR statuses.recipient_id = @search_id)
ORDER BY status_id ASC

E qui potresti vederlo in azione in un sqlfiddle. Come puoi vedere, solo strutturando meglio il database, ho eliminato la necessità di una sottoquery (che è ciò che EXISTS / NOT EXISTS fare secondo i documenti e EXPLAIN ). Inoltre, il codice SQL di cui sopra sarebbe molto più facile da mantenere ed estendere.

Ad ogni modo, spero che lo trovi utile.