【问题标题】:SQL query to return a report of two tablesSQL 查询返回两个表的报告
【发布时间】:2012-11-17 11:46:45
【问题描述】:

我有两个表,AnswersUsers,看起来像这样:

Answers (AnswerID, QuestionNumber, Answer, UserID)
Users (UserID, FirstName, LastName)

我可以运行什么 SQL 查询来返回这样的报告:

【问题讨论】:

  • 另外,如果你能提供一些样本数据,给出正确答案会很有帮助。您有没有尝试过,如果有,请发布您的查询。
  • 您真的希望用户名作为列标题吗?

标签: sql sql-server-2008 tsql pivot


【解决方案1】:

您可以使用PIVOT 函数来转换此数据。将Name(名字/姓氏)作为标题似乎很不寻常,但如果这是您想要的,那么您可以使用以下内容:

select *
from
(
  select a.questionnumber,
    u.firstname +' '+ u.lastname as Name,
    a.answer
  from answers a
  left join users u
    on a.userid = u.userid
) src
pivot
(
  max(answer)
  for name in ([John Smith], [Bob Jones])
) piv;

SQL Fiddle with Demo

结果:

| QUESTIONNUMBER | JOHN SMITH | BOB JONES |
-------------------------------------------
|              1 |       blah |      test |
|              2 |      hsdfk |    (null) |

我想你会希望 Question Numbers 作为标题,下面的答案如下:

select *
from
(
  select 'QuestionNumber'+cast(a.questionnumber as varchar(10)) questionnumber,
    u.firstname +' '+ u.lastname as Name,
    a.answer
  from answers a
  left join users u
    on a.userid = u.userid
) src
pivot
(
  max(answer)
  for questionnumber in ([QuestionNumber1], [QuestionNumber2])
) piv;

SQL Fiddle with Demo

结果:

|       NAME | QUESTIONNUMBER1 | QUESTIONNUMBER2 |
--------------------------------------------------
|  Bob Jones |            test |          (null) |
| John Smith |            blah |           hsdfk |

如果您有已知数量的要转换的项目,上述答案将非常有用。但是如果你有一个未知的数字,那么你可以使用动态SQL来PIVOT这个数据:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('QuestionNumber'+cast(questionnumber as varchar(10))) 
                    from answers
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT Name, ' + @cols + ' from 
             (
              select ''QuestionNumber''+cast(a.questionnumber as varchar(10)) questionnumber,
                u.firstname +'' ''+ u.lastname as Name,
                a.answer
              from answers a
              left join users u
                on a.userid = u.userid
            ) x
            pivot 
            (
                max(answer)
                for questionnumber in (' + @cols + ')
            ) p '

execute(@query)

SQL Fiddle with Demo

结果:

|       NAME | QUESTIONNUMBER1 | QUESTIONNUMBER2 |
--------------------------------------------------
|  Bob Jones |            test |          (null) |
| John Smith |            blah |           hsdfk |

【讨论】:

  • 如何在第一个查询中更改“[John Smith], [Bob Jones]”以返回所有用户?我试过“(从用户中选择名字,姓氏)”
  • @user982119 您必须对所有值进行硬编码,或者您可以更改动态版本以使用 Users 而不是问题编号。
  • @user982119 查询将与此类似 -- sqlfiddle.com/#!3/666f1/9
  • 绝对是最后一个附加问题:(您刚刚粘贴的最新 sqlfiddle 对我有用)如何添加以“,”分隔的另一列。 IE。 a.answer +'', ''+ a.answercomment
  • @user982119 看到这个小提琴,我将answer 转换为varchar,所以它可以与comments 连接——sqlfiddle.com/#!3/a02cb/2
【解决方案2】:

这称为交叉表查询 - 有大量示例说明如何生成它们;例如:

http://www.simple-talk.com/sql/t-sql-programming/creating-cross-tab-queries-and-pivot-tables-in-sql/

编辑

@Bluefleet 使用 pivot 可能是最好的答案;使用简单的交叉表可能需要您提前了解数据形状的某些方面,因此列本质上是硬编码的 - 如果列是稳定的集合,那么以下应该可以工作:

declare @Answers table (AnswerID int, QuestionNumber int , Answer int , UserID int)
declare @Users table (UserID int , FirstName varchar(10), LastName varchar(10))
declare @Questions table (QuestionNumber int, QuestionName varchar(10))

insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (1, 1, 10, 1)
insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (2, 2, 20, 1)
insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (3, 3, 30, 2)
insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (1, 1, 40, 2)
insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (2, 2, 50, 2)
insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (3, 3, 60, 3)
insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (1, 1, 70, 3)
insert into @Answers (AnswerID, QuestionNumber, Answer, UserID) values (2, 2, 80, 3)

insert into @Users (UserID, FirstName, LastName) values (1, 'Tom', 'Smith')
insert into @Users (UserID, FirstName, LastName) values (2, 'Dick', 'Brown')
insert into @Users (UserID, FirstName, LastName) values (3, 'Harry', 'Robinson')

insert into @Questions (QuestionNumber, QuestionName) values (1, 'Question 1')
insert into @Questions (QuestionNumber, QuestionName) values (2, 'Question 2')
insert into @Questions (QuestionNumber, QuestionName) values (3, 'Question 3')

select 
    QuestionName, MAX(User1) as 'Tom Smith', MAX(User2) as 'Dick Brown', MAX(User3) as 'Harry Robinson'
from 
(
select 
    q.QuestionName,
    (case when a.UserID=1 then Answer else null end) as 'User1',
    (case when a.UserID=2 then Answer else null end) as 'User2',
    (case when a.UserID=3 then Answer else null end) as 'User3'
from @Answers a
join @Users u on u.UserID = a.UserID
join @Questions q on q.QuestionNumber = a.QuestionNumber
) as combined
group by QuestionName



QuestionName Tom Smith   Dick Brown  Harry Robinson
------------ ----------- ----------- --------------
Question 1   10          40          70
Question 2   20          50          80
Question 3   NULL        30          60

【讨论】:

  • 我认为这不适用于所有数据库。我们首先必须知道目标数据库是什么。
  • 跨选项卡查询是所有关系数据库上的一种成熟模式——它可以在自 1990 年代以来遵循 ISO 标准的所有 sql 变体中完成。 Joe Celko 1990 年代中期的书中有一个很好的交叉 rdbms 示例 - “Sql For Smarties”
  • 对于动态交叉表列,您需要 db 特定元素(如链接文章中的存储过程)或 Oracle 11g PIVOT 函数。
猜你喜欢
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多