2015-02-06 12 views
0

SQL Server 2012.внутреннее соединение между столом и подзапрос на том же столе

Edit: мой первоначальный запрос был более сложным, чем это должно быть, так как я пытался сделать Distinct запрос на подмножества полей в таблице и присоедините это к самой таблице, чтобы получить другие (текстовые) поля. следующий запрос делает трюк, а также:

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 

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

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

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

+0

Используйте отличимым, если описание такой же и отказаться от описания или агрегировать описание также –

+0

мне нужно описание в результате запроса, и я не могу агрегировать его, я хотел бы получить 10 раз тот же текст в поле описания. –

+0

Просто добавьте GROUP BY Id, Name, Description. –

ответ

1

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

В качестве альтернативы вы можете исправить ваш плохой дизайн таблицы.

+0

Пробовал это уже: Msg 421, уровень 16, состояние 1, строка 2 Тип текстовых данных не может быть выбран как DISTINCT, потому что он не сопоставим. –

+0

Упс не заметил, что это текст. Должно ли это быть текстом? Вы не используете текстовый файл dataype в SQL Server 2012. Вы можете использовать varchar (max) или nvarchar (max). Если возможно, я бы конвертировал их или вы можете применить к одному из запросов в запросе и посмотреть, работает ли это. – HLGEM

+0

Поля описания идентичны для всех записей с одним и тем же идентификатором. Фактически таблица является результатом более сложного запроса, объединяющего несколько таблиц. Я планировал интегрировать этот запрос в вышеупомянутый, как только у меня это будет работать так, как должно. –

1
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 
+0

Пробовал это уже: Msg 421, уровень 16, состояние 1, строка 2 Тип текстовых данных не может быть выбран как DISTINCT, потому что он не сопоставим. –

+0

обновите запрос. Это немного уродливо, но должно работать –

1

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

. Ваш ответ - это дубликат того, что предложил HLGEM ранее. –

Смежные вопросы