【问题标题】:How to transpose table SQL如何转置表 SQL
【发布时间】:2020-11-19 10:41:14
【问题描述】:

我正在尝试转置表,但我收到消息表明列类型与其他列冲突。 这是解决方案

WITH CTE_Unpivoted as
( select ID, Fields, QuantityValue
from Bikes2 as s
UNPIVOT
(QuantityValue for Fields IN(ProductName, Country, Quantity)
)AS u
)
SELECT Fields, [1],[2],[3],[4],[5],[6],[7]
from CTE_Unpivoted AS u
PIVOT
(SUM(QuantityValue) for ID IN ([1],[2],[3],[4],[5],[6],[7])) AS p

这是数据

CREATE TABLE Bikes2
 (ID INT PRIMARY KEY IDENTITY,
 ProductName VARCHAR(50),
 Country VARCHAR(50),
 Quantity INT);
INSERT INTO Bikes2 VALUES ('Road Bike', 'USA', 128)
INSERT INTO Bikes2 VALUES ('Road Bike', 'Italy', 64)
INSERT INTO Bikes2 VALUES ('Electric Bike', 'USA', 257)
INSERT INTO Bikes2 VALUES ('Electric Bike', 'Italy', 143)
INSERT INTO Bikes2 VALUES ('Children Bicecle', 'USA', 386)
INSERT INTO Bikes2 VALUES ('Children Bicecle', 'Italy', 52)
INSERT INTO Bikes2 VALUES ('Road Bike', 'USA', 35)
SELECT * FROM Bikes2

如何正确地做到这一点?有没有可能让它动态化? 结果是这样的

【问题讨论】:

  • 请向我们展示您想要的样本数据结果。
  • 显然,您应该将所有列转换为相同的数据类型。看起来像varchar,因为它是最通用的,其他列可以转换为它。或者你想如何将数字、日期和字符串存储在同一列中,而 SQL 结果列应该具有单一类型?
  • edit your question 包含此信息。
  • 为什么要在 SQL 中这样做?如果您想做像SUM 这样的“简单”事情(这正是您在PIVOT 中尝试做的事情),那么将诸如数量之类的事情更改为varchar 将会有问题。
  • 最后添加结果。当我尝试将 Quantity 转换为 varchar(50) 时,仍然出现错误

标签: sql sql-server pivot unpivot


【解决方案1】:

这种类型的重新格式化最好在应用层而不是在数据库中完成。以下是两个原因:

  • SQL 查询返回固定数量的列,并且您似乎希望表中每行一列。所以你必须硬连线这个号码。
  • 每一列都有一个类型,但您的数据有字符串和数字。

也就是说,这是可能的。这是一种方法:

with b as (
      select b.*, row_number() over (order by id) as seqnum
      from bikes2 b
     )
select 'productname',
       max(case when seqnum = 1 then productname end),
       max(case when seqnum = 2 then productname end),
       max(case when seqnum = 3 then productname end),
       max(case when seqnum = 4 then productname end),
       max(case when seqnum = 5 then productname end),
       max(case when seqnum = 6 then productname end),
       max(case when seqnum = 7 then productname end)
from b
union all
select 'country',
       max(case when seqnum = 1 then country end),
       max(case when seqnum = 2 then country end),
       max(case when seqnum = 3 then country end),
       max(case when seqnum = 4 then country end),
       max(case when seqnum = 5 then country end),
       max(case when seqnum = 6 then country end),
       max(case when seqnum = 7 then country end)
from b
union all
select 'quantity',
       max(case when seqnum = 1 then cast(quantity as varchar(255)) end),
       max(case when seqnum = 2 then cast(quantity as varchar(255)) end),
       max(case when seqnum = 3 then cast(quantity as varchar(255)) end),
       max(case when seqnum = 4 then cast(quantity as varchar(255)) end),
       max(case when seqnum = 5 then cast(quantity as varchar(255)) end),
       max(case when seqnum = 6 then cast(quantity as varchar(255)) end),
       max(case when seqnum = 7 then cast(quantity as varchar(255)) end)
from b;

这可以缩短为:

with b as (
      select b.*, row_number() over (order by id) as seqnum
      from bikes2 b
     )
select name,
       max(case when seqnum = 1 then val end),
       max(case when seqnum = 2 then val end),
       max(case when seqnum = 3 then val end),
       max(case when seqnum = 4 then val end),
       max(case when seqnum = 5 then val end),
       max(case when seqnum = 6 then val end),
       max(case when seqnum = 7 then val end)
from b cross apply
     (values (1, 'productname', productname),
             (2, 'country', country),
             (3, 'quantity', convert(varchar(255), quantity))
     ) v(ord, name, val)
group by name, ord
order by ord;

Here 是一个 dbfiddle。

【讨论】:

  • 所以基本上我不能通过 UNPIVOT/PIVOT 做到这一点?不同的数据类型可以防止这种情况发生吗?
  • @OlhaTkachuk 。 . .你可能可以。但是,这是定制的非标准语法。横向连接是标准语法并且更强大。因此,我建议使用显式横向连接。
  • 非常感谢,您的回答对我很有帮助
  • @OlhaTkachuk 。 . .如果可行,您可以接受答案。
猜你喜欢
  • 2016-10-24
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
  • 2013-02-24
  • 2020-10-08
  • 2022-12-10
相关资源
最近更新 更多