带数据透视表的SQL查询?

时间:2016-09-07 08:36:30

标签: sql sql-server pivot-table

我试图围绕如何使用数据透视表来处理我需要的查询。我有3个数据库表。显示相关列:

TableA: Columns = pName
TableB: Columns = GroupName, GroupID
TableC: Columns = pName, GroupID

TableA contains a list of names (John, Joe, Jack, Jane)

TableB contains a list of groups with an ID#. (Soccer|1, Hockey|2, Basketball|3)

TableC contains a list of the names and the group they belong to (John|1, John|3, Joe|2, Jack|1, Jack|2, Jack|3, Jane|3)

我需要使用SQL查询创建一个类似于网格视图的矩阵,该查询将返回TableA(Y轴)中所有名称的列表以及所有可能组(X轴)的列表。如果单元格属于该组,则单元格值将为true或false。

任何帮助将不胜感激。我无法找到有帮助的现有答案。

2 个答案:

答案 0 :(得分:3)

您可以像这样尝试

我在这里设置MCVE,请在下一个问题中尝试创建这个...

DECLARE @Name TABLE (pName VARCHAR(100));
INSERT INTO @Name VALUES('John'),('Joe'),('Jack'),('Jane');
DECLARE @Group TABLE(gName VARCHAR(100),gID INT);
INSERT INTO @Group VALUES ('Soccer',1),('Hockey',2),('Basketball',3);
DECLARE @map TABLE(pName VARCHAR(100),gID INT);
INSERT INTO @map VALUES
  ('John',1),('John',3)
 ,('Joe',2)
 ,('Jack',1),('Jack',2),('Jack',3)
 ,('Jane',3);

此查询将收集值并执行PIVOT

 SELECT p.*
 FROM
 (
     SELECT n.pName
           ,g.gName
           ,'x' AS IsInGroup
     FROM @map AS m
     INNER JOIN @Name AS n ON m.pName=n.pName
     INNER JOIN @Group AS g ON m.gID=g.gID
 ) AS x
 PIVOT
 (
    MAX(IsInGroup) FOR gName IN(Soccer,Hockey,Basketball)
 ) as p 

结果就是这样。

pName   Soccer  Hockey  Basketball
Jack    x       x       x
Jane    NULL    NULL    x
Joe     NULL    x       NULL
John    x       NULL    x

一些提示:

  • 您可以使用10代替x,因为SQL Server不知道真实布尔
  • 您应该在名字中添加pID。永远不要在真实数据上加入表格(除非它是独特且不可更改的东西[这意味着永远不会] !!!)

更新动态SQL(thx到@djlauk)

如果您想要一个动态处理任何数量的群组的查询。但请注意,您在 ad-hoc-SQL 中失去了使用此功能的机会,例如VIEWinline TVF,这是一个非常大的反向... < / p>

CREATE TABLE #Name(pName VARCHAR(100));
INSERT INTO #Name VALUES('John'),('Joe'),('Jack'),('Jane');
CREATE TABLE #Group(gName VARCHAR(100),gID INT);
INSERT INTO #Group VALUES ('Soccer',1),('Hockey',2),('Basketball',3);
CREATE TABLE #map(pName VARCHAR(100),gID INT);
INSERT INTO #map VALUES
  ('John',1),('John',3)
 ,('Joe',2)
 ,('Jack',1),('Jack',2),('Jack',3)
 ,('Jane',3);

DECLARE @ListOfGroups VARCHAR(MAX)=
(
    STUFF
    (
        (
        SELECT DISTINCT ',' + QUOTENAME(gName) 
        FROM #Group
        FOR XML PATH('')
        ),1,1,''
    )
);

DECLARE @sql VARCHAR(MAX)=
(
 'SELECT p.*
 FROM
 (
     SELECT n.pName
           ,g.gName
           ,''x'' AS IsInGroup
     FROM #map AS m
     INNER JOIN #Name AS n ON m.pName=n.pName
     INNER JOIN #Group AS g ON m.gID=g.gID
 ) AS x
 PIVOT
 (
    MAX(IsInGroup) FOR gName IN(' +  @ListOfGroups + ')
 ) as p');

 EXEC(@sql); 
 GO

 DROP TABLE #map;
 DROP TABLE #Group;
 DROP TABLE #Name;

答案 1 :(得分:0)

我怀疑如果添加类别,保持枢轴更新可能会很费力。或许我只是喜欢Excel(如果你忽略了一个主要优势)。假设您有Office 365,以下方法也可能会有所帮助。

我根据上面看到的代码使用3个CREATE TABLE语句和3个INSERT语句添加了三个表。 (解决方案使用临时表来插入特定值,但我相信您已经在三个表中拥有了数据,称为TableA,TableB,TableC)。

CREATE TABLE TestName (pName VARCHAR(100));
INSERT INTO TestName VALUES('John'),('Joe'),('Jack'),('Jane');
CREATE TABLE TestGroup (gName VARCHAR(100),gID INT);
INSERT INTO TestGroup VALUES ('Soccer',1),('Hockey',2),('Basketball',3);
CREATE TABLE Testmap (pName VARCHAR(100),gID INT);
INSERT INTO Testmap VALUES
  ('John',1),('John',3)
 ,('Joe',2)
 ,('Jack',1),('Jack',2),('Jack',3)
 ,('Jane',3);

然后,在MS Excel中,我添加了(可能有一个较短的序列,但我仍然在探索)这三个表作为来自数据库&gt;的查询。 sql server数据库。添加它们之后,我将所有三个添加到数据模型中(如果你问我可以详细说明)。

然后我从功能区插入了数据透视表,选择了外部数据源,但打开了表格选项卡(而不是连接选项卡),找到我的数据模型(我的列表是最重要的),然后点击了打开。在某些时候,Excel提示我创建表之间的关系,它为我自动生成它们做得很好。

经过小调整后,我的数据透视表就像这样(我也可以要求Excel将数据显示为数据透视图)。 Pivot showing groups as columns and names as rows.

优点是,如果列表(组)发生更改,则不必在SQL中重新访问PIVOT代码。正如我想其他人提到的那样,考虑使用id作为pName,或者另一种方法来确保如果你有两个名叫John或Jack的人,你第二天就不会被卡住。

在Excel中,您可以选择何时刷新数据(或数据透视),刷新后,将添加和计算任何其他类别。