SQL-сервер 2012.
Изменить: мой исходный запрос был более сложным, чем должен быть, поскольку я попытался выполнить особый запрос для подмножества полей в таблице и присоединиться к нему в самой таблице, чтобы получить другие (текстовые) поля. следующий запрос тоже поможет:
SELECT DISTINCT
p1.id
,p1.Name
,CAST( p1.[Description] AS nvarchar(max)) AS Description
,( SELECT [Category] + ', '
FROM [dbo].[Company] AS p2
WHERE p2.Id = p1.Id
ORDER BY Name
FOR XML PATH('') ) AS Categories
FROM [dbo].[Company] AS p1
ORDER BY p1.Id
У меня есть таблица с данными, подобными этой (несколько записей для каждой компании, которые идентичны, за исключением поля категории):
+----+------+-----------------+----------+
| Id | Name | Description | Category |
+----+------+-----------------+----------+
| 1 | AAA | <loads of text> | cat1 |
| 1 | AAA | <loads of text> | cat2 |
| 2 | BBB | <even more text>| cat1 |
| 2 | BBB | <even more text>| cat3 |
+----+------+-----------------+----------+
Я пытаюсь сделать запрос, чтобы получить этот результат (уникальные записи для каждой компании и категорий, объединенные в одно поле):
| 1 | AAA | <loads of text> | cat1, cat2 |
| 2 | BBB | <even more text>| cat1, cat3 |
Используя информацию из разных тем по SO, я придумал следующее:
SELECT
t1.Id
,t2.Name
,t2.[Description]
,t1.Category
FROM [dbo].[Company] AS t2
INNER JOIN (SELECT DISTINCT p1.Id
,( SELECT [Category] + ', '
FROM [dbo].[Company] AS p2
WHERE p2.Id = p1.Id
ORDER BY Name
FOR XML PATH('') ) AS Category
FROM [dbo].[Company] AS p1
) AS t1 ON t1.Id = t2.Id
ORDER BY t1.Id
В результате запроса есть запись для каждой записи в таблице Company, где категории объединены в поле категории:
+----+------+-----------------+------------+
| Id | Name | Description | Category |
+----+------+-----------------+------------+
| 1 | AAA | <loads of text> | cat1, cat2 |
| 1 | AAA | <loads of text> | cat1, cat2 |
| 2 | BBB | <even more text>| cat1, cat3 |
| 2 | BBB | <even more text>| cat1, cat3 |
+----+------+-----------------+------------+
Я думал, что INNER JOIN будет выбирать строки только в том случае, если обе таблицы совпадают. Подзапрос сам по себе дает ожидаемый результат (одна запись на каждый идентификатор с агрегированными категориями). Я попробовал использовать другое предложение group by для всего запроса, но это не удалось, потому что я не могу включить поле Description в предложение group, поскольку это поле текстового типа.
Что мне не хватает?
3 ответа
Я бы попробовал DISTINCT во внешнем запросе. Это должно решить вашу проблему, если описания / имена не различаются для некоторых строк, что вполне возможно, поскольку ваша таблица базы данных, вероятно, должна быть двумя таблицами, и, вероятно, вы никогда не писали код, чтобы гарантировать, что описание / имя остается неизменным для каждого МНЕ БЫ. Если у вас есть составной уникальный индекс по идентификатору, имени и описанию, то, скорее всего, все в порядке.
Если у вас есть проблема с несколькими описаниями, вам нужно будет использовать агрегат, чтобы исправить проблему во внешнем запросе. Или вам нужно будет исправить данные и добавить уникальный индекс, чтобы предотвратить появление в будущем.
Что касается того, почему у вас возникла эта проблема, соединение работает нормально, но у вас есть отношение «один-много» между производной таблицей и другой таблицей. Вот почему вы получаете несколько записей и почему отдельный должен исправить это, если данные для идентификатора не отличаются по имени и описанию.
Попробуй это:
SELECT DISTINCT
t1.Id
,t2.Name
,cast(t2.[Description] as nvarchar(max))
,t1.Category
FROM [dbo].[Company] AS t2
INNER JOIN (SELECT DISTINCT p1.Id
,( SELECT [Category] + ', '
FROM [dbo].[Company] AS p2
WHERE p2.Id = p1.Id
ORDER BY Name
FOR XML PATH('') ) AS Category
FROM [dbo].[Company] AS p1
) AS t1 ON t1.Id = t2.Id
ORDER BY t1.Id
В качестве альтернативы вы можете исправить свой плохой дизайн стола.
SELECT *
FROM ( SELECT t1.Id ,
t2.Name ,
t2.[Description] ,
t1.Category ,
ROW_NUMBER() OVER ( PARTITION BY t1.Id, t2.Name,
t1.Category ORDER BY t1.id ) row_num
FROM [dbo].[Company] AS t2
INNER JOIN ( SELECT DISTINCT
p1.Id ,
( SELECT [Category] + ', '
FROM [dbo].[Company] AS p2
WHERE p2.Id = p1.Id
ORDER BY Name
FOR
XML PATH('')
) AS Category
FROM [dbo].[Company] AS p1
) AS t1 ON t1.Id = t2.Id
) t1
ORDER BY t1.Id
Чтобы обойти неприятную проблему использования текста в качестве типа данных, вы можете преобразовать этот столбец, когда вы его потянете. Если это вообще возможно, я бы навсегда изменил столбец на varchar (max).
Что-то вроде этого:
SELECT
t1.Id
, t2.Name
, cast(t2.[Description] as varchar(max)) as Description
, t1.Category
FROM [dbo].[Company] AS t2
INNER JOIN (SELECT DISTINCT p1.Id
,( SELECT [Category] + ', '
FROM [dbo].[Company] AS p2
WHERE p2.Id = p1.Id
ORDER BY Name
FOR XML PATH('') ) AS Category
FROM [dbo].[Company] AS p1
) AS t1 ON t1.Id = t2.Id
GROUP BY Id
, Name
, cast(t2.[Description] as varchar(max))
ORDER BY t1.Id
Похожие вопросы
Новые вопросы
sql-server
Microsoft SQL Server — это система управления реляционными базами данных (RDBMS). Используйте этот тег для всех выпусков Microsoft SQL Server, включая Compact, Express, Azure, Fast-track, APS (ранее PDW) и Azure SQL DW. Не используйте этот тег для других типов СУБД (MySQL, PostgreSQL, Oracle и т. д.). Не используйте этот тег для вопросов по программному обеспечению и разработке мобильных устройств, если только он не связан напрямую с базой данных.