【问题标题】:Change table format to pivot将表格格式更改为透视
【发布时间】:2020-05-05 18:55:09
【问题描述】:

在此继续issue

主要代码:

CREATE TABLE params
(
    id_param smallint PRIMARY KEY,
    name varchar(50) NOT NULL
)

CREATE TABLE objects_params
(
    id_object int,
    id_param smallint NOT NULL,
    cdate smalldatetime,
    value int
)

INSERT INTO dbo.params (id_param, name)
VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), 
       (5, 'e'), (6, 'f'), (7, 'g')

INSERT INTO dbo.objects_params (id_object, id_param, cdate, value)
VALUES (1, 1, '20191206',NULL), (1, 2,'20191212', 100), (1, 1, '20191201', 110),
       (2, 4, '20191211',120), (2, 1,'20190101', 130), (2, 3, '20191212', 140),
       (2, 4, '20191111',150), (2, 3,'20190201', 160), (2, 3, '20190312', 170),
       (2, 3, '20191201', 175),(2, 3, '20191202', 180), (2, 3, '20191203', 185),
       (2, 3, '20191204', 190)

然后我需要获取最接近给定日期的值列表:

DECLARE @userdate DATETIME
SET @userdate='20191202'

DECLARE @names as VARCHAR(MAX)
SELECT @names =
COALESCE(@names + ', ','') + QUOTENAME(name)
FROM
   (SELECT distinct name
    FROM objects_params 
    JOIN params ON objects_params.id_param = params.id_param
   ) AS B;

With t_sql as ( 
    SELECT  id_object, objects_params.id_param, name, cdate, value  
    FROM objects_params 
    JOIN params ON objects_params.id_param = params.id_param)
    --Where value <> ''

SELECT id_object, id_param, name, cdate, value  
FROM 
    (
        SELECT RANK() OVER (PARTITION BY id_object, id_param ORDER BY abs(datediff(ss, @userdate,cdate)) ASC) AS DateRank, *
        FROM t_sql
        WHERE cdate < @userdate
    ) 
AS DetailsRanking
WHERE DetailsRanking.DateRank=1

得到一个这样的表:

id_object id_param   name      cdate      value
-----------------------------------------------
   1         1         a     2019-12-01    110
   2         1         a     2019-01-01    130
   2         3         c     2019-12-01    175
   2         4         d     2019-11-11    150

但是我怎样才能得到这种格式的结果:

    id_object     a         b       c      d      e      f      g   
    ---------------------------------------------------------------
       1         110      null    null   null   null   null   null
       2         130      null    175    150    null   null   null

我在这种情况下使用 pivot 的所有尝试都失败了。


更新

根据@Gordon Linoff 和@xXx 的建议,尝试重做代码以使用 Dinamic SQL,所以我们开始:

USE [DConturDb]
GO

DECLARE @userdate VARCHAR(MAX)
SET @userdate='20191202';

DECLARE @names as VARCHAR(MAX)
SELECT @names =
COALESCE(@names + ', ','') + QUOTENAME(name)
FROM
   (SELECT name
    FROM params 
   ) AS B;

DECLARE @SQL as VARCHAR(MAX)
SET @SQL = 

'WITH 操作为 ( 选择 op.id_object、op.id_param、名称、op.cdate、op.value、 ROW_NUMBER() OVER (PARTITION BY op.id_object, op.id_param ORDER BY op.cdate DESC) 作为 seqnum FROM objects_params 操作 JOIN 参数 p ON op.id_param = p.id_param

  WHERE op.cdate <='''+ @userdate +'''
 )

SELECT id_object, ' + @names + ' 从 ( 选择 id_object、值、名称 从操作 其中 seqnum=1 ) 作为 tbl 枢 ( (' + @names + ') 中的名称的最大值(值) ) piv'

execute(@SQL)

完成。

【问题讨论】:

  • 这能回答你的问题吗? how to make your data horizontal
  • 问题类似,但是,正如我在您的回答中所说,我想了解如何在此示例的上下文中使用它

标签: sql sql-server pivot


【解决方案1】:

您可以使用条件聚合:

