这里有很多东西要解开。让我们从如何呈现演示数据开始:
如果您为您的数据提供 DDL 和 DML,那么人们可以更轻松地使用:
DECLARE @Customer TABLE (ID INT, Name NVARCHAR(100))
DECLARE @Detail TABLE (ID INT, Name NVARCHAR(20))
DECLARE @DataValues TABLE (CustomerID INT, DetailID INT, [Values] NVARCHAR(20))
INSERT INTO @Customer (ID, Name) VALUES
(1, 'Jack'),(2, 'Anne')
INSERT INTO @Detail (ID, Name) VALUES
(1, 'Sex'),(2, 'Age')
INSERT INTO @DataValues (CustomerID, DetailID, [Values]) VALUES
(1, 1, 'M'),(1, 2, '30'),(2, 1, 'F'),(2, 2, '28')
这将设置您的表(作为变量)并使用演示数据填充它们。
接下来让我们谈谈这里的可怕架构。
您也应该始终尽量避免使用保留字作为列名。 Values 是一个关键字。
这可能应该是一个客户表:
DECLARE @Genders TABLE (ID INT IDENTITY, Name NVARCHAR(20))
DECLARE @Customer1 TABLE (CustomerID INT IDENTITY, Name NVARCHAR(100), BirthDate DATETIME, GenderID INT NULL, Age AS (DATEDIFF(YEAR, BirthDate, CURRENT_TIMESTAMP)))
请注意,我使用的是 BirthDate 而不是 Age。这是因为一个人的年龄会随着时间而改变,但他们的出生日期不会。不应存储基于另一个属性计算的属性(但如果您愿意,可以使用计算列,就像我们在这里一样)。您还会注意到,我们将通过 Gender ID 引用它,而不是在客户表中明确定义性别。这是一个查找表。
如果您使用了规范化模式,您的查询将如下所示:
/* Demo Data */
DECLARE @Genders TABLE (ID INT IDENTITY, Name NVARCHAR(20));
INSERT INTO @Genders (Name) VALUES
('Male'),('Female'),('Non-Binary');
DECLARE @Customer1 TABLE (CustomerID INT IDENTITY, Name NVARCHAR(100), BirthDate DATETIME, GenderID INT NULL, Age AS (DATEDIFF(YEAR, BirthDate, CURRENT_TIMESTAMP)));
INSERT INTO @Customer1 (Name, BirthDate, GenderID) VALUES
('Jack', '2000-11-03', 1),('Anne', '2000-11-01', 2),('Chris', '2001-05-13', NULL);
/* Query */
SELECT *
FROM @Customer1 c
LEFT OUTER JOIN @Genders g
ON c.GenderID = g.ID;
现在介绍如何从您拥有的结构中获取您想要的数据。无论如何,您这样做将是杂技,因为我们必须针对模式工作。
/* Demo Data */
DECLARE @Customer TABLE (ID INT, Name NVARCHAR(100));
DECLARE @Detail TABLE (ID INT, Name NVARCHAR(20));
DECLARE @DataValues TABLE (CustomerID INT, DetailID INT, [Values] NVARCHAR(20));
INSERT INTO @Customer (ID, Name) VALUES
(1, 'Jack'),(2, 'Anne');
INSERT INTO @Detail (ID, Name) VALUES
(1, 'Sex'),(2, 'Age');
INSERT INTO @DataValues (CustomerID, DetailID, [Values]) VALUES
(1, 1, 'M'),(1, 2, '30'),(2, 1, 'F'),(2, 2, '28');
/* Query */
SELECT *
FROM (
SELECT d.Name AS DetailName, c.Name AS CustomerName, DV.[Values]
FROM @DataValues dv
INNER JOIN @Detail d
ON dv.DetailID = d.ID
INNER JOIN @Customer c
ON dv.CustomerID = c.ID
) a
PIVOT (
MAX([Values]) FOR DetailName IN (Sex,Age)
) p;
CustomerName Sex Age
-----------------------
Anne F 28
Jack M 30