sqlite3 JOIN, GROUP CONCAT с использованием distinct с пользовательским разделителем

учитывая таблицу "событий", где каждое событие может быть связано с нулем или более "динамиков" и нулем или более "терминов", эти записи, связанные с событиями через таблицы объединения, мне нужно создать таблицу всех событий со столбцом в каждой строке, которая представляет список "speaker_names" и "term_names", связанных с каждым событием.

однако, когда я запускаю свой запрос, у меня есть дублирование в значениях speaker_names и term_names, так как таблицы соединений производят строку на ассоциация для каждого из докладчиков и сроки проведения мероприятий:

1|Soccer|Bobby|Ball
2|Baseball|Bobby - Bobby - Bobby|Ball - Bat - Helmets
3|Football|Bobby - Jane - Bobby - Jane|Ball - Ball - Helmets - Helmets

агрегатная функция group_concat имеет возможность использовать "distinct", которая удаляет дублирование, хотя, к сожалению, она не поддерживает это наряду с пользовательским разделителем, который мне действительно нужен. Я остаюсь с этими результатами:

1|Soccer|Bobby|Ball
2|Baseball|Bobby|Ball,Bat,Helmets
3|Football|Bobby,Jane|Ball,Helmets

мой вопрос такой: есть ли способ сформировать запрос или изменить структуры данных, чтобы получить желаемое результаты?

имейте в виду, что мне нужен запрос sqlite3, и я не могу добавить пользовательские агрегатные функции C, так как это для развертывания Android.

Я создал суть, которая позволяет вам легко протестировать возможное решение:https://gist.github.com/4072840

4 ответов


найдите имена динамиков / терминов независимо друг от друга:

SELECT _id,
       name,
       (SELECT GROUP_CONCAT(name, ';')
        FROM events_speakers
        JOIN speakers
          ON events_speakers.speaker_id = speakers._id
        WHERE events_speakers.event_id = events._id
       ) AS speaker_names,
       (SELECT GROUP_CONCAT(name, ';')
        FROM events_terms
        JOIN terms
          ON events_terms.term_id = terms._id
        WHERE events_terms.event_id = events._id
       ) AS term_names
FROM events

Я побежал через эту проблему, но придумали способ, который я нашел немного легче понять. Начиная с отчетов SQLite SQLite3::SQLException: DISTINCT aggregates must have exactly one argument, проблема, кажется, не столько с GROUP_CONCAT метод, но с помощью DISTINCT внутри GROUP_CONCAT...

когда вы инкапсулируете отдельный "подзапрос" в REPLACE метод, который на самом деле ничего вы можете иметь относительную простоту предложения nawfal без недостатка только быть в состоянии конкат строки без запятой правильно.

SELECT events._id, events.name, 
       (group_concat(replace(distinct speakers.name),'',''), ' - ') AS speaker_names, 
       (group_concat(replace(distinct speakers.name),'',''), ' - ') AS term_names 
FROM events 
LEFT JOIN 
   (SELECT et.event_id, ts.name 
    FROM terms ts 
    JOIN events_terms et ON ts._id = et.term_id
   ) terms ON events._id = terms.event_id 
LEFT JOIN 
   (SELECT sp._id, es.event_id, sp.name 
    FROM speakers sp 
    JOIN events_speakers es ON sp._id = es.speaker_id
   ) speakers ON events._id = speakers.event_id 
GROUP BY events._id;

но на самом деле я бы счел это ошибкой / несоответствием SQLite, или я что-то упускаю?


странно, что SQLite не поддерживает это!.

рискуя быть проголосованным, только если это поможет:

вы можете использовать Replace(X, Y, Z). Но вы должны быть уверены, что у вас не будет valid , значения в столбцы..

SELECT events._id, events.name, 
       REPLACE(group_concat(distinct speakers.name), ',', ' - ') AS speaker_names, 
       REPLACE(group_concat(distinct terms.name), ',', ' - ') AS term_names 
FROM events 
LEFT JOIN 
   (SELECT et.event_id, ts.name 
    FROM terms ts 
    JOIN events_terms et ON ts._id = et.term_id
   ) terms ON events._id = terms.event_id 
LEFT JOIN 
   (SELECT sp._id, es.event_id, sp.name 
    FROM speakers sp 
    JOIN events_speakers es ON sp._id = es.speaker_id
   ) speakers ON events._id = speakers.event_id 
GROUP BY events._id;

просто ту поставил правильное решение (ответ murb является strangly parenthesised).

:

group_concat(distinct column_name, 'custom_separator') принимает custom_separator в рамках distinct.

устранение:

нам нужен какой-то no-op, чтобы SQLite знал, что distinct готово (чтобы обернуть distcint и его аргументы). No-op можно заменить пустой строкой как S