Как динамически объявлять столбцы в запросе выбора с помощью PIVOT - PullRequest
2 голосов
/ 22 февраля 2012

Я пишу запрос, чтобы получить адрес для PersonID.Следующий запрос работает для меня, но он возвращается только с двумя адресами.Я хочу обработать номер n адреса одним запросом.Есть ли способ сделать это?

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

SELECT 
  PersonID, PersonName
  [Address1], [Address2]
FROM
  (
  SELECT 
    P.PersonID, 
    P.PersonName, 
    (ROW_NUMBER() OVER(PARTITION BY P.PersonID ORDER BY A.AddressID)) RowID
    FROM tblPerson
    INNER JOIN tblAddress AS A ON A.PersonID = P.PersonID
  ) AS AddressTable
PIVOT
  (
    MAX(AddressID)
    FOR RowID IN ([Address1], [Address2])
  ) AS PivotTable;

1 Ответ

6 голосов
/ 22 февраля 2012

Предполагается, что следующие таблицы и примеры данных:

USE tempdb;
GO

CREATE TABLE dbo.tblPerson(PersonID INT, PersonName VARCHAR(255));

INSERT dbo.tblPerson SELECT 1, 'Bob'
           UNION ALL SELECT 2, 'Charlie'
           UNION ALL SELECT 3, 'Frank'
           UNION ALL SELECT 4, 'Amore';

CREATE TABLE dbo.tblAddress(AddressID INT, PersonID INT, [Address] VARCHAR(255));

INSERT dbo.tblAddress SELECT 1,1,'255 1st Street'
            UNION ALL SELECT 2,2,'99 Elm Street'
            UNION ALL SELECT 3,2,'67 Poplar Street'
            UNION ALL SELECT 4,2,'222 Oak Ave.'
            UNION ALL SELECT 5,1,'36 Main Street, Suite 22'
            UNION ALL SELECT 6,4,'77 Sicamore Ct.';

Следующий запрос получает требуемые результаты и показывает, как он обрабатывает 0, 1 или n адресов.В этом случае наибольшее число равно 3, но вы можете поиграть с большим количеством адресов, если захотите, слегка изменив пример данных.

DECLARE @col   NVARCHAR(MAX) = N'',
        @sel   NVARCHAR(MAX) = N'',
        @from  NVARCHAR(MAX) = N'',
        @query NVARCHAR(MAX) = N'';

;WITH m(c) AS
(
    SELECT TOP 1 c = COUNT(*)
    FROM dbo.tblAddress
    GROUP BY PersonID
    ORDER BY c DESC
)
SELECT @col = @col + ',[Address' + RTRIM(n.n) + ']',
    @sel = @sel + ',' + CHAR(13) + CHAR(10) + '[Address' + RTRIM(n.n) + '] = x' 
        + RTRIM(n.n) + '.Address',
    @from = @from + CHAR(13) + CHAR(10) + ' LEFT OUTER JOIN xMaster AS x' 
        + RTRIM(n.n) + ' ON x' + RTRIM(n.n) + '.PersonID = p.PersonID AND x' 
        + RTRIM(n.n) + '.rn = ' + RTRIM(n.n)
FROM m CROSS JOIN (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id]) 
    FROM sys.all_columns) AS n WHERE n.n <= m.c;

SET @query = N';WITH xMaster AS 
(
  SELECT PersonID, Address, 
    rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address) 
    FROM dbo.tblAddress
)
SELECT PersonID, PersonName' + @col
+ ' FROM
    (
        SELECT p.PersonID, p.PersonName, ' + STUFF(@sel, 1, 1, '')
 + CHAR(13) + CHAR(10) + ' FROM dbo.tblPerson AS p ' + @from + '
 ) AS Addresses;';

PRINT @query;
--EXEC sp_executesql @query;

Если вы напечатаете SQL, вы увидите такой результат:

;WITH xMaster AS 
(
  SELECT PersonID, Address, 
    rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address) 
    FROM dbo.tblAddress
)
SELECT PersonID, PersonName,[Address1],[Address2],[Address3] FROM
    (
        SELECT p.PersonID, p.PersonName, 
 [Address1] = x1.Address,
 [Address2] = x2.Address,
 [Address3] = x3.Address 
FROM dbo.tblPerson AS p 
 LEFT OUTER JOIN xMaster AS x1 ON x1.PersonID = p.PersonID AND x1.rn = 1
 LEFT OUTER JOIN xMaster AS x2 ON x2.PersonID = p.PersonID AND x2.rn = 2
 LEFT OUTER JOIN xMaster AS x3 ON x3.PersonID = p.PersonID AND x3.rn = 3
 ) AS Addresses;

Если вы выполните его, вы увидите это:

enter image description here

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

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