[英]Change table format to pivot
在这个问题的延续中
主要代码:
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
我在这种情况下尝试使用枢轴的所有尝试都没有成功。
更新
根据@Gordon Linoff 和@xXx 的建议尝试重做使用动态 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 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, ' + @names + ' FROM ( select id_object, value, name from op where seqnum=1 ) 作为 tbl pivot ( max(value) for name in (' + @names + ') ) piv'
execute(@SQL)
完毕。
您可以使用条件聚合:
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;
你会得到你想要的结果。
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
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
结果:
| 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) |
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.