【问题标题】:Divide one column into many - SQL将一列分成多列 - SQL
【发布时间】:2011-12-07 19:31:22
【问题描述】:

我有一个名为@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')

【问题讨论】:

  • 为什么要在 RDBMS 中存储分隔字符串?
  • Bad bad bad design... 修复你的表格结构,而不是在黑暗中四处乱窜,试图弥补这个错误的设计决定。
  • 你的意思是,我每个月应该有 12 个不同的列?
  • 我再解释一下:我有 20k 条记录,每条记录都有一个预定的月份,每年都会被调用。还有另一个表保存通话记录。到目前为止,逻辑对我来说可以追溯当前和过去一年中每个月的记录吗?我在做什么错并修复它。并且此查询仅供我自己用于测试目的,不会在实际代码中实现。

标签: sql sql-server-2005 select case


【解决方案1】:

我可能不清楚您要做什么,但您可以使用以下方法分为 12 个表:

INSERT INTO January_table
SELECT *
FROM Original_table
WHERE month LIKE '%01%';

每个月都这样做,它应该会为您提供 12 个表,其中仅包含该月的值。然后,您可以使用视图来组合它们。

或者,如果您正在寻找一个查询,您可以使用如下的 case 语句:

INSERT INTO table
SELECT *
    CASE
    WHEN month LIKE '%01%' THEN 'True'
    ELSE 'False'
    END,
    CASE
    WHEN month LIKE '%02%' THEN 'True'
    ...
FROM Original_table;

这将生成一个表,其中包含原始表中的所有字段,然后是 12 个“每月列”,每个列都有一个 true 或 false 表示该月是否存在于该行中。

【讨论】:

  • 哦,我想避免 12 个查询,这就是我发布问题的原因 :)
  • 我不确定是否可以仅通过 1 个查询来完成。或者,至少,查询不是非常复杂。我建议永久重组表格,以便有 12 列,每列都有一个布尔值。这样做可能需要 12 个查询,但它的 12 个查询只执行一次,以后的工作会容易得多。
【解决方案2】:

创建 SPLIT 函数并将其与 DATENAME 一起使用,如下所示,您可以获得字符串格式的月份列表。我认为这将解决您的部分问题。

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

【讨论】:

    【解决方案3】:

    你应该用'-'分割这些值 - 然后你就会有一个表格

    然后您应该查看该值是否在此表中 + 它的字符串名称。

    附言

    你必须有一张这样的桌子:

    01 - jan
    02 - feb
    ...
    ...
    

    让我们说: 表月份(TBLMNTH)将有( id , name )

    例如:

    1 |   jan  
    2 |   feb
    select name from  TBLMNTH where @month CHARINDEX(name , @month)>-1
    

    【讨论】:

    • 但我说的是一个查询。我这样做是为了进行一些分析。其余的实现已经完成。我只需要查询。
    【解决方案4】:

    我同意其他海报 - 你应该改变你的桌子设计 - 因为你有它是非常糟糕的形式。

    您的案例陈述通常应采用以下形式:

    case when instr(month,'01') > 0 then 'Jan'
    

    【讨论】:

    • instr 不是公认的功能,我必须自己定义吗? - 谢谢
    • MS SQL 相当于 Oracle InStr 是 CharIndex 顺便说一句,虽然仍然不起作用,但语法很好:)
    猜你喜欢
    • 2014-07-24
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    • 2020-02-10
    • 2015-09-08
    相关资源
    最近更新 更多