Подтвердить что ты не робот

Форматирование сводного результата путем слияния строк в Sql

Фон:

Подумайте о приложении, которое позволяет людям делать опросы с настраиваемыми вопросами. В частном случае интервью семьи, An интервьюер отправляется на House 1 и соберет двух участников Member 1и Member 2. Он задает такие вопросы. Что это за дом адрес? Какое ваше имя и возраст? Ответы для что является общим для стран-членов, и ответы, характерные для они сохраняются в одной таблице

После некоторого присоединения к некоторым таблицам и поворота результата я получаю следующую структуру таблицы.

Что было достигнуто до сих пор

| ID | ADDRESS |   MEMBER |    AGE | SubformIteration  |
|----|---------|----------|--------|-------------------|
|  1 | HOUSE 1 |   (null) | (null) |    (null)         |
|  1 |  (null) | MEMBER h |     18 |         s0        |
|  1 |  (null) | MEMBER i |     19 |         s1        |
|  2 | HOUSE 2 |   (null) | (null) |    (null)         |
|  2 |  (null) | MEMBER x |     36 |         s0        |
|  2 |  (null) | MEMBER y |     35 |         s1        |
|  3 | HOUSE 3 |   (null) | (null) |    (null)         |
|  3 |  (null) | MEMBER a |     18 |         s0        |
|  3 |  (null) | MEMBER b |     19 |         s1        |

Я пытаюсь найти способ отформатировать таблицу следующим образом:

Желаемый вывод

| ID | ADDRESS |   MEMBER |    AGE | SubformIteration  |
|----|---------|----------|--------|-------------------|
|  1 | HOUSE 1 | MEMBER 1 |     18 |        s0         |
|  1 | HOUSE 1 | MEMBER 2 |     19 |        s1         |
|  2 | HOUSE 2 | MEMBER x |     36 |        s0         |
|  2 | HOUSE 2 | MEMBER y |     35 |        s1         |
|  3 | HOUSE 3 | MEMBER a |     18 |        s0         |
|  3 | HOUSE 3 | MEMBER b |     19 |        s1         |

У меня недостаточно словарного кода sql для описания и поиска требуемой операции/процедуры. Поскольку я новичок в SQL, и я был бы очень благодарен, если бы кто-нибудь мог сказать мне эффективный способ достичь этого.

Внимание!

НЕ ОТНОСЯТСЯ К колонке QuestionText, поскольку это будет изменение Когда кто-то решил изменить вопросы

Edit

Исходные таблицы

ссылка Sql со всеми приведенными ниже таблицами

В соответствии с предложениями в ответах, я отправляю исходную таблицу и запросы в надежде, что будет лучшее понимание проблемы.

Questions таблица

+------------+--------------+---------+----------+---------------+
| QuestionID | QuestionText |  type   | SurveyID | IsIncremental |
+------------+--------------+---------+----------+---------------+
|       3483 | subform      | subform |      311 |             1 |
|       3484 | MEMBER       | text    |      311 |             0 |
|       3485 | AGE          | number  |      311 |             0 |
|       3486 | ADDRESS      | address |      311 |             0 |
+------------+--------------+---------+----------+---------------+

Results таблица

+----------+-------------------------+----------+
| ResultID |      DateSubmitted      | SurveyID |
+----------+-------------------------+----------+
|     2272 | 2017-04-12 05:11:41.477 |      311 |
|     2273 | 2017-04-12 05:12:22.227 |      311 |
|     2274 | 2017-04-12 05:13:02.227 |      311 |
+----------+-------------------------+----------+

Chunks, где хранятся все ответы:

