#sql-server #sql-server-2012
#sql-сервер #sql-server-2012
Вопрос:
у меня здесь есть таблица, указывающая на СКРИПКУ
---- ------ ------ ----- -----
| id | year | sell | buy | own |
---- ------ ------ ----- -----
| 1 | 2016 | 9 | 2 | 10 |
| 1 | 2017 | 9 | | 10 |
| 1 | 2018 | | 2 | 10 |
| 2 | 2016 | 7 | 2 | 11 |
| 2 | 2017 | 2 | | |
| 2 | 2018 | | | 18 |
---- ------ ------ ----- -----
create table test(id varchar(20), year varchar(20),
sell varchar(20), buy varchar(20),
own varchar(20));
insert into test values('1', '2016','9','2','10' )
insert into test values('1', '2017','9',NULL,'10' )
insert into test values('1', '2018',NULL,'2','10' )
insert into test values('2', '2016','7','2','11' )
insert into test values('2', '2017','2',NULL,'17' )
insert into test values('2', '2018','5','2','18' )
Я пытаюсь PIVOT
, но вместо того, чтобы агрегировать значения, я хотел сохранить некоторые буквы, если они не равны нулю (S-Sell, B-Buy, O-Own). Если есть значения для всех столбцов за определенный год, то мне нужен S_B_O
этот год. Если есть значения только для продажи и покупки, то S_B
и т.д., Поэтому ожидаемый результат
---- ------- ------ ------
| ID | 2016 | 2017 | 2018 |
---- ------- ------ ------
| 1 | S_B_O | S_O | B_O |
---- ------- ------ ------
| 2 | S_B_O | S | O |
---- ------- ------ ------
Самое близкое, что у меня есть, — это использование условного объединения ( MAX
и concat
) вместо PIVOT
, но это также дает null, если таковой имеется NULL
. Пожалуйста, предложите решение.
select ID,
MAX(CASE WHEN Year = '2016' AND sell is not null THEN 'S_' END
CASE WHEN Year = '2016' AND buy is not null THEN 'B_' END
CASE WHEN Year = '2016' AND own is not null THEN 'O' END)
AS [2016],
MAX(CASE WHEN Year = '2017' AND sell is not null THEN 'S_' END
CASE WHEN Year = '2017' AND buy is not null THEN 'B_' END
CASE WHEN Year = '2017' AND own is not null THEN 'O' END)
AS [2017]
/* ......for all year */
from test
group by id
Комментарии:
1.
{Some String} NULL = NULL
ИспользуйтеCONCAT
, который неявно изменяетNULL
значения на''
.2. Конечно, @Larnu, я попробую это. Есть ли лучший способ сделать это? потому что иногда я не могу предсказать количество лет. Я должен жестко кодировать ее для каждого года
3. Вам придется использовать динамический свод. Это совсем другой вопрос, и в Stack Overflow есть буквально 100 примеров.
4. Но как я могу использовать эти буквы (S_B_O) в динамическом своде? Не могли бы вы перенаправить меня на какую-нибудь справочную страницу? @Larnu
5. Google — Site:stackoverflow.com Динамический сводный SQL-сервер ; буквально тысячи результатов.
Ответ №1:
Вы можете использовать функцию CONCAT, которая будет автоматически обрабатывать нули.
select ID,
CONCAT(MAX(CASE WHEN Year = '2016' AND sell is not null THEN 'S_' END) ,
MAX(CASE WHEN Year = '2016' AND buy is not null THEN 'B_' END) ,
MAX(CASE WHEN Year = '2016' AND buy is not null THEN 'O' END))
AS [2016],
CONCAT(MAX(CASE WHEN Year = '2017' AND sell is not null THEN 'S_' END) ,
MAX(CASE WHEN Year = '2017' AND buy is not null THEN 'B_' END) ,
MAX(CASE WHEN Year = '2017' AND buy is not null THEN 'O' END))
AS [2017]
from test
group by id
---- ------- ------
| ID | 2016 | 2017 |
---- ------- ------
| 1 | S_B_O | S_ |
| 2 | S_B_O | S_ |
---- ------- ------
ОБНОВИТЕ динамический запрос. Как сказал @Larnu, вы должны были задать это как отдельный вопрос. Вы не должны изменять требование.
DECLARE @lst_Years NVARCHAR(MAX) , @query NVARCHAR(MAX)
SET @lst_Years = STUFF((SELECT distinct ',' QUOTENAME([Year])
FROM test
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET @query = 'SELECT * FROM
(
select ID, [Year],
CONCAT(MAX(CASE WHEN sell is not null THEN ''S_'' END) ,
MAX(CASE WHEN buy is not null THEN ''B_'' END) ,
MAX(CASE WHEN buy is not null THEN ''O'' END))
AS [Value]
from test
group by id, [year]) as t
pivot
(
max(value) FOR YEAR IN (' @lst_Years ')
) as pvt'
EXEC(@query)
---- ------- ------ -------
| ID | 2016 | 2017 | 2018 |
---- ------- ------ -------
| 1 | S_B_O | S_ | B_O |
| 2 | S_B_O | S_ | S_B_O |
---- ------- ------ -------
Комментарии:
1. Спасибо. Кажется, все в порядке. Могу ли я как-то сделать ее динамической? так что я не хочу жестко кодировать каждый год.
2. Это должен быть отдельный вопрос, @Avinash , однако быстрый поиск даст вам 100 примеров.
3. @Avinash, КАК упоминал Ларну, это должен быть отдельный вопрос. в любом случае, я добавил динамический запрос также к ответу.
4. @VenkataramanR. Не могли бы вы, пожалуйста, помочь мне удалить лишние
_
в конце,S_
S
если это возможно? Я перепробовал так много способов, и ничего не работает. Кажется, это легко в последней версии, но ничего не найти в2012
версии5. @Avinash, пожалуйста, задайте отдельный вопрос. ее изменение приведет к путанице для будущих читателей этого вопроса.