Можно ли объединить столбцы из представления и хранимой процедуры? - PullRequest
3 голосов
/ 08 апреля 2020

Я использую SQL Server 2017. Я пытаюсь вернуть набор данных с SQL Сервер в формате, который в конечном итоге go, в электронную таблицу Excel. Данные сложны, и хотя я мог бы вывести данные в виде двух наборов в Excel, а затем использовать код для создания VLOOKUP для объединения наборов данных, я стараюсь избежать этого дополнительного осложнения.

Проще говоря, у меня есть набор оценок для студентов за курсы, которые они прошли. Таблица может выглядеть примерно так:

CREATE TABLE TempStudentMarks 
(
    StudentID VARCHAR(4),
    CourseName VARCHAR(50),
    Mark INT
)

INSERT INTO TempStudentMarks (StudentID, CourseName, Mark)
VALUES ('1234', 'English', 78),
        ('1234', 'Maths', 68),
        ('1234', 'Science', 58),
        ('4321', 'English', 66),
        ('4321', 'Maths', 76),
        ('4321', 'French', 86),
        ('5555', 'Maths', 69),
        ('5555', 'Science', 49),
        ('5555', 'French', 69),
        ('6666', 'English', 33),
        ('6666', 'Maths', 44),
        ('6666', 'Science', 55),
        ('6666', 'French', 66)

Я создал хранимую процедуру, которая выводит каждого студента в строке, а каждый курс в столбце. Он использует динамический c SQL, потому что количество курсов варьируется в зависимости от года и зависит от ряда других факторов:

CREATE PROCEDURE spTemp_StudentMarksPivot
AS
    DECLARE @SQL NVARCHAR(MAX)
    DECLARE @PivotCols NVARCHAR(MAX)

    SELECT 
        @PivotCols = COALESCE(@PivotCols + ',', '') + 
                     QUOTENAME(CourseName) 
    FROM 
        (SELECT DISTINCT CourseName 
         FROM TempStudentMarks) AS HeaderData

    PRINT @PivotCols

    SET @SQL = 'SELECT StudentID, ' + @PivotCols + ' 
                FROM (SELECT * FROM TempStudentMarks) SourceData
                PIVOT (MAX(Mark) FOR CourseName IN (' + @PivotCols + ')) AS PivotData'

    PRINT @SQL

    EXEC sys.sp_executesql @SQL

Это работает достаточно хорошо; вывод, который я получаю для этого:

EXEC spTemp_StudentMarksPivot

выглядит так:

StudentID English     French      Maths       Science
--------- ----------- ----------- ----------- -----------
1234      78          NULL        68          58
4321      66          86          76          NULL
5555      NULL        69          69          49
6666      33          66          44          55

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

CREATE VIEW vwStudentAggregates
AS
    SELECT tsm.StudentID, AVG(Mark) AS Average, MAX(Mark) AS BestMark
    FROM TempStudentMarks tsm
    GROUP BY tsm.StudentID

Когда я запускаю оператор SELECT для этого представления, я получаю следующее:

StudentID Average     BestMark
--------- ----------- -----------
1234      68          78
4321      76          86
5555      62          69
6666      49          66

Все это хорошо.

Но у меня вопрос об объединении двух, чтобы получить результат, подобный следующему:

StudentID English     French      Maths       Science     Average    BestMark
--------- ----------- ----------- ----------- ----------- ---------- ----------
1234      78          NULL        68          58          68         78
4321      66          86          76          NULL        76         76
5555      NULL        69          69          49          62         69
6666      33          66          44          55          49         66

Возможно ли это?

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

Вставьте результаты хранимой процедуры во временную таблицу

И хотя я думал, что это может сделать работу, ситуация осложняется тем, что некоторые пользователи входят в систему через Windows аутентификацию, в то время как другие должны использовать SQL аутентификацию, поэтому, хотя это решение использует OpenRowset, я опускаюсь на бит, который говорит

SELECT * 
INTO #MyTempTable 
FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC getBusinessLineHistory')

потому что я не знаю, как создать строку подключения, которая будет работать для всех.

[Редактировать] Я просто немного поигрался с этой идеей и получил целый ряд ошибок, начиная с

"Процедура sp_configure, строка 105 Пользователь не имеет разрешения выполнить это действие. "

и заканчивая

"SQL Сервер заблокировал доступ к ЗАЯВЛЕНИЮ 'OpenRowset / OpenDatasource"

, так что это не выглядит хорошо ... (эта работа для клиента где отдел ИКТ довольно ограничен в вопросах безопасности и вряд ли захочет предоставить дополнительные разрешения ...

Если кто-то может помочь или направить, я был бы очень благодарен.

Большое спасибо Andrew

Ответы [ 2 ]

2 голосов
/ 08 апреля 2020
SET @SQL = '
SELECT PivotData.StudentID, ' + @PivotCols + ', vst.Average, vst.BestMark 
FROM (SELECT * FROM TempStudentMarks) SourceData
PIVOT (MAX(Mark) FOR CourseName IN (' + @PivotCols + ')) AS PivotData
join vwStudentAggregates as vst on PivotData.StudentID = vst.StudentID
';
--or
SET @SQL = '
select *
from
(
SELECT StudentID, ' + @PivotCols + '
FROM (SELECT * FROM TempStudentMarks) SourceData
PIVOT (MAX(Mark) FOR CourseName IN (' + @PivotCols + ')) AS PivotData
) as pd
join vwStudentAggregates as vst on pd.StudentID = vst.StudentID
';
--you can even parameterize the procedure, to return or not the studentaggregates and conditionally construct the executed @SQL.
0 голосов
/ 08 апреля 2020

ur wanted sql image

вы пишете sql для разных таблиц, вы хотите, чтобы результаты были в одной таблице. table joining это способ сделать это.

query:

select TempStudentMarks.StudentID, avg(TempStudentMarks.mark) as 
average,max(TempStudentMarks.mark) as maximum,
Science.mark as science,French.Mark as french,Math.mark as math,
English.Mark as english from TempStudentMarks
LEFT JOIN 
    (
        select StudentID,mark  from TempStudentMarks where  CourseName='Science'
    ) AS Science
    on Science.StudentID=TempStudentMarks.StudentID
LEFT JOIN 
    (
        select StudentID,mark  from TempStudentMarks where  CourseName='French'
    ) AS French
    on French.StudentID=TempStudentMarks.StudentID

LEFT JOIN 
    (
        select StudentID,mark  from TempStudentMarks where  CourseName='Maths'
    ) AS Math
    on Math.StudentID=TempStudentMarks.StudentID

LEFT JOIN 
    (
        select StudentID,mark  from TempStudentMarks where  CourseName='English'
    ) AS English
    on English.StudentID=TempStudentMarks.StudentID

group by TempStudentMarks.StudentID,French.Mark,Science.Mark,English.Mark,Math.Mark



Мне не хотелось писать al oop. Вы можете попробовать сами, если хотите

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...