在一个字段中报告多个值

时间:2016-02-25 23:18:08

标签: sql sql-server tsql sql-server-2012

我仍然在通过SQL跋涉(我觉得我将永远这样做!)

我正在尝试选择客户并展示他们前往的所有地方,这些地方可能超过1个,并按年列出列。

示例:

name    2014    2015      2016
bob     japan   korea     Mexico
        Tucson  England   
Dennis  Paris   England   China
        Texas   Canada
                Portland

我有:

SELECT name, 
     (SELECT location from places where year = '2014') AS '2014',
     (SELECT location from places where year = '2015') AS '2015',
     (SELECT location from places where year = '2014') AS '2016'
FROM customer
JOIN places 
on places.customerID = customer.customerID

抱歉伪代码;我现在正在旅行,但这已经困扰了我好几天。我觉得我的语法或方法是错误的......

非常感谢您的指导!

2 个答案:

答案 0 :(得分:0)

对于您编写的查询,您将遇到的问题是,如果您尝试将子查询用作表达式并且它返回多个记录,则SQL Server会抱怨。你会看到错误:

  

Msg 512,Level 16,State 1,Line 3 Subquery返回的值超过1   值。当子查询遵循=,!=,<,< =,>时,不允许这样做。 >,> =或当子查询用作表达式时。

在您的情况下,您在主select语句中使用子查询作为表达式。

您的输出通常是您希望在报告或应用程序层中完成的。这不是SQL擅长的,但可能。但是,有一点可以帮助生成一个字段,其中包含每个客户和每年的地点列表。 FOR XML子句善于将许多值压缩成列表或xml值。下面是一个创建逗号分隔的位置列表的示例,但您可以使用任何您喜欢的分隔符。

create table #customer (customerID int, name varchar(50))
create table #places (customerID int, year int, location varchar(50))

insert into #customer values (1, 'Bob')
insert into #customer values (2, 'Dennis')

insert into #places values (1, 2014, 'Japan')
insert into #places values (1, 2014, 'Tucon')
insert into #places values (2, 2014, 'Paris')
insert into #places values (2, 2014, 'Texas')
insert into #places values (1, 2015, 'Korea')
insert into #places values (1, 2015, 'England')
insert into #places values (2, 2015, 'England')
insert into #places values (2, 2015, 'Canada')
insert into #places values (2, 2015, 'Portland')
insert into #places values (1, 2016, 'Mexico')
insert into #places values (2, 2016, 'China')

select name, year,
    STUFF(
        (select ',' + location
        from #places 
        where #places.customerID = c.customerID
            and #places.year = p.year
        for XML Path('')
        ) 
        , 1, 1, ''
    ) AS locations
FROM #customer c
JOIN #places p
on p.customerID = c.customerID
group by c.name, c.customerID, p.year

然后,从这种数据格式中,您可以执行更类似于上述查询的操作,因为每个客户/年组合的位置只是一个值。您还可以使用SQL Server中的PIVOT功能,但您可以再次在报告层中执行此操作。例如,在Excel,Reporting Services等中使用透视功能

答案 1 :(得分:0)

使用ROW_NUMBER条件聚合来获得所需的结果:

;WITH Cte AS(
    SELECT c.name,p.*,
        rn = ROW_NUMBER() OVER(PARTITION BY c.customerID, p.year ORDER BY (SELECT NULL)) 
    FROM customer c
    INNER JOIN places p
        ON p.customerID = c.customerID
)
SELECT
    name    = CASE WHEN rn = 1 THEN name ELSE '' END,
    [2014]  = MAX(CASE WHEN c.year = '2014' THEN c.location ELSE '' END),
    [2015]  = MAX(CASE WHEN c.year = '2015' THEN c.location ELSE '' END),
    [2016]  = MAX(CASE WHEN c.year = '2016' THEN c.location ELSE '' END)
FROM Cte c
GROUP BY c.customerID, c.name, c.rn
ORDER BY c.name, c.customerID

TRY IT HERE