#sql #sql-server-2005 #select #case
#sql #sql-server-2005 #выберите #случай
Вопрос:
У меня есть столбец с именем @months, в котором хранятся месяцы в этом формате
@month = ’01-03-05-11-12′
Я хотел бы иметь запрос SELECT, который делит этот столбец на 12, делая его янв, февраль, март
Каждая моя запись имеет этот столбец впереди. Поэтому, если в записи есть @month = ’01-03′, она отображается в январе и марте. Можно ли сделать что-то подобное? Или что-нибудь близкое достаточно хорошо.
Я играл с оператором case, но не смог выдать результаты.
Код, если кто-нибудь хочет попробовать
create table recs(
id int not null primary key,
cust_name varchar(20),
callmonth varchar(36)
)
insert into recs values(1,'john','01-12')
insert into recs values(2,'Jessica','02-06')
insert into recs values(3,'Charlie','01-06')
insert into recs values(4,'steale','03-04')
insert into recs values(5,'Silica','01-02-03-04-05-06-07-08-09-10-11-12')
insert into recs values(6,'Luder','01-03-05-07-09-11-12')
insert into recs values(7,'Panther','01-06-12')
insert into recs values(8,'Dinky','03-04-15')
Комментарии:
1. Почему вы храните строки с разделителями в СУБД?
2. Плохой, плохой, плохой дизайн… Исправьте структуру таблицы вместо того, чтобы блуждать в темноте, пытаясь компенсировать это неправильное дизайнерское решение.
3. вы имеете в виду, что у меня должно быть 12 разных столбцов для каждого месяца?
4. Я объясню это немного подробнее: у меня 20 тысяч записей, каждая запись имеет запланированный месяц, который будет вызываться каждый год. Существует еще одна таблица, в которой хранятся записи выполненных вызовов. До сих пор логика работает для меня, чтобы отслеживать записи за каждый месяц текущего и прошлого года? Что я делаю не так и как это исправить. И этот запрос предназначен только для меня в целях тестирования, а не для реализации в реальном коде.
Ответ №1:
Возможно, мне неясно, что вы пытаетесь сделать, но вы можете разделить на 12 таблиц, используя следующее:
INSERT INTO January_table
SELECT *
FROM Original_table
WHERE month LIKE '%';
Сделайте это для каждого месяца, и это должно дать вам 12 таблиц, содержащих только значения, которые имеют этот месяц. Затем вы можете использовать представление для их объединения.
В качестве альтернативы, если вы ищете один запрос, вы можете использовать оператор case, подобный приведенному ниже:
INSERT INTO table
SELECT *
CASE
WHEN month LIKE '%' THEN 'True'
ELSE 'False'
END,
CASE
WHEN month LIKE '%' THEN 'True'
...
FROM Original_table;
В результате будет получена таблица со всеми полями из исходной таблицы, за которой следуют 12 «ежемесячных столбцов», каждый из которых имеет значение true или false, указывающее, присутствует ли этот месяц в этой строке.
Комментарии:
1. О, я хотел избежать 12 запросов, поэтому я опубликовал вопрос 🙂
2. Я не уверен, что это можно сделать только с помощью 1 запроса. Или, по крайней мере, по запросу, который не является чрезвычайно сложным. Я бы рекомендовал постоянно реструктурировать таблицы так, чтобы, как вы спрашиваете, было 12 столбцов, каждый с логическим значением. Для этого может потребоваться 12 запросов, но его 12 запросов вы выполните только один раз, тогда будущая работа будет намного проще.
Ответ №2:
я согласен с другими плакатами — вам следует изменить дизайн таблицы — в том виде, в каком она у вас есть, это очень плохая форма.
ваш оператор case обычно должен иметь такую форму:
case when instr(month,'01') > 0 then 'Jan'
Комментарии:
1.
instr
это не распознанная функция, я должен определить это сам? — Спасибо2. Эквивалентом Oracle в MS SQL
InStr
является CharIndex, кстати, он все еще не работал, но синтаксис приятный 🙂
Ответ №3:
вы должны разделить значения на ‘-‘ — и тогда у вас будет таблица
и затем вы должны посмотреть, находится ли это значение внутри этой таблицы ее строковое имя.
p.s.
У вас должна быть такая таблица :
01 - jan
02 - feb
...
...
допустим,
таблица месяцев (TBLMNTH) будет иметь ( id , name )
например :
1 | jan
2 | feb
select name from TBLMNTH where @month CHARINDEX(name , @month)>-1
Комментарии:
1. Но я говорю о запросе. Я делаю это для некоторого анализа. Остальная часть реализации выполнена. Мне нужен просто запрос.
Ответ №4:
Создайте функцию разделения и используйте ее с именем даты, как показано ниже, вы можете получить список месяцев в строковом формате..Я думаю, что это решит часть вашей проблемы.
select DATENAME(month, DATEADD(month, convert(int, val) , -1 )) AS month_str
from SPLIT('01-03-05-11-12', '-')
Результат будет (протестирован на сервере mssql; он работает)
January
March
May
November
December
UDF
CREATE FUNCTION SPLIT
(
@s nvarchar(max),
@splitChar nchar(1)
)
returns @t table (id int identity(1,1), val nvarchar(max))
as
begin
declare @i int, @j int
select @i = 0, @j = (len(@s) - len(replace(@s,@splitChar,'')))
;with cte
as
(
select
i = @i 1,
s = @s,
n = substring(@s, 0, charindex(@splitChar, @s)),
m = substring(@s, charindex(@splitChar, @s) 1, len(@s) - charindex(@splitChar, @s))
union all
select
i = cte.i 1,
s = cte.m,
n = substring(cte.m, 0, charindex(@splitChar, cte.m)),
m = substring(
cte.m,
charindex(@splitChar, cte.m) 1,
len(cte.m)-charindex(@splitChar, cte.m)
)
from cte
where i <= @j
)
insert into @t (val)
select pieces
from
(
select
ltrim(rtrim(case when i <= @j then n else m end)) pieces
from cte
) t
where
len(pieces) > 0
option (maxrecursion 0)
return
end
GO