+---------+------------+----------+------------+------------------+
| ChunkID |   Answer   | ResultID | QuestionID | SubFormIteration |
+---------+------------+----------+------------+------------------+
|    9606 | HOUSE 1    |     2272 |       3486 | NULL             |
|    9607 | MEMEBER 1  |     2272 |       3484 | NULL             |
|    9608 | 12         |     2272 |       3485 | NULL             |
|    9609 | MEMBER 2   |     2272 |       3484 | s1               |
|    9610 | 10         |     2272 |       3485 | s1               |
|    9611 | MEMEBER 1  |     2272 |       3484 | s0               |
|    9612 | 12         |     2272 |       3485 | s0               |
|    9613 | MEMBER 2   |     2272 |       3484 | s1               |
|    9614 | 10         |     2272 |       3485 | s1               |
|    9615 | HOUSE 2    |     2273 |       3486 | NULL             |
|    9616 | MEMBER A   |     2273 |       3484 | NULL             |
|    9617 | 23         |     2273 |       3485 | NULL             |
|    9618 | MEMBER B   |     2273 |       3484 | s1               |
|    9619 | 25         |     2273 |       3485 | s1               |
|    9620 | MEMBER A   |     2273 |       3484 | s0               |
|    9621 | 23         |     2273 |       3485 | s0               |
|    9622 | MEMBER B   |     2273 |       3484 | s1               |
|    9623 | 25         |     2273 |       3485 | s1               |
|    9624 | HOUSE 3    |     2274 |       3486 | NULL             |
|    9625 | MEMBER K   |     2274 |       3484 | NULL             |
|    9626 | 41         |     2274 |       3485 | NULL             |
|    9627 | MEMBER J   |     2274 |       3484 | s1               |
|    9628 | 26         |     2274 |       3485 | s1               |
|    9629 | MEMBER K   |     2274 |       3484 | s0               |
|    9630 | 41         |     2274 |       3485 | s0               |
|    9631 | MEMBER J   |     2274 |       3484 | s1               |
|    9632 | 26         |     2274 |       3485 | s1               |
+---------+------------+----------+------------+------------------+

Я написал следующую хранимую процедуру, которая дает первую таблицу, приведенную в этом вопросе:

ALTER PROCEDURE [dbo].[ResultForSurvey] @SurveyID int
AS
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),@colsAggregated as nvarchar(max);
IF OBJECT_ID('tempdb.dbo.#Temp', 'U') IS NOT NULL
  DROP TABLE #Temp;
SELECT *
INTO #Temp
FROM (Select Answer=( case 
                    When Questions.type='checkboxes' or Questions.IsIncremental=1 THEN  STUFF((SELECT distinct ',' + c.Answer 
            FROM Chunks c Where c.ResultID=Results.ResultID and c.QuestionID=Questions.QuestionID and (Chunks.SubFormIteration IS NULL )
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')
         else  Chunks.Answer end),Chunks.SubFormIteration,Questions.QuestionText,Questions.type,Questions.QuestionID,Chunks.ResultID,Results.ResultID as Action,Results.DateSubmitted,Results.Username,Results.SurveyID from Chunks Join Questions on Questions.QuestionID= Chunks.QuestionID Join Results on Results.ResultID=Chunks.ResultID Where [email protected]) as X


SET @colsAggregated = STUFF((SELECT distinct ','+ 'max('+ QUOTENAME(c.QuestionText)+') as '+ QUOTENAME(c.QuestionText)
            FROM #Temp c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)')
        ,1,1,'')
        print @colsAggregated
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.QuestionText) 
            FROM #Temp c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')
set @query = 'SELECT ResultID,max(Username) as Username,max(DateSubmitted) as DateSubmitted,max(SubFormIteration) as SubFormIteration, ' + @colsAggregated + ' from 
            (
                select * 
                from #Temp
           ) as y
            pivot 
            (
                 max(Answer)
                for QuestionText in (' + @cols + ')
            ) as p GROUP BY 
    ResultID,SubFormIteration'
execute(@query)
4b9b3361

Ответ 1

Может быть полезно опубликовать запрос, который принес вам ваши исходные результаты; существует вероятность, что исходный запрос можно переписать, чтобы избежать этой сложности. С данной информацией это наиболее упрощенный способ решения этой проблемы:

SELECT
   h1.Id,
   h2.Address,
   h1.Member,
   h1.Age,
   h1.MemberNo
FROM House h1
  INNER JOIN House h2
  ON h1.Id = h2.Id
WHERE h2.Address IS NOT NULL  -- Eliminates the results whre the Address is NULL after the join
  AND h1.Member IS NOT NULL -- Eliminates the results that would show up from the original table (t1) where there is no Member field

Update:

Вот простой пример структуры таблицы, используя временные таблицы:

DROP TABLE #Questions
DROP TABLE #Results
DROP TABLE #Chunks

CREATE TABLE #Questions
(
  QuestionId INT,
  QuestionText VARCHAR(MAX),
  type VARCHAR(MAX),
  SurveyID INT,
  IsIncremental INT
)

CREATE TABLE #Results
(
    ResultId INT,
    DateSubmitted DATETIME,
    SurveyID INT
)

CREATE TABLE #Chunks
(
    ChunkId INT,
    Answer VARCHAR(MAX),
    ResultId INT,
    QuestionId INT,
    SubFormIteration VARCHAR(20)
)

INSERT INTO #Results
VALUES (2272, '04-12-2017', 311),
(2273, '04-12-2017', 311),
(2274, '04-12-2017', 311)

INSERT INTO #Chunks
VALUES (9606, 'WhiteHouse', 2272, 3486, NULL),
(9607, 'MEMBER 1', 2272, 3484, NULL),
(9608, '12', 2272, 3485, NULL),
(9609, 'MEMBER 2', 2272, 3484, 's1'),
(9610, '10', 2272, 3485, 's1'),
(9611, 'MEMBER 1', 2272, 3484, 's0'),
(9612, '12', 2272, 3485, 's0'),
(9613, 'MEMBER 2', 2272, 3484, 's1'),
(9614, '10', 2272, 3485, 's1'),
(9615, 'RpBhavan', 2273, 3486, NULL),
(9618, 'MEMBER B', 2273, 3484, 's1'),
(9619, '25', 2273, 3485, 's1'),
(9620, 'MEMBER A', 2273, 3484, 's0'),
(9621, '23', 2273, 3485, 's0')

INSERT INTO #Questions
VALUES (3483, 'subform', 'subform', 311, 1),
( 3484, 'MEMBER', 'text', 311, 0 ),
(3485, 'AGE', 'number', 311, 0),
(3486, 'ADDRESS', 'address', 311, 0)

Вот способ получения результатов, которые вы ищете без использования PIVOT и XML:

; WITH Responses AS (
SELECT
    c.ResultId,
    QuestionText,
    Answer,
    c.SubFormIteration
FROM #Chunks c
    INNER JOIN #Results r
    ON c.ResultId = r.ResultId
    INNER JOIN #Questions q
    ON q.QuestionId = c.QuestionId
WHERE c.SubFormIteration IS NOT NULL -- Removes the "Address" responses and duplicate Answers
),
FindAddress AS (
-- Pulls ONLY the address for each ResultId
SELECT
    ResultId,
    MAX(CASE WHEN QuestionText = 'ADDRESS' THEN Answer END) AS [Address]
FROM #Chunks c
    INNER JOIN #Questions q
    ON q.QuestionId = c.QuestionId
GROUP BY ResultId
)
-- Combines all responses and the address back together
SELECT
    r.ResultId,
    fa.Address,
    MAX(CASE WHEN QuestionText = 'MEMBER' THEN Answer END) AS [MEMBER],
    MAX(CASE WHEN QuestionText = 'AGE' THEN Answer END) AS [Age],
    SubFormIteration
FROM Responses r
    INNER JOIN FindAddress fa
    ON fa.ResultId = r.ResultId
GROUP BY r.ResultId, SubFormIteration, fa.Address

По существу, я разбил довольно большой запрос в Common Table Expression (CTE). Каждый запрос имел цель: a) Response вытягивает все ответы, кроме адреса, b) Вытягивает только адрес на основе ResultId и c) Объединяет оба запроса вместе.

MAX (CASE...), за которым следует GROUP BY, является альтернативным методом использования PIVOTS, и они по существу выполняют то же самое.

Чтобы применить этот запрос к вашему конкретному случаю, вам нужно только изменить имя таблиц.

Ответ 2

Насколько я понимаю: вы хотите сделать это динамически. Для этого вам нужно подготовить текст вопроса и запустить его.

Подготавливаются столбцы. Затем сливается с запросом.

DECLARE @Columns NVARCHAR(MAX)
DECLARE @Query NVARCHAR(MAX)

SELECT  @Columns = 'C.ResultId' +
           (
                SELECT
                    ',' +       
                    CASE WHEN COL.QuestionText = 'ADDRESS' THEN 'MAX(AA.Answer)' +  COL.QuestionText
                    ELSE 'MAX(CASE WHEN Q.QuestionText = ''' + COL.QuestionText  + ''' THEN C.Answer ELSE  '''' END) AS ' +  COL.QuestionText END
                FROM 
                    #Questions COL
                WHERE
                    COL.QuestionText != 'subform'       
                FOR XML PATH ('')
           ) + 
           ',MAX(C.SubFormIteration) AS SubFormIteration'

SET @Query = '
           SELECT ' +
                @Columns +
         ' FROM 
               #Chunks C INNER JOIN 
               #Results R ON C.ResultId = R.ResultId INNER JOIN 
               #Questions Q ON Q.QuestionId = C.QuestionId INNER JOIN
               (
                    SELECT 
                        IC.ResultId,
                        MAX(IC.Answer) AS Answer
                    FROM 
                       #Chunks IC INNER JOIN 
                       #Results IR ON IC.ResultId = IR.ResultId INNER JOIN 
                       #Questions IQ ON IQ.QuestionId = IC.QuestionId 
                    WHERE
                        IQ.QuestionText = ''ADDRESS''
                    GROUP BY
                        IC.ResultId

               ) AA ON C.ResultId = AA.ResultId
            WHERE
               C.SubFormIteration IS NOT NULL                   
             GROUP BY   
               C.ResultId,       
               C.SubFormIteration           
             '
