2017-02-15 19 views
0

Для данного списка уникальных элементов, после сортировки их по нескольким столбцам в партиях, я получаю дублирование элементов.Ошибка дублирования с сортировкой MySQL по нескольким столбцам

Есть 2 таблицы:

- item_popularity_tbl: 
    iid (UINT, PK) pplt (UTINYINT) 

- item_cat_id_tbl: 
    iid (UINT, PK) cid (UTINYINT) 

Where: 
    iid: item ID, unique values in the tables 
    cid: cat ID, values in the range (1, 15). Multiple items can have same cid. 
    pplt: popularity, vals in the range (1, 10). Multiple items can have same pplt. 

Учитывая список элементов идентификаторов, все уникальных, мне нужно заказать его чид ASC, а затем pplt DESC.

Я использую ниже SQL (с помощью MySQL) код для ее достижения:

# python code snippet 
def db_get_items_sorted(conn, iid_list, offset, limit): 
    n1 = ','.join(['%s'] * len(iid_list)) 
    # 
    sql_stmt = ("SELECT a.iid, a.cid, b.pplt " 
       "FROM pclg.item_cat_id_tbl  AS a " 
      "INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid " 
       "WHERE a.iid IN (%s) " 
       "ORDER BY a.cid ASC, " 
         "b.pplt DESC " 
       "LIMIT %s,%s") % (n1, offset, limit) 
    # 
    return conn.query(sql_stmt % tuple(iid_list)) 

я называю db_get_items_sorted (...) в партиях 10. Я проверил это с входом iid_list 58 пунктов (уникальный) , против полностью заполненных столов с уникальными iids. Для каждого вызова mysql возвращает уникальные 10 iids с правильной сортировкой, как и требовалось. Но когда я объединяю партии для создания последних 58 элементов, я замечаю, что несколько элементов (iid) в списке дублируются (и для них все возвращенные столбцы совпадают, в основном, полное дублирование). Например, 48 уникальных строк и 10 дубликатов.

Если я вызываю db_get_items_sorted (...) со смещением 0 и предел 58, то нет дубликатов iid. Тем не менее, мне нужно позвонить небольшими партиями, так как мы можем потенциально выполнить эту сортировку для нескольких тысяч элементов, продвигаясь вперед.

Вопрос: как достичь уникальной уникальности между партиями?

+0

Если отдельный поток вставки или удаления записей, как вы делаете пакетирование, то 'OFFSET' перепутались. –

+0

@ RickJames Это хороший момент, Рик. Однако в этом случае такого сценария не существует, например, статических таблиц. Использование DISTINCT, как упоминалось в scaisEdge ниже, решает проблему. Но непонятно, почему нам нужно DISTINCT и почему происходит дублирование. – Ethan

+1

'JOIN' раздувает количество строк. –

ответ

0

Я не хотел использовать DISTINCT для решения проблемы. Я не был уверен, почему дублирование строк происходит в первую очередь, поэтому хотелось бы рассмотреть это.

Ниже исправление, с использованием колонки IID с уникальными вальса, в ORDER BY:

 sql_stmt = ("SELECT a.iid, a.cid, b.pplt " 
        "FROM pclg.item_cat_id_tbl  AS a " 
       "INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid " 
        "WHERE a.iid IN (%s) " 
        "ORDER BY a.cid ASC, " 
          "b.pplt DESC, a.iid DESC " 
        "LIMIT %s,%s") % (n1, offset, limit) 

TL; DR: Размножение происходит, как мы использовали LIMIT вместе с ORDER BY и столбцов используемый в ORDER BY, не имел уникальных валов.

Причины:

  • LIMIT возвращает момент, когда он узнает, что требуемое количество строк, удовлетворяющих запросу.

  • Когда столбец с неуникальными валами используется с ORDER BY, строки, содержащие одни и те же валы этих столбцов, не обязательно должны иметь детерминированный порядок.

Таким образом, с помощью LIMIT и вызова Этих процедуры несколько раз (чтобы, наконец, объединить их для получения конечного результата), MySQL был запущен заказ по несколько раз и строк с одинаковым Валом для столбцов (используется в ORDER BY) были не упорядочены по этим звонкам, т. е. их позиции не были постоянными. LIMIT M, N, однако, возвращает строки из определенного (M, N) окна результата ORDER BY.

Это привело к окончательному конкатенированному результату, содержащему повторяющиеся строки.

Ref: https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html

1

Вы можете работать с запросом с использованием отдельных элементов, поэтому сам запрос удаляет дубликаты.

sql_stmt = ("SELECT DISTINCT a.iid, a.cid, b.pplt " 
       "FROM pclg.item_cat_id_tbl  AS a " 
      "INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid " 
       "WHERE a.iid IN (%s) " 
       "ORDER BY a.cid ASC, " 
         "b.pplt DESC " 
       "LIMIT %s,%s") % (n1, offset, limit) 
+0

Спасибо, это должно решить. Будет проверять его по моим данным и вернуться. Связанный прецедент с небольшим модом: что, если iid не на 100% уникален? Предположим, что он используется как временная метка (с минимальной детализацией) для таблицы комментариев и есть экземпляры нескольких добавленных комментариев (хранящихся в другой таблице) в одну и ту же метку времени? Если это помогает, я могу добавить этот случай использования в запрос. – Ethan

+0

Очевидно, что отдельное предложение действительно работает над отдельными значениями, и поэтому важно выбрать столбцы (или представление столбца), которые действительно необходимы для вашей цели. В случае, если строки, имеющие значение меньше, чем значения в метке времени, вы можете выбрать группировку этих значений используя функцию time minute(). или .hour или что-нибудь, что вам нравится – scaisEdge

+0

Вы говорите, что мы используем уникальный comment_id и используем DISTINCT на нем? (Я обновил свой запрос). – Ethan