WITH op as ( 
      SELECT op.id_object, op.id_param, name, op.cdate, op.value,
             ROW_NUMBER() OVER (PARTITION BY op.id_object, op.id_param ORDER BY op.cdate DESC) as seqnum
      FROM objects_params op JOIN
           params p
           ON op.id_param = p.id_param
      WHERE op.cdate < @userdate
     )
SELECT id_object,
       MAX(CASE WHEN id_param = 1 THEN value END) as value_1,  
       MAX(CASE WHEN id_param = 2 THEN value END) as value_2, 
       . . .  
FROM op
WHERE seqnum = 1
GROUP BY id_object;

【讨论】:

  • 效果很好,谢谢。但是是否可以不明确指出列的名称,而是确保它们是自动设置的?是否可以使用我的示例中指示的范围“@names”?
  • @heso 。 . .如果您希望名称不是常量,则需要使用动态 SQL。
【解决方案2】:

你会得到你想要的结果。

DECLARE @userdate DATETIME
   SET @userdate='20191202'
   select * from (
   select b.id_object,value,a.name from params a
   INNER JOIN objects_params b on a.id_param = b.id_param
   where cdate < @userdate--here is your parameters
   ) as t 
   pivot (sum(value) for name IN ([a],[b],[c],[d],[e],[f],[g]) ) as Pivot_tbl --pivot based on names 

【讨论】:

    【解决方案3】:

    SQL Fiddle - 只需将 getdate() 替换为您正在使用的变量即可:

    MS SQL Server 2017 架构设置

    CREATE TABLE Result (id_object int,id_param int,name varchar(255)
                        ,cdate date,  val int);
    INSERT INTO  Result(id_object,id_param,name,cdate,val)
                VALUES (1,1,'a','2019-12-01',110)
                ,(2,1,'a','2019-01-01',130)
                ,(2,3,'c','2019-12-01',175)
                ,(2,4,'d','2019-11-11',150)
    

    查询 1

    with CTE AS (select *,
    (CASE WHEN name='a' THEN val  END) AS a,
    (CASE WHEN name = 'b' THEN val END) AS b,
    (CASE WHEN name='c' THEN val END) AS c,
    (CASE WHEN name='d' THEN val END) AS d,
    (CASE WHEN name='e' THEN val END) AS e,
    (CASE WHEN name='f' THEN val END) AS f,
    (CASE WHEN name='g' THEN val END) AS g,             
    ROW_NUMBER() OVER (PARTITION BY id_param,id_object Order By cdate) as rn
    from Result
                 where cdate < getdate()
    group by id_object,id_param,name,cdate,val              )
    
    select c.id_object
    
    ,max(c.a) AS a
    ,max(c.b) AS b
    ,max(c.c) AS c
    ,max(c.d) AS d
    ,max(c.e) AS e
    ,max(c.f) AS f
    ,max(c.g) AS g
    
    from cte c
    where rn=1
    group by c.id_object
    

    Results

    | id_object |   a |      b |      c |      d |      e |      f |      g |
    |-----------|-----|--------|--------|--------|--------|--------|--------|
    |         1 | 110 | (null) | (null) | (null) | (null) | (null) | (null) |
    |         2 | 130 | (null) |    175 |    150 | (null) | (null) | (null) |
    

    【讨论】:

    • 谢谢,但我没有单独的“结果”表。试图结合您和我的代码(在查询字段中)mycode Bur 出现错误:“关键字“where”附近的语法不正确。”我也想了解是否可以不明确指出列名
    • @heso 请检查如何在 sql fiddle 中使用变量。另外,不明确指出列名是什么意思?
    • 我使用这个站点(sql fiddle)仅作为我的代码示例,因为我无法将它插入到 cmets 中。 “不明确指出列名”——我的意思是在这个例子中我们有名称“a-g”,但在另一个例子中,可能还有其他名称。那么是否可以不直接指定名称,例如,与它们形成一个单独的数组(如我的示例@names) - 并使用它。
    • @heso 请更新您的问题。 stackoverflow.com/questions/10404348/…
    猜你喜欢
    • 2022-07-04
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多