--SELECT @Query
EXEC sp_executesql @Query

Вывод:

ResultId    MEMBER      AGE  ADDRESS      SubFormIteration
----------- ----------- ---- ------------ --------------------
2272        MEMBER 1    12   WhiteHouse   s0
2272        MEMBER 2    10   WhiteHouse   s1
2273        MEMBER A    23   RpBhavan     s0
2273        MEMBER B    25   RpBhavan     s1

Для комментариев:

Столбцы "ResultId" и "SubFormIteration" сгруппированы и результат. Но операция группировки неверна, потому что информация о адресе выглядит так. Запрос и результат ниже.

ResultId    MEMBER       AGE      ADDRESS      SubFormIteration
----------- -------------------------------------------------------
2272        MEMBER 1     12       WhiteHouse   NULL -- Which value you want to group. s1 or s0
2272        MEMBER 1     12                    s0
2272        MEMBER 2     10                    s1
2273                              RpBhavan     NULL -- Which value you want to group. s1 or s0
2273        MEMBER A     23                    s0
2273        MEMBER B     25                           

Query:

DECLARE @Columns NVARCHAR(MAX)
DECLARE @Query NVARCHAR(MAX)

SELECT  @Columns = 'C.ResultId' +
           (
                SELECT
                    ',' +                           
                    'MAX(CASE WHEN Q.QuestionText = ''' + COL.QuestionText  + ''' THEN C.Answer ELSE  '''' END) AS ' +  COL.QuestionText
                FROM 
                    #Questions COL
                WHERE
                    COL.QuestionText != 'subform'       
                FOR XML PATH ('')
           ) + 
           ',MAX(C.SubFormIteration
           ) AS SubFormIteration'

SET @Query = '
           SELECT ' +
                @Columns +
         ' FROM 
               #Chunks C INNER JOIN 
               #Results R ON C.ResultId = R.ResultId INNER JOIN 
               #Questions Q ON Q.QuestionId = C.QuestionId                              
             GROUP BY   
               C.ResultId,       
               C.SubFormIteration           
             '
--SELECT @Query
EXEC sp_executesql @Query

Ответ 3

Мы не можем видеть ваш входной запрос, но я предполагаю, что вы получаете эти нулевые столбцы из-за объединения LEFT или RIGHT в исходном запросе. Если вы можете разделить результат по вертикали на два вида:

| ID | ADDRESS |
|----|---------|
|  1 | HOUSE 1 |    

и

| ID |  MEMBER  |    AGE | MEMBERNO |
|----|----------|--------|----------|
|  1 | MEMBER 1 |     18 |        1 |
|  1 | MEMBER 2 |     19 |        2 |

а затем присоедините их к полю ID, вы получите именно тот результат, который вам нужен.

Изменить

После просмотра вашего редактирования, вот как вы применяете вышеуказанный метод в своем сценарии:

Первый запрос:

SELECT ID, ADDRESS FROM YourTable WHERE ADDRESS IS NOT NULL

Второй запрос:

SELECT MEMBER, AGE, MEMBERNO WHERE MEMBER IS NOT NULL AND AGE IS NOT NULL AND MEMBERNO IS NOT NULL

Теперь соедините их вместе на ID:

SELECT * FROM
  (SELECT ID, ADDRESS FROM YourTable WHERE ADDRESS IS NOT NULL) AS A
  INNER JOIN
  (SELECT MEMBER, AGE, MEMBERNO WHERE MEMBER IS NOT NULL AND AGE IS NOT NULL AND MEMBERNO IS NOT NULL) AS B
  ON A.ID = B.ID

Ответ 4

Если приведенная выше таблица является результатом нескольких объединений /etc, было бы лучше, если бы мы могли дать рекомендацию, основанную на фактической схеме, доступной вам. Однако, если образец таблицы в ссылке SQL Fiddle - это все, с чем вам нужно работать, попробуйте следующее:

SELECT h.address, p.member, p.age, p.memberno
FROM House h
     INNER JOIN
       House p 
       ON h.id = p.id
         AND h.member IS NULL
         AND p.member IS NOT NULL

Ответ 5

Взглянув на ваш ответ, я думаю, вам нужен результат CROSS JOIN из двух таблиц

Вы можете использовать этот запрос:

SELECT * from table1,table2

Это поможет вам...