将具有相同ID的多个查询结果展平为单行?

时间:2016-03-30 16:47:51

标签: sql sql-server

我对SQL Server数据库中的某些内容感到好奇。我当前的查询提取有关我雇主的待售物品的数据。它找到的信息不到105,000项,这是正确的。但是,它返回超过155,000行,因为每个项目都有其他相关内容。现在,我通过Python中的循环运行该数据,通过检查循环正在处理的项是否与它刚刚处理的项相同来手动展平它。如果是,我会开始填写该项目的额外信息。理想情况下,SQL会返回已经放入一行的所有数据。

以下是设置概述。我为了简单起见省略了一些细节,因为我对一般理论感到好奇,而不是寻找我可以复制和粘贴的东西。

项目:包含项目ID,SKU,描述,供应商ID,重量和尺寸。

AttributeName:包含attr_id和attr_text。例如," color"," size",或" style"。

AttributeValue:包含attr_value_id和attr_text。例如," blue"或"小"。

AttributeAssign:包含item_id和attr_id。这将属性名称绑定到项目。

attributeValueAssign:包含item_id和attr_value_id,将属性值绑定到项目。

一系列附件以类似的方式设置,但带有附件和attachmentAssignment。附件只能有值,没有名称,所以不需要第三个表的额外复杂性,因为有属性。

供应商很简单:ID在项目表中使用。那就是:

select item_id, vendorName
from item
join vendor on vendor_id = item.vendorNumber

为您提供商品供应商的名称。

现在,有趣的部分:商品可能有也可能没有供应商,属性或附件。如果他们有后两者中的任何一个,那就无法知道他们有多少。我看过0个属性的项目和5个项目。附件更简单,因为每个项目只能有0或1,但是0的可能性仍然需要左外连接,所以我保证得到所有项目

这是我如何获得每个项目的多行。如果一个项目有三个attrigbutes,我只得到那个项目的四行或七行 - 我不确定它是每个名称/值是一行还是每个名称一行和每个值一行。无论哪种方式,这都是我想停下来的。我希望结果集中的每一行都包含所有属性,其中cap为7,null为任何缺失属性。就是这样:

ITEM_ID; ITEM_TITLE; item_sku; ... attribute1_name; attribute1_value; ATTRIBUTE2_NAME; attribute2_value; ... attribute7_value
1;一些随机项目; 123-45; ...颜色;蓝色;尺寸;介质; ...... null

现在,我为此获取了多行,例如(仅限ID和属性):

ID;属性1名称;属性1值;属性2名称;属性2值 1;颜色;蓝色;空值;空
1;颜色;蓝色;尺寸;介质

仅在第二行之后 - 所有信息按照唯一的商品ID汇总到一行。但是,目前我获得了多行,而Python必须将所有内容放在一起。我将此输出到电子表格中,因此有关商品的信息必须在该商品的行上。

如果太麻烦,我可以继续使用Python。但我想知道是否有办法做到这一点相对容易。我的脚本工作正常,执行时间不是问题。这更多是出于我自己的好奇心,而不是需要让任何事情发挥作用。关于如何 - 或者 - 这是可能的任何想法?

3 个答案:

答案 0 :(得分:2)

这是@ WCWedin的答案被修改为使用CTE。

WITH attrib_rn as
(
  select
    *, row_number() over(partition by item_id order by name, attribute_id) as row_number
  from attributes
)
select
  i.item_id,
  attr1.name as attribute1_name, attr1.value as attribute1_value,
  ...
  attr7.name as attribute7_name, attr7.value as attribute7_value
from items i
left join attrib_rn as attr1 ON attr1.item_id = i.item_id AND attr1.row_number = 1
left join attrib_rn as attr2 ON attr2.item_id = i.item_id AND attr2.row_number = 2
left join attrib_rn as attr3 ON attr3.item_id = i.item_id AND attr3.row_number = 3 
left join attrib_rn as attr4 ON attr4.item_id = i.item_id AND attr4.row_number = 4 
left join attrib_rn as attr5 ON attr5.item_id = i.item_id AND attr5.row_number = 5
left join attrib_rn as attr6 ON attr6.item_id = i.item_id AND attr6.row_number = 6
left join attrib_rn as attr7 ON attr7.item_id = i.item_id AND attr7.row_number = 7

答案 1 :(得分:1)

由于您只需要前7个属性,并且希望保留SQL查询中的所有逻辑,因此您可能正在考虑使用row_number。子查询将直接使用多个连接来完成工作,并且性能可能非常好,因为您只是加入了很多次。

select
  i.item_id,
  attr1.name as attribute1_name, attr1.value as attribute1_value,
  ...
  attr7.name as attribute7_name, attr7.value as attribute7_value
 from
  items i
  left join (
   select
      *, row_number() over(partition by item_id order by name, attribute_id) as row_number
     from
      attributes
   ) AS attr1 ON
   attr1.item_id = i.item_id
   AND attr1.row_number = 1
  ...
  left join (
   select
      *, row_number() over(partition by item_id order by name, attribute_id) as row_number
     from
      attributes
   ) AS attr7 ON
   attr7.item_id = i.item_id
   AND attr7.row_number = 7

答案 2 :(得分:0)

在SQL Server中,您可以使用包含'ROW_NUMBER()OVER'的子查询和一些CASE语句来解决这个问题,以便将前7个映射到列中。

有点棘手,但发布了返回大列表的完整查询,我将演示如何转置它。