SQL查询转表

时间:2013-03-22 11:37:24

标签: sql sql-server pivot

我有一个SQL查询,它从几个表中选择数据并进行一些计算。它产生的结果如下:

year    month   avg region
2011    1       123 UK
2012    1       0   UK
2013    1       0   UK
2011    2       400 UK
2012    2       200 UK
2013    2       0   UK

但我希望结果看起来像这样:

month   year1   year2   year3   region
1       123     0       0       UK
2       400     200     0       UK

这是我当前的查询:

SELECT TOP (100) PERCENT DATEPART(YEAR, dbo.Fixtures.Date) AS YEAR,
                         DATEPART(MONTH, dbo.Fixtures.Date) AS MONTH,
                         AVG(dbo.Fixtures.PCRate) AS AveragePCRate,
                         dbo.Region.GroupName AS Region
FROM dbo.Fixtures
INNER JOIN dbo.Vessel ON dbo.Fixtures.VesselId = dbo.Vessel.ID
INNER JOIN dbo.Region ON dbo.Fixtures.RegionId = dbo.Region.ID
WHERE (YEAR(dbo.Fixtures.Date) >= YEAR(DATEADD(YEAR, - 2, GETDATE())))
  AND (dbo.Vessel.TypeId = 1)
  AND (dbo.Vessel.Total_BHP >= 15000)
  AND (dbo.Vessel.Total_BHP < 20000)
GROUP BY dbo.Region.GroupName,
         DATEPART(YEAR, dbo.Fixtures.Date),
         DATEPART(MONTH, dbo.Fixtures.Date)
ORDER BY YEAR, MONTH

这可能吗? 附:只有过去3年的数据。

编辑: 这就是我的SQL查询的结果。

year        month   avgPC   Region
2011    1   7300    Norway
2011    1   6818    United Kingdom
2011    2   8500    Norway
2011    2   6235    United Kingdom
2011    3   15400   Norway
2011    3   0       South America
2011    3   12545   United Kingdom
2011    4   22887   Norway
2011    4   17231   United Kingdom
2011    5   24033   Norway
2011    5   9730    United Kingdom
2011    6   24249   Norway
2011    6   25000   United Kingdom
2011    7   23310   Norway
2011    7   25495   United Kingdom
2011    8   35890   Norway
2011    8   23000   United Kingdom
2011    9   28055   Norway
2011    9   33510   United Kingdom
2011    10  66437   Norway
2011    10  53713   United Kingdom
2011    11  26300   Norway
2011    11  14264   United Kingdom
2011    12  10800   Norway
2011    12  14553   United Kingdom

这是我在执行下面建议的解决查询时得到的结果:

m   year1   year2   year3   region
1   NULL    0   8500    Norway
2   NULL    NULL    NULL    Norway
3   NULL    NULL    NULL    Norway
4   NULL    NULL    NULL    Norway
5   NULL    NULL    NULL    Norway
6   NULL    NULL    NULL    Norway
7   NULL    NULL    NULL    Norway
8   NULL    NULL    NULL    Norway
9   NULL    NULL    NULL    Norway
10  NULL    NULL    NULL    Norway
11  NULL    NULL    NULL    Norway
12  NULL    NULL    NULL    Norway
3   NULL    NULL    NULL    South America
1   10250   6000    13000   United Kingdom
2   NULL    NULL    NULL    United Kingdom
3   NULL    NULL    NULL    United Kingdom
4   NULL    NULL    NULL    United Kingdom
5   NULL    NULL    NULL    United Kingdom
6   NULL    NULL    NULL    United Kingdom
7   NULL    NULL    NULL    United Kingdom
8   NULL    NULL    NULL    United Kingdom
9   NULL    NULL    NULL    United Kingdom
10  NULL    NULL    NULL    United Kingdom
11  NULL    NULL    NULL    United Kingdom
12  NULL    NULL    NULL    United Kingdom

2 个答案:

答案 0 :(得分:3)

您没有指定您正在使用的RDBMS,但是因为您正在使用TOP我猜测SQL Server。

在SQL Server中,您可以使用PIVOT函数转换数据:

SELECT month,
  [2011] as year1, 
  [2012] as year2, 
  [2013] as year3,
  region
FROM
(
  SELECT DATEPART(year, dbo.Fixtures.Date) AS Year, 
    DATEPART(Month, dbo.Fixtures.Date) AS Month, 
    dbo.Fixtures.PCRate, 
    dbo.Region.GroupName AS Region
  FROM  dbo.Fixtures 
  INNER JOIN dbo.Vessel 
    ON dbo.Fixtures.VesselId = dbo.Vessel.ID 
  INNER JOIN dbo.Region 
    ON dbo.Fixtures.RegionId = dbo.Region.ID
  WHERE (YEAR(dbo.Fixtures.Date) >= YEAR(DATEADD(year, - 2, GETDATE()))) 
    AND (dbo.Vessel.TypeId = 1) 
    AND (dbo.Vessel.Total_BHP >= 15000) 
    AND (dbo.Vessel.Total_BHP < 20000)
) src
pivot
(
  avg(PCRate)
  for year in ([2011], [2012], [2013])
) piv;

