SQL-запрос для установки строк в виде столбцов - PullRequest
3 голосов
/ 07 июля 2011

Поскольку я использую SQL Server 2000 и не могу позволить себе роскошь сводных таблиц SQL Server 2005, мне нужна помощь в создании запроса.

Ниже приведены примеры данных.

TBLProduct
ProductID   ProductName
1           Jacket
2           Blazer
3           Chaleco

TBLFactors
FactorID    FactorName
1           Length
2           Threading
3           Wool
4       Cotton

TBLFactorInspect
ID  ProductID   FactorID    FactorValue
1   1           1           5.00
2   1           2           5.55
3   2           2           6.33
4   2           3           3.66
5   2           4           1.05

Мне нужна помощь в запросе, который выводит данные в это:

ProductID   ProductName Length  Threading   Wool    Cotton
1           Jacket      5.00    5.55        -       -
2           Blazer      -       6.33        3.66    1.05
3           Chaleco     -       -           -       -

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

ProductID   ProductName Length  Threading
1           Jacket      5.00    5.55

Любые предложения высоко ценятся. Спасибо.

Обновление: Если хранимая процедура была бы лучшим ответом для достижения этой цели, то у меня не возникло бы никаких проблем с этим, так как мне кажется, что ограничения SQL Server 2K по созданию сводок являются основным препятствием здесь.

Я пытаюсь работать с динамическим SQL в решении Stored Proc, но я не зацикливаюсь на динамическом сопоставлении столбцов и значений.

Ответы [ 3 ]

2 голосов
/ 07 июля 2011

У меня нет экземпляра SQL Server 2000, который можно было бы попробовать, но посмотрите, поможет ли это вам. Я немного удивлен требованием условного включения столбцов - будем надеяться, что приложение создано для обработки случая, когда столбцы внезапно появляются и исчезают в зависимости от параметров и изменяющихся данных в таблице TBLFactorInspect.

USE [tempdb];
GO
SET NOCOUNT ON;
GO

Установка:

CREATE TABLE dbo.TBLProduct
(
    ProductID INT PRIMARY KEY, ProductName NVARCHAR(50)
);

INSERT dbo.TBLProduct(ProductID, ProductName)
SELECT 1, 'Jacket'
UNION SELECT 2, 'Blazer'
UNION SELECT 3, 'Chaleco';

CREATE TABLE dbo.TBLFactors
(
    FactorID INT PRIMARY KEY, FactorName NVARCHAR(50)
);

INSERT dbo.TBLFactors(FactorID, FactorName)
SELECT 1, 'Length'
UNION SELECT 2, 'Threading'
UNION SELECT 3, 'Wool'
UNION SELECT 4, 'Cotton';

CREATE TABLE dbo.TBLFactorInspect
(
    ID INT PRIMARY KEY, ProductID INT,
    FactorID INT, FactorValue DECIMAL(5,2)
);

INSERT dbo.TBLFactorInspect(ID, ProductID, FactorID, FactorValue)
SELECT 1,1,1,5.00 UNION SELECT 2,1,2,5.55
UNION SELECT 3,2,2,6.33 UNION SELECT 4,2,3,3.66
UNION SELECT 5,2,4,1.05;
GO

Теперь код:

CREATE PROCEDURE dbo.GetProductPivot
    @ProductID INT = NULL
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @sql NVARCHAR(4000);
    SET @sql = N'';

    SELECT @sql = @sql + N'
        ' + QUOTENAME(FactorName) 
        + ' = MAX(CASE WHEN d.FactorID = ' 
        + RTRIM(FactorID) + ' THEN d.FactorValue END),'
    FROM
    (
        SELECT f.FactorID, f.FactorName
        FROM dbo.TBLFactorInspect AS d
        INNER JOIN dbo.TBLFactors AS f
        ON f.FactorID = d.FactorID
        WHERE (d.ProductID = @ProductID OR @ProductID IS NULL)
        GROUP BY f.FactorID, f.FactorName
    ) AS f
    ORDER BY f.FactorID;

    IF @sql = N''
    BEGIN
        SELECT ProductID, ProductName, 
            Result = 'No data in TBLFactorInspect'
            FROM dbo.TBLProduct
            WHERE ProductID = COALESCE(@ProductID, ProductID);
    END
    ELSE
    BEGIN
        SELECT @sql = N'SELECT p.ProductID, p.ProductName, ' + 
            LEFT(@sql, LEN(@sql)-1) + '
                FROM dbo.TBLProduct AS p
                LEFT OUTER JOIN dbo.TBLFactorInspect AS d
                ON p.ProductID = d.ProductID
                ' + CASE WHEN @ProductID IS NOT NULL THEN 
                ' WHERE p.ProductID = ' + RTRIM(@ProductID) ELSE '' END + '
                GROUP BY p.ProductID, p.ProductName
                ORDER BY p.ProductID;';

        EXEC sp_executeSQL @sql;
    END
