2015-03-31 2 views
1

Я новичок в SQL Server и есть проблемаT SQL: Выбор каждой найденной строки в качестве столбца

Вот моя базовая ситуация:

Таблица Foo:

id | pid | val1 | val2 | val3 
------------------------------ 
1 | 4721 | 1 | 2 | 3 
2 | 25 | 4 | 5 | 6 
3 | 4721 | 7 | 8 | 9 

Таблица результатов:

pid | id_1 | val1_1 | val2_1 | val3_1 | id_2 | val1_2 | val2_2 | val3_2 | id_3 | val1_3 | val2_3 | val3_3 
---------------------------------------------------- 
4721 | 1 | 1 | 2 | 3 | 2 | 4 | 5 | 6 | 3 | 7 | 8 | 9 

То, что я хочу, чтобы выбрать все соответствующие строки в PID = 4721, и показать их в отдельной колонке.

+0

почему вторая строка в результате? –

+0

@GiorgiNakeuri sry, вторая строка ошибочна в результате. – hunt3r87

ответ

2

Строго говоря, SQL-ответ на эту проблему: «Это проблема отображения. Дисплей - проблема приложения, а не проблема с базой данных». Реляционно говоря, это также просит сервер нарушить первую нормальную форму и создать повторяющиеся группы, а это означает, что почти наверняка потребуется перепрыгнуть через несколько обручей и будет иметь значительные ограничения.

«Правильный путь» в соответствии с DBA будет делать что-то вроде:

SELECT pid, id, val1, val2, val3 
FROM Table 
ORDER BY pid, id; 

Затем в вашем приложении, ходить через результирующий набор и форматирование вывода, как вам нужно.

Можно даже включить для каждого id в пределах pid приказ может быть, сделать это немного проще:

SELECT pid, 
    id, 
    val1, 
    val2, 
    val3, 
    ROW_NUMBER() OVER (PARTITION BY pid, ORDER BY id) AS "id_order" 
FROM Table 
ORDER BY pid, id; 

Однако, предположим, что вы не можете сделать это.

Если вы абсолютно имеют сделать это с помощью SQL (например, ваше программное обеспечение отчетности не обрабатывает такого рода вещи, и все это у вас есть), и вы знаете, что вы никогда не более 3 id для каждого pid, вы можете попробовать что-то вроде этого:

;WITH Table_id_ordered AS (
    SELECT pid, 
     id, 
     val1, 
     val2, 
     val3, 
     ROW_NUMBER() OVER (PARTITION BY pid, ORDER BY id) AS "id_order" 
    FROM Table 
) 
SELECT t1.pid, 
    t1.id as id_1, 
    t1.val1 as val1_1, 
    t1.val2 as val2_1, 
    t1.val3 as val3_1, 
    t2.id as id_2, 
    t2.val1 as val1_2, 
    t2.val2 as val2_2, 
    t2.val3 as val3_2, 
    t3.id as id_3, 
    t3.val1 as val1_3, 
    t3.val2 as val2_3, 
    t3.val3 as val3_3 
FROM Table_id_ordered t1 
LEFT JOIN Table_id_ordered t2 
    ON t2.pid = t1.pid 
    AND t2.id_order = t1.id_order + 1 
LEFT JOIN Table_id_ordered t3 
    ON t3.pid = t2.pid 
    AND t3.id_order = t2.id_order + 1 
WHERE t1.id_order = 1; 

Очевидно, что это хорошо только до трех id для любого pid,. Как написано, он также не скажет вам, есть ли в вашей таблице id, который был бы в первом или пятом. Они просто полностью отсутствуют в результатах. Первый метод, который я упомянул, всегда будет возвращать все данные, и приложение может быть написано для обработки этого довольно легко.

Динамические решения могут быть созданы для любого количества id s для pid, но это значительно сложнее.

+0

Большое спасибо, ты мне очень помог. я организую вывод на стороне приложения, но это еще одна тема. – hunt3r87

0

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

Примечание: Я немного изменил имена столбцов, чтобы они правильно сортировались.

IF OBJECT_ID('tempdb..#yourTable') IS NOT NULL 
    DROP TABLE #yourTable; 
IF OBJECT_ID('tempdb..#UnpivotTable') IS NOT NULL 
    DROP TABLE #UnpivotTable; 

SELECT * INTO #yourTable 
FROM 
(
    SELECT 1,4721,1,2,3 
    UNION ALL 
    SELECT 2,25,4,5,6 
    UNION ALL 
    SELECT 3,4721,7,8,9 
) AS bar(id,pID,val1,val2,val3); 

DECLARE @cols VARCHAR(MAX); 


SELECT pID, 
     --This is where I create the column names 
     CONCAT(ROW_NUMBER() OVER (PARTITION BY pID,col ORDER BY pID,id2),'_',col) NewColName, 
     val INTO #UnpivotTable 
FROM 
(
    --I need ID2 for ROW_NUMBER() so the NewColNames are applied to the correct values 
    SELECT *,id as ID2 
    FROM #yourTable 
) A 
UNPIVOT 
(
    val FOR col IN(ID,val1,val2,val3) 
) unpvt 


--Puts columns in alphabetic order into @cols 
SELECT @cols = COALESCE(@cols + ',','') + QUOTENAME(NewColName) 
FROM #UnpivotTable 
--Group by gets rid of any duplicate column names 
GROUP BY NewColName 
ORDER BY NewColName 

EXEC 
(
    'SELECT * 
    FROM #UnpivotTable 
    PIVOT 
    (
     MAX(val) FOR newColName IN (' + @cols + ') 
    ) pvt 
    WHERE pID = 4721' 
) 

--Cleanup 
IF OBJECT_ID('tempdb..#yourTable') IS NOT NULL 
    DROP TABLE #yourTable; 
IF OBJECT_ID('tempdb..#UnpivotTable') IS NOT NULL 
    DROP TABLE #UnpivotTable; 

Результаты:

pID   1_id  1_val1  1_val2  1_val3  2_id  2_val1  2_val2  2_val3 
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- 
4721  1   1   2   3   3   7   8   9 
Смежные вопросы