如果您不想对年份值进行硬编码,那么您可以使用类似于以下内容的内容:

SELECT month,
  year1, 
  year2, 
  year3,
  region
FROM
(
  SELECT 
    DATEPART(Month, dbo.Fixtures.Date) AS Month, 
    dbo.Fixtures.PCRate, 
    dbo.Region.GroupName AS Region,
    'year'+cast(row_number() over(partition by DATEPART(year, dbo.Fixtures.Date) 
                      order by DATEPART(year, dbo.Fixtures.Date)) as varchar(4)) year
  FROM  dbo.Fixtures 
  INNER JOIN dbo.Vessel 
    ON dbo.Fixtures.VesselId = dbo.Vessel.ID 
  INNER JOIN dbo.Region 
    ON dbo.Fixtures.RegionId = dbo.Region.ID
  WHERE (YEAR(dbo.Fixtures.Date) >= YEAR(DATEADD(year, - 2, GETDATE()))) 
    AND (dbo.Vessel.TypeId = 1) 
    AND (dbo.Vessel.Total_BHP >= 15000) 
    AND (dbo.Vessel.Total_BHP < 20000)
) src
pivot
(
  avg(PCRate)
  for year in (year1, year2, year3)
) piv;

编辑#1,很难从数据中判断出您发布的问题是什么,但是如果您无法从子查询中删除avg,那么您应该可以使用:

select month, [2011] as year1, [2012] as year2, [2013] as year3, region
from
(
  SELECT 
    DATEPART(YEAR, dbo.Fixtures.Date) AS YEAR,
    DATEPART(MONTH, dbo.Fixtures.Date) AS MONTH,
    AVG(dbo.Fixtures.PCRate) AS AveragePCRate,
    dbo.Region.GroupName AS Region
  FROM dbo.Fixtures
  INNER JOIN dbo.Vessel ON dbo.Fixtures.VesselId = dbo.Vessel.ID
  INNER JOIN dbo.Region ON dbo.Fixtures.RegionId = dbo.Region.ID
  WHERE (YEAR(dbo.Fixtures.Date) >= YEAR(DATEADD(YEAR, - 2, GETDATE())))
    AND (dbo.Vessel.TypeId = 1)
    AND (dbo.Vessel.Total_BHP >= 15000)
    AND (dbo.Vessel.Total_BHP < 20000)
  GROUP BY dbo.Region.GroupName,
           DATEPART(YEAR, dbo.Fixtures.Date),
           DATEPART(MONTH, dbo.Fixtures.Date)
) src
pivot
(
  max(AveragePCRate)
  for YEAR in ([2011], [2012], [2013])
) piv;

答案 1 :(得分:0)

尝试:

SELECT 
    Month
    ,MAX(CASE WHEN YEAR = 2011 THEN AveragePCRate ELSE Null END) AS Year1
    ,MAX(CASE WHEN YEAR = 2012 THEN AveragePCRate ELSE Null END) AS Year2
    ,MAX(CASE WHEN YEAR = 2013 THEN AveragePCRate ELSE Null END) AS Year3
    ,Region 
FROM
(
SELECT TOP (100) PERCENT DATEPART(YEAR, dbo.Fixtures.Date) AS YEAR,
                         DATEPART(MONTH, dbo.Fixtures.Date) AS MONTH,
                         AVG(dbo.Fixtures.PCRate) AS AveragePCRate,
                         dbo.Region.GroupName AS Region
FROM dbo.Fixtures
INNER JOIN dbo.Vessel ON dbo.Fixtures.VesselId = dbo.Vessel.ID
INNER JOIN dbo.Region ON dbo.Fixtures.RegionId = dbo.Region.ID
WHERE (YEAR(dbo.Fixtures.Date) >= YEAR(DATEADD(YEAR, - 2, GETDATE())))
  AND (dbo.Vessel.TypeId = 1)
  AND (dbo.Vessel.Total_BHP >= 15000)
  AND (dbo.Vessel.Total_BHP < 20000)
GROUP BY dbo.Region.GroupName,
         DATEPART(YEAR, dbo.Fixtures.Date),
         DATEPART(MONTH, dbo.Fixtures.Date)
) YourQuery
GROUP BY Month, Region

你可以让CASE语句使用当前日期进行测试(这样你一次只能有三年)。