END
GO

Некоторые доказательства того, что он работает без параметров или конкретных идентификаторов продукта:

EXEC dbo.GetProductPivot;
EXEC dbo.GetProductPivot @ProductID = 1;
EXEC dbo.GetProductPivot @ProductID = 2;
EXEC dbo.GetProductPivot @ProductID = 3;
GO

А теперь давайте добавим новый фактор и докажем, что он продолжает работать:

INSERT dbo.TBLFactors(FactorID, FactorName)
    SELECT 5, 'Tubing';

INSERT dbo.TBLFactorInspect(ID, ProductID, FactorID, FactorValue)
SELECT 6,1,5,2.75;
GO
EXEC dbo.GetProductPivot;
EXEC dbo.GetProductPivot @ProductID = 1;
GO

Очистить:

DROP TABLE dbo.TBLProduct, dbo.TBLFactors, dbo.TBLFactorInspect;
GO
DROP PROCEDURE dbo.GetProductPivot;
GO
1 голос
/ 07 июля 2011

Моей первой мыслью было бы использовать левые соединения следующим образом: (Все явно, но это работает с конечным числом строк в tblFactors)

SELECT
  tblProduct.ProductID,
  tblProduct.ProductName,
  ISNULL(tblLength.FactorValue, '-') AS [Length],
  ISNULL(tblThreading.FactorValue, '-') AS Threading,
  ISNULL(tblWool.FactorValue, '-') AS Wool,
  ISNULL(tblCotton.FactorValue, '-') AS Cotton
FROM
  tblProduct
LEFT JOIN tblFactorInspect tblLength
    ON  tblLength.ProductID = tblProduct.ProductID AND FactorID = 1
LEFT JOIN tblFactorInspect tblThreading
    ON  tblThreading.ProductID = tblProduct.ProductID AND FactorID = 2
LEFT JOIN tblFactorInspect tblWool
    ON  tblWool.ProductID = tblProduct.ProductID AND FactorID = 3
LEFT JOIN tblFactorInspect tblCotton
    ON  tblCotton.ProductID = tblProduct.ProductID AND FactorID = 4
1 голос
/ 07 июля 2011

Без динамического SQL вам нужно четко указать, с какими столбцами вы закончите. (В SQL Server 2000 вы можете использовать Pivot только в том случае, если вы уже знаете, какими будут имена столбцов и т. Д. Если вам нужно динамическое число столбцов с динамическими именами, SQL Server 2000 не сможет сделать это без кодирования динамического SQL. )

Кроме того, согласно комментарию, денормализованные данные часто лучше всего делать в графическом интерфейсе, а не на самой базе данных.

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

SELECT
  tblProduct.ProductID,
  tblProduct.ProductName,
  MAX(CASE WHEN tblFactorInspect.FactorID = 1 THEN tblFactorInspect.FactorValue END) AS Length,
  MAX(CASE WHEN tblFactorInspect.FactorID = 2 THEN tblFactorInspect.FactorValue END) AS Threading,
  MAX(CASE WHEN tblFactorInspect.FactorID = 3 THEN tblFactorInspect.FactorValue END) AS Wool,
  MAX(CASE WHEN tblFactorInspect.FactorID = 4 THEN tblFactorInspect.FactorValue END) AS Cotton
FROM
  tblProduct
LEFT JOIN
  tblFactorInspect
    ON  tblFactorInspect.ProductID = tblProduct.ProductID
GROUP BY
  tblProduct.ProductID,
  tblProduct.ProductName

Добавление WHERE tblProduct.ProductID = 1 также даст то, о чем вы просили, как вторую половину вашего вопроса.

...