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