Объединить несколько полей в одно с помощью SQL - PullRequest
5 голосов
/ 01 сентября 2008

У меня есть три таблицы tag, page, pagetag

С данными ниже

страница

ID      NAME
1       page 1
2       page 2
3       page 3
4       page 4

бирка

ID      NAME
1       tag 1
2       tag 2
3       tag 3
4       tag 4

pagetag

ID   PAGEID  TAGID
1    2        1
2    2        3
3    3        4
4    1        1
5    1        2
6    1        3

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

ID      NAME       TAGS
1       page 1     tag 1, tag 2, tag 3
2       page 2     tag 1, tag 3
3       page 3     tag 4
4       page 4    

Возможно ли это с SQL?


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

Ответы [ 6 ]

3 голосов
/ 01 сентября 2008

Серхио дель Амо:

Однако я не получаю страницы без тегов. Я думаю, мне нужно написать свой запрос с левыми внешними объединениями.

SELECT pagetag.id, page.name, group_concat(tag.name)
FROM
(
    page LEFT JOIN pagetag ON page.id = pagetag.pageid
)
LEFT JOIN tag ON pagetag.tagid = tag.id
GROUP BY page.id;

Не очень красивый запрос, но он должен дать вам то, что вы хотите - pagetag.id и group_concat(tag.name) будут null для страницы 4 в примере, который вы разместили выше, но страница должна появиться в результатах.

3 голосов
/ 01 сентября 2008

Да, вы можете сделать это через 3 что-то вроде ниже:

SELECT page_tag.id, page.name, group_concat(tags.name)
FROM tag, page, page_tag
WHERE page_tag.page_id = page.page_id AND page_tag.tag_id = tag.id;

Не был протестирован, и, возможно, его можно было бы написать более эффективно, но вы должны начать!

Кроме того, предполагается, что MySQL, поэтому может не так хорошо играть с MSSQL! И MySQL не в восторге от дефисов в именах полей, поэтому в приведенных выше примерах изменился на подчеркивание.

1 голос
/ 01 сентября 2008

Я получил решение, играя с объединениями. Запрос:

SELECT
    page.id AS id,
    page.name AS name,
    tagstable.tags AS tags
FROM page 
LEFT OUTER JOIN 
(
    SELECT pagetag.pageid, GROUP_CONCAT(distinct tag.name) AS tags
    FROM tag INNER JOIN pagetag ON tagid = tag.id
    GROUP BY pagetag.pageid
)
AS tagstable ON tagstable.pageid = page.id
GROUP BY page.id

И это будет вывод:

id   name    tags
---------------------------
1    page 1  tag2,tag3,tag1
2    page 2  tag1,tag3
3    page 3  tag4
4    page 4  NULL

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

1 голос
/ 01 сентября 2008

Насколько я знаю, SQL92 не определяет, как следует выполнять конкатенацию строк. Это означает, что у большинства двигателей есть свой метод.

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

(не проверено во всех, кроме Oracle)

Oracle

SELECT field1 | ', ' | field2
FROM table;

MS SQL

SELECT field1 + ', ' + field2
FROM table;

MySQL

SELECT concat(field1,', ',field2)
FROM table;

PostgeSQL

SELECT field1 || ', ' || field2
FROM table;
0 голосов
/ 01 сентября 2008

pagetag.id и group_concat (tag.name) будут нулевыми для страницы 4 в примере, который вы разместили выше, но страница должна появиться в результатах.

Вы можете использовать функцию COALESCE для удаления нулей, если вам нужно:

select COALESCE(pagetag.id, '') AS id ...

Возвращает первое ненулевое значение из списка параметров.

0 голосов
/ 01 сентября 2008

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

Что-то вроде (не проверено):

select ID as 'PageId', Name as 'PageName', null as 'Tags'
into #temp 
from [PageTable]

declare @lastOp int
set @lastOp = 1

while @lastOp > 0
begin
    update p
    set p.tags = isnull(tags + ', ', '' ) + t.[Tagid]
    from #temp p
        inner join [TagTable] t
            on p.[PageId] = t.[PageId]
    where p.tags not like '%' + t.[Tagid] + '%'

    set  @lastOp == @@rowcount
end

select * from #temp

Хотя уродливо.

T-SQL в этом примере, но я думаю, что MySql имеет эквиваленты всему используемому.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...