Sql 以相同条件将列一分为二

Sql 以相同条件将列一分为二,sql,sql-server,substring,case,Sql,Sql Server,Substring,Case,我有一个名为X的列,在这个列中实际上存储了两个不同的信息。我知道如何分割它们,但我希望得到优化的东西,或者至少比我的查询更优化的东西 我有一个查询正在工作,但我希望它在处理大量数据时遇到困难 SELECT CASE SUBSTRING(X,1,3) WHEN 'AAA' THEN SUBSTRING(X,1,10) WHEN 'BBB' THEN SUBSTRING(X,1,20) END as firstinfo, CASE SUBSTRIN

我有一个名为X的列,在这个列中实际上存储了两个不同的信息。我知道如何分割它们,但我希望得到优化的东西,或者至少比我的查询更优化的东西

我有一个查询正在工作,但我希望它在处理大量数据时遇到困难

  SELECT
    CASE SUBSTRING(X,1,3)
      WHEN 'AAA' THEN SUBSTRING(X,1,10)
      WHEN 'BBB' THEN SUBSTRING(X,1,20)
    END as firstinfo,
    CASE SUBSTRING(X,1,3)
      WHEN 'AAA' THEN SUBSTRING(X,11,5)
      WHEN 'BBB' THEN SUBSTRING(X,21,5)
    END as secondinfo
  FROM Table
结果如下:

      firstinfo     |secondinfo
------------------------------
AAAfstdata          |smthg
BBBfirstdatalongerXX|else

是否可能只有一个条件,因为它是相同的
案例
条件显示两列时

您可以使用XML技巧来拆分它们

示例代码片段:

declare @Table table (X varchar(30));

insert into @Table (X) values
('AAAfstdatasmthg'),
('BBBfirstdatalongerXXelse'),
('ZZZ4567890123456789012345');

SELECT 
X2.value('/x[1]','varchar(30)') as firstinfo,
X2.value('/x[2]','varchar(30)') as secondinfo
FROM @Table
CROSS APPLY (
   SELECT 
   CAST('<x>'+STUFF(X, 
         case LEFT(X,3) 
         when 'AAA' then 11 
         when 'BBB' then 21 
         else LEN(X)-4 
         end
         ,0,'</x><x>')+'</x>' AS XML) AS X2
) as ca;
declare @Table table (X varchar(30));

insert into @Table (X) values
('AAAfstdatasmthg'),
('BBBfirstdatalongerXXelse'),
('ZZZ4567890123456789012345');

SELECT 
LEFT(X, COALESCE(pos, LEN(X)-5)) as firstinfo,
SUBSTRING(X, COALESCE(pos, LEN(X)-4), IIF(pos is not null, LEN(X)-pos+1, 5)) as secondinfo
FROM @Table t
LEFT JOIN (VALUES 
 ('AAA',11),
 ('BBB',21)
) v(code, pos) ON v.code = LEFT(X,3);
firstinfo               secondinfo
-------------           ----------
AAAfstdata              smthg
BBBfirstdatalongerXX    else
ZZZ45678901234567890    12345
结果:

declare @Table table (X varchar(30));

insert into @Table (X) values
('AAAfstdatasmthg'),
('BBBfirstdatalongerXXelse'),
('ZZZ4567890123456789012345');

SELECT 
X2.value('/x[1]','varchar(30)') as firstinfo,
X2.value('/x[2]','varchar(30)') as secondinfo
FROM @Table
CROSS APPLY (
   SELECT 
   CAST('<x>'+STUFF(X, 
         case LEFT(X,3) 
         when 'AAA' then 11 
         when 'BBB' then 21 
         else LEN(X)-4 
         end
         ,0,'</x><x>')+'</x>' AS XML) AS X2
) as ca;
declare @Table table (X varchar(30));

insert into @Table (X) values
('AAAfstdatasmthg'),
('BBBfirstdatalongerXXelse'),
('ZZZ4567890123456789012345');

SELECT 
LEFT(X, COALESCE(pos, LEN(X)-5)) as firstinfo,
SUBSTRING(X, COALESCE(pos, LEN(X)-4), IIF(pos is not null, LEN(X)-pos+1, 5)) as secondinfo
FROM @Table t
LEFT JOIN (VALUES 
 ('AAA',11),
 ('BBB',21)
) v(code, pos) ON v.code = LEFT(X,3);
firstinfo               secondinfo
-------------           ----------
AAAfstdata              smthg
BBBfirstdatalongerXX    else
ZZZ45678901234567890    12345
但对于这个例子,我想人们也可以关注第二个信息的长度:

SELECT 
LEFT(X,      case LEFT(X,3) when 'BBB' then LEN(X)-4 else LEN(X)-5 end) as firstinfo,
SUBSTRING(X, case LEFT(X,3) when 'BBB' then LEN(X)-3 else LEN(X)-4 end, 5) as secondinfo
FROM @Table;

您可以使用PIVOT将数据拆分为具有自己数据的列。以下是PIVOT的工作原理

SELECT * FROM table1
PIVOT(
       SUM(Sales) -- for strings use MAX(comment) for example.
       FOR X --this is the column which will be split into parts
       IN (First_Hand, Second_Hand) --this creates 2 columns
) AS PIVOT1
样品 来自名为Drinks的表的原始数据

在我使用PIVOT之后

从temp.dbo.drinks中选择* 支点( 金额(可用金额) 对于loc IN(加利福尼亚州、华盛顿州、佛罗里达州) )PIV1

然后结果


在两个不同的列中存储两项信息。这是最佳的方法。这里没有什么可以“优化”的;优化器将只对
子字符串(X,1,3)
求值一次。您可以考虑<代码>交叉应用< /C>和表值函数(和/或嵌入这些表达式作为计算列,这样您就不会在整个地方重复自己),但它可能是过度的。T-SQL中的字符串操作是笨拙和缓慢的,无论你如何分割它(双关语)好悲伤…如果你还在开发中,那么为什么你“必须处理我们目前拥有的东西”?修复数据结构后,您根本不需要问这个问题。请注意,任何形式为
where firstinfo='…'
的查询无论怎样都会很慢,因为您正在处理计算值。对于仅为显示目的提取数据而言,实际上没有什么需要优化的(或迫切需要优化的)。为了有效/高效地使用列作为单独的值,您至少需要索引视图,但最好只需要一个新表。要与现有代码保持兼容,您可以通过
CONCAT
ing进行
X
计算。(当然,索引的相同注意事项也适用于该列。)表达式看起来是确定性的,因此您可以简单地创建一个持久化的计算列并完成。您还可以在这些列上创建索引。如果对于“优化”,我们将“减少键入”,那么这可能被视为“更优化”。但至于表现,可能会很糟糕。(免责声明:未实际测试并与重复的
子字符串
s进行比较。)交叉应用程序不从表中选择,它只是使用记录的值。所以它应该是好的(可能)。这实际上更多的是一种只定义拆分位置一次的方法。