我仍然在通过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
抱歉伪代码;我现在正在旅行,但这已经困扰了我好几天。我觉得我的语法或方法是错误的......
非常感谢您的指导!
答案 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