Внутреннее соединение между таблицей и подзапросом в той же таблице

108
12

SQL Server 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 поле):

| 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, так как это поле типа текста.

Что мне не хватает?

спросил(а) 2021-01-25T18:16:20+03:00 4 месяца, 3 недели назад
1
Решение
77

Я бы попробовал 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

Кроме того, вы можете исправить свой дизайн плохих таблиц.

ответил(а) 2021-01-25T18:16:20+03:00 4 месяца, 3 недели назад
63

Чтобы обойти неприятную проблему использования текста в качестве типа данных, вы можете указать этот столбец, когда вы его потянете. Если это вообще возможно, я бы постоянно менял столбец на 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

ответил(а) 2021-01-25T18:16:20+03:00 4 месяца, 3 недели назад
63

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

ответил(а) 2021-01-25T18:16:20+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема