【问题标题】:How to build a SQL Server 2005 query that combines three tables' data into a single grid output?如何构建一个 SQL Server 2005 查询,将三个表的数据组合到一个网格输出中?
【发布时间】:2013-07-23 18:54:50
【问题描述】:

我有一个包含大约 30000 条记录的 Items 表、我的客户分组到的 Groupings 表、我的 Products 排序到的 Categories 表和 Product_Categories 表,它存储了哪些 Items 进入哪些 Groupings 的哪些类别(因为每个分组都有自己的印刷目录,其中项目根据分组分为不同的类别)。

+----------+   +---------------+   +---------------+   +-------------------+
| Items    |   | Groupings     |   | Categories    |   | Item_Categories   |
+----------+   +---------------+   +---------------+   +-------------------+
| Item_ID  |   | Grouping_ID   |   | Category_ID   |   | Item_ID           |
| Item_Name|   | Grouping_Name |   | Category_Name |   | Grouping_ID       |
+----------+   +---------------+   +---------------+   | Category_ID       |
                                                       +-------------------+

例如,我的产品“Red Paint”在“艺术家”分组(我将其缩写为“AR”)中的客户的“美术用品”类别中,但它出现在“油漆 - 丙烯酸”类别中我的客户在“画家”(PN) 分组中,而我的客户在“学校”分组中的“返校”类别中。

因此,关系存储在 Item_Categories 表中,如下所示(为了清楚起见,显示名称而不是 ID):

+------------+--------------+-----------------+
| Item_ID    | Grouping_ID  | Category_ID     |
+------------+--------------+-----------------+
| Red Paint  | Artists      | Art Supplies    |
| Red Paint  | Painters     | Paint - Acrylic |
| Red Paint  | Schools      | Back to School  |
+------------+--------------+-----------------+

现在我需要的是一个 SQL Server 2005 查询,它在标题行中提供项目和所有分组,以及网格格式的实际关系,如下所示:

+--------------+-----------------+-----------------+----------------+
| Item_Name    | Artists         | Painters        | Schools        |
+--------------+-----------------+-----------------+----------------+
| Red Paint    | Art Supplies    | Paint - Acrylic | Back to School |
| Blue Paint   | Art Supplies    | Paint - Acrylic | Back to School |
| 1" Brush     | Art Supplies    | Brushes - Small | Back to School |
+--------------+-----------------+-----------------+----------------+

我希望我的问题是有道理的。我的直觉告诉我,如果我使用“交叉表”类型的方法,这可以通过单个查询来实现,但是我需要的输出格式的(明显的)复杂性让我头晕目眩。

感谢您花时间阅读我的问题;希望大家多多指教。

【问题讨论】:

    标签: sql sql-server-2005 pivot crosstab cross-apply


    【解决方案1】:

    将数据上的行转换为列的过程类型称为PIVOT。有几种方法可以在 sql server 中透视数据。

    您可以将聚合函数与 CASE 表达式一起使用:

    select i.item_name,
      max(case when g.grouping_name = 'Artists' then c.category_name end) Artists,
      max(case when g.grouping_name = 'Painters' then c.category_name end) Painters,
      max(case when g.grouping_name = 'Schools' then c.category_name end) Schools
    from items i
    left join item_categories ic
      on i.item_id = ic.item_id
    left join groupings g
      on ic.grouping_id = g.grouping_id
    left join categories c
      on ic.category_id = c.category_id
    group by i.item_name;
    

    SQL Fiddle with Demo

    如果您知道值,则可以使用 PIVOT 对查询进行硬编码:

    select item_name,
     Artists, Painters, Schools 
    from
    (
      select i.item_name,
        g.grouping_name,
        c.category_name
      from items i
      left join item_categories ic
        on i.item_id = ic.item_id
      left join groupings g
        on ic.grouping_id = g.grouping_id
      left join categories c
        on ic.category_id = c.category_id
    ) d
    pivot
    (
      max(category_name)
      for grouping_name in (Artists, Painters, Schools)
    ) piv;
    

    SQL Fiddle with Demo

    但似乎您可能有未知数量的值要转换为列,如果是这种情况,那么您将需要使用动态 SQL 来获得解决方案:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Grouping_Name) 
                        from Groupings
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT item_name, ' + @cols + ' 
                 from 
                 (
                    select i.item_name,
                      g.grouping_name,
                      c.category_name
                    from items i
                    left join item_categories ic
                      on i.item_id = ic.item_id
                    left join groupings g
                      on ic.grouping_id = g.grouping_id
                    left join categories c
                      on ic.category_id = c.category_id
                ) x
                pivot 
                (
                    max(category_name)
                    for grouping_name in (' + @cols + ')
                ) p '
    
    execute(@query);
    

    SQL Fiddle with Demo。所有版本都会给出结果:

    |  ITEM_NAME |      ARTISTS |        PAINTERS |        SCHOOLS |
    ----------------------------------------------------------------
    |   1" Brush | Art Supplies |          (null) | Back to School |
    | Blue Paint | Art Supplies | Paint - Acrylic | Back to School |
    |  Red Paint | Art Supplies | Paint - Acrylic | Back to School |
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 2020-03-26
      • 2020-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多