Выберите дубликаты / повторяющиеся значения, не сгруппированные - PullRequest
1 голос
/ 18 мая 2011

Я пытаюсь вернуть список разгруппированных значений, имеющих максимально определенное количество повторяющихся значений. У меня есть список значений, полученных как таковые:

select TagDirID from tags where id = '550'

Результаты будут:

9508
10382
10672
65454
65454
65454
65454

Как вы можете видеть, есть 4 повторения 65454. Я хотел бы вернуть список, в котором пользователь определил максимальное количество повторов для TagDirID. Например, выбирая только 3 повторения или меньше:

9508
10382
10672
65454
65454
65454

Все методы, которые я нашел, возвращают сгруппированный список, я хотел бы сохранить отдельные элементы. Это то, что можно сделать в запросе? Существует первичный ключ, TagID.

edit: для этого нужно выбрать все теги для элемента, id = '550'. потому что это пользовательский контент, иногда люди отмечают одно и то же несколько раз, и я пытаюсь сократить дубликаты, которые я показываю.

edit 2: так, хотя принятый ответ работал для меня, я обнаружил, что он был слишком медленным для того, что мне было нужно, поэтому я нашел решение php:

function get_tags($ID = '', $tags_to_keep = 3)
{   
    // Select all tags.
    $query = "select TagDirID, Tag from tags where id = '$ID'";

    $tags_result = mysql_query($query); 

    $num_results = mysql_num_rows($tags_result);

    for ($i=0; $i<$num_results; $i++)
    {
        //Get tag topics
        $tags_row = mysql_fetch_array($tags_result);

        //build array of items already found with counts
        $tags_count = array_count_values($tags_filter);

        //if number of tags already found($tags_count/$tags_filter) is less than or equal to tags_to_keep then add to filtered array and return array.
        if($tags_count[$tags_row['TagDirID']] <= $tags_to_keep)
        {
            $tags_filter[$i] = $tags_row['TagDirID'];
            $tags[$i] = $tags_row['Tag'];
        }           
    }

    return $tags;
}

Ответы [ 2 ]

2 голосов
/ 18 мая 2011
Select TagID, TagDirID
From    (
        Select T1.TagID, T1.TagDirID
             , (Select Count(*)
                From tags As T2
                Where T2.TagDirID = T1.TagDirID
                    And T2.TagID < T1.TagID) As Rnk
        Where T1.id = '550'
        From tags As T1
        ) As T
Where T.Rnk < 3

Другой способ написать тот же запрос:

Select TagID, TagDirID
From    (
        Select T1.TagID, T1.TagDirID, Count( T2.TagID ) As Rnk
        From tags As T1
            Left Join tags As T2
                On T2.TagDirID = T1.TagDirID
                    And T2.TagID < T1.TagID
        Where T1.id = '550'
        Group By T1.TagID, T1.TagDirID
        ) As T
Where T.Rnk < 3

Подход здесь заключается в том, чтобы имитировать функцию ранжирования, которая бы упорядочивала строки для каждой группировки TagDirID. Таким образом, внутренний запрос в любом из двух приведенных выше решений должен дать вам что-то вроде:

TagID | TagDirID | Rnk
1     | 9508     | 0
2     | 10382    | 0
3     | 10672    | 0
4     | 65454    | 0
5     | 65454    | 1
6     | 65454    | 2
7     | 65454    | 3

Теперь, когда строки пронумерованы в каждой группе, мы можем отфильтровать наши результаты, чтобы получить только максимальное количество строк в любой данной группе. Решением ISO / ANSI будет использование функции ранжирования ROW_NUMBER, которая еще не поддерживается MySQL.

0 голосов
/ 18 мая 2011

Поскольку все повторяющиеся значения равны, вы можете запросить количество повторений различных элементов.Это будет что-то вроде этого, для 3 предметов или меньше:

SELECT T.tdid, T.cnt
FROM ( 
      SELECT distinct(TagDirID) as tdid, 
             (SELECT COUNT(*) FROM tags WHERE id = tdid) as cnt 
      FROM tags
) as T
WHERE T.tdid = '550' AND T.cnt < 3;

Таким образом, результат будет немного отличаться от того, что у вас было (не дублирующиеся элементы, а один элемент и количество дубликатов)но я думаю это подойдет.

...