由于我使用的是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,但我对动态列 - 值映射没有太大影响。
答案 0 :(得分:2)
我没有方便尝试的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
一些证据表明它不使用参数或特定产品ID:
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 :(得分:1)
如果没有动态SQL,您需要明确说明最终会使用哪些列。 (在SQL Server 2000中,只有在您已经知道列名称等的情况下才能进行透视。如果需要动态数量的列,使用动态名称,SQL Server 2000无法在不编写动态SQL的情况下执行此操作)
此外,根据评论,非规范化数据通常最好在GUI中完成,而不是在数据库本身上完成。
但这应该做你要求的......
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
也会提出您要求的问题的后半部分。
答案 2 :(得分:1)
我的第一个想法是使用这样的左连接:(一切都是显式的,但在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