Получить общие строки в одной таблице - PullRequest
3 голосов
/ 04 февраля 2009

Я немного поискал, но не нашел ничего похожего на то, чего я пытаюсь достичь.

По сути, я пытаюсь найти сходство между голосованием двух пользователей.

У меня есть таблица, в которой хранится каждый сделанный голос, в котором хранится:

voteID
itemID     (the item the vote is attached to)
userID     (the user who voted)
direction  (whether the user voted the post up, or down)

Я стремлюсь вычислить сходство, скажем, между пользователями A и B, обнаружив две вещи:

  1. Число общих голосов, которыми они обладают . То есть, сколько раз они оба проголосовали за один и тот же пост (направление на данном этапе не имеет значения).
  2. Количество раз, когда они проголосовали в одном и том же направлении, за общие голоса .

(Затем просто рассчитать # 2 в процентах от # 1, чтобы получить приблизительный рейтинг сходства).

У меня вопрос: как мне найти пересечение между наборами голосов двух пользователей? (т.е. как мне правильно рассчитать балл № 1, не зацикливаясь на каждом голосе крайне неэффективным способом. ) Если бы они были в разных таблицах, ВНУТРЕННЕГО СОЕДИНЕНИЯ было бы достаточно, я бы подумал ... но это, очевидно, не будет работать на той же таблице (или так?).

Любые идеи будут с благодарностью.

Ответы [ 6 ]

5 голосов
/ 04 февраля 2009

Примерно так:

SELECT COUNT(*)
FROM votes v1
INNER JOIN votes v2 ON (v1.item_id = v2.item_id)
WHERE v1.userID = 'userA'
AND v2.userUD = 'userB'
2 голосов
/ 04 февраля 2009

В случае, если вы хотите сделать это для одного пользователя (вместо того, чтобы знать обоих пользователей в начале), чтобы найти, кому они наиболее близки:

SELECT
     v2.userID,
     COUNT(*) AS matching_items,
     SUM(CASE WHEN v2.direction = v1.direction THEN 1 ELSE 0 END) AS matching_votes
FROM
     Votes v1
INNER JOIN Votes v2 ON
     v2.userID <> v1.userID AND
     v2.itemID = v1.itemID
WHERE
     v1.userID = @userID
GROUP BY
     v2.userID

Затем вы можете ограничить это, как считаете нужным (вернуть 10 лучших, 20 лучших и т. Д.)

Я еще не проверял это, поэтому дайте мне знать, если он не работает, как ожидалось.

2 голосов
/ 04 февраля 2009

Самостоятельное соединение в порядке. Вот все, что вы просили:

SELECT v1.userID user1, v2.userID user2,
  count(*) n_votes_in_common,
  sum(case when v1.direction = v2.direction then 1 else 0 end) n_votes_same_direction,
  (n_votes_same_direction * 100.0 / n_votes_in_common) crude_similarity_percent 
FROM votes v1
INNER JOIN votes v2
ON v1.item_id = v2.item_id
2 голосов
/ 04 февраля 2009

Предполагается, что userID 1 сравнивается с userID 2

Чтобы узнать, сколько у них общих голосов:

SELECT COUNT(*)
FROM Votes AS v1
INNER JOIN Votes AS v2 ON (v2.userID = 2
                            AND v2.itemID = v1.itemID)
WHERE v1.userID = 1;

Чтобы узнать, когда они также проголосовали:

SELECT COUNT(*)
FROM Votes AS v1
INNER JOIN Votes AS v2 ON (v2.userID = 2
                            AND v2.itemID = v1.itemID
                            AND v2.direction = v1.direction)
WHERE v1.userID = 1;
2 голосов
/ 04 февраля 2009

Вот пример, который должен приблизить вас:

SELECT COUNT(*)
FROM (
      SELECT u1.userID
      FROM vote u1, vote u2
      WHERE u1.itemID = u2.itemID
      AND u1.userID = user1
      AND u2.userID = user2)
1 голос
/ 04 февраля 2009

Вы наверняка можете присоединить стол к себе. На самом деле, это то, что вам нужно сделать. Вы должны использовать псевдонимы, когда присоединяете таблицу к себе. Если на вашем столе нет PK или FK, вам придется использовать Union. Union удалит дубликаты, а Union All - нет.

...