0

グループまたは個々のユーザーとの共有が必要なサイトを構築しています。Googleがmysqlを使用していないことは知っていますが、自分のサイトでそのような機能をどのように複製できるか疑問に思っていました. g+ では、次のことができます。

  1. 投稿を「公開」で共有します (全員が閲覧できます)。
  2. 「すべてのサークル」で投稿を共有します (サークル内の全員が閲覧できます)。
  3. サークルと個人ユーザーの両方と投稿を共有します。例: post = "my first post" で、家族、友人、ユーザー 1 (Joey tribbiani)、ユーザー 2 (Ross geller) などと共有されます。

条件:

  1. 投稿がサークルと共有され、新しいユーザーがサークルに追加された場合、そのユーザーはそのサークルで共有された以前の投稿をすべて表示できるはずです。
  2. ユーザーがサークルから削除された場合。(s)彼がコメントした投稿を除いて、そのサークルと共有されている投稿を見ることはできません。

現在、私のデータベース テーブルは次のようになっています。

Circle_category

Cat_id
Cat_name
user_id

投稿

post_id 
user_id
post
is_public
all_circle

サークルに投稿

entry_id
post_id
cat_id

Post_to_user

entry_id
post_id
user_id

ファミリー サークル ( cat_id が 1 の Circle_category にある) のユーザーが表示できる投稿

  1. 公開されている投稿を見ることができます。
  2. すべてのサークルで共有されている投稿を表示できます。
  3. ファミリー サークルと共有されている投稿を表示できます。
  4. 共有された投稿を見ることができます (個人ユーザー)。

SQL

 SELECT p.* FROM posts p
    JOIN Post_to_circle pc
    ON p.post_id = pc.post_id
    JOIN Post_to_user pu
    ON p.post_id = pu.post_id
    WHERE p.is_public = 1 
    OR all_circle = 1
    OR pc.cat_id = $cat_id 
    OR pu.user_id = $user_id

質問:
まず、ケース 1 (すべての公開投稿を参照)、ケース 2 (すべてのサークルと共有された投稿) から投稿を取得できましたが、他の 2 つのケースは機能しません。私はそれについて考え、主な問題は、p.is_public = 1 の投稿を取得するために where 句を指定したことであることがわかりました。これは、p.is_public = 0 の行を無視することを意味します。クエリを更新して、すべてをカバーする投稿を表示するにはどうすればよいですか4 つのケースであり、冒頭で説明した条件もカバーしています。

次に、テーブルを構造化するためのより良い方法はありますか? 私はそれを正しい方法で行っているかどうかわかりません。

4

1 に答える 1

2

簡単な読みトラフから、私が言えることは次のとおりです。

左結合ステートメントの代わりに結合ステートメントを使用しています。

結合手段の使用: from 句で使用されるテーブルから、その結合句で指定された条件に対して true を検証するすべての行を保持します。

2つのステートメントを使用しているため、最初の結合は必要な結合を持たないすべてのレコードを破棄し、2番目の結合は2番目の結合に必要な結合を持たないすべてのレコードを破棄しますが、最初の結合に一致したレコードのみを使用します加入。

代わりに左結合を使用する必要があります。これにより、最初のテーブルのすべての行が保持されます。一致しなかったすべての行、結合されたテーブルで指定された列の値 NULL を取得します

簡単な例:

ユーザー テーブル:

user_id
name

user_posts

post_id
user_id
content
created

関連クエリ:

select *
from users u
JOIN user_posts up on up.user_id = u.user_id and up.created > date_sub(curdate(), interval 1 day)

これはすべてのユーザーを使用し、そのユーザーによって作成されてから 1 日以内に作成された各投稿と一致させます。ユーザーが最終日に投稿しなかった場合、そのユーザーは結果セットに含まれません。

この例を

select *
from users u
LEFT JOIN user_posts up on up.user_id = u.user_id and up.created > date_sub(curdate(), interval 1 day)

これはすべてのユーザーを使用し、ユーザーが最終日に投稿していない場合、そのユーザーによって作成されてから 1 日以内に作成された各投稿と一致させます。ユーザーは結果セットに残りますが、投稿のすべての列テーブルはNULLになります

where は、結合後に残ったすべての行をフィルタリングします。(クエリを高速化できる場合、mysql は参加する前に where 句を使用します)。

クエリを変更する:

すべての異なるケースで、WHERE ステートメントの句が () で囲まれていることを確認してください。また、情報が不足しているため、これは完全な回答ではありません(ユーザーテーブル、サークル関係テーブル、友達関係の例)

また、all_circlesオプションは私を混乱させるので、クエリにはありませんが、これで正しい軌道に乗るはずです

SELECT p.* FROM posts p
    left JOIN Post_to_circle pc
    ON p.post_id = pc.post_id and /* define statement for valid circles for user you're trying to get the posts for */
    left JOIN Post_to_user pu
    ON p.post_id = pu.post_id and /* define statement for valid friends for user you're trying to get the posts for */
    WHERE 
/* 1 day old */
p.created > date_sub(curdate(), interval 1 day)
AND (
/* is public */
p.is_public = 1 OR
/* or to friends */
pu.id is not null OR
/* or to circles */
pc.id is not null
)

また、2 つのサブクエリが必要になると思われますが、これは最善の方法ではありません。友人の正しい ID と有効なサークルの ID をすべて見つけてから、IN 句を使用することをお勧めします。各結合ステートメント (コメントの部分)

于 2013-02-03T13:00:18.923 に答える