【问题标题】:Split column in two with same condition将列一分为二,条件相同
【发布时间】:2019-06-09 13:10:56
【问题描述】:

我有一个名为 X 的列,在此列中实际上存储了 2 个不同的信息。我知道如何拆分它们,但我想要一些优化的东西,或者至少比我的查询更优化。

我有一个查询正在运行,但我预计它在处理大量数据时会遇到困难。

  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

是否可能只有一个条件,因为它是相同的 casewhen 条件,显示 2 列

【问题讨论】:

  • 将两项信息存储在两个不同的列中。这是最佳方法。
  • 这里没有什么可以“优化”的;优化器将只评估一次SUBSTRING(X,1,3)。您可以考虑CROSS APPLY 和一个表值函数(和/或将这些表达式嵌入为计算列,这样您就不会到处重复自己),但这可能有点矫枉过正。 T-SQL 中的字符串操作很笨拙而且速度很慢,无论您​​如何切片(双关语)
  • 天哪......修复数据结构,你根本不需要这个问题。
  • 请注意,where firstinfo = '...' 形式的任何查询无论如何都会变慢,因为您正在处理计算值。仅仅为了显示目的而提取数据,实际上并没有什么可以优化的(或迫切需要)。为了有效/高效地将列用作单独的值,您至少需要索引视图,但更好的是只需要一个新表。为了保持与现有代码的兼容性,您可以使 XCONCATing 计算。 (当然,与索引相同的警告也适用于 that 列。)
  • 表达式看起来是确定性的,因此您可以简单地创建一个持久的计算列并完成。您还可以在此类列上创建索引。

标签: sql sql-server substring case


【解决方案1】:

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

示例 sn-p:

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;

或者使用值

示例 sn-p:

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;

【讨论】:

  • 如果对于“优化”我们阅读“更少打字”,那么这可能被认为是“更优化”。但至于性能,它可能会很臭。 (免责声明:未经实际测试并与重复的SUBSTRINGs 进行比较。)
  • CROSS APPLY 不会从表中选择,它只是使用记录的值。所以应该没问题(可能)。这确实更多的是一种只定义一次分割位置的方法。
【解决方案2】:

您可以使用 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 中选择 * 枢( 总和(avail_amt) 位置 印第安纳州(加利福尼亚州、哥伦比亚特区、佛罗里达州) ) PIV1

然后是结果

【讨论】:

    猜你喜欢
    • 2016-05-02
    • 2021-02-09
    • 2021-12-06
    • 1970-01-01
    • 2020-03-22
    • 2021-09-21
    • 1970-01-01
    • 2021-10-04
    • 1970-01-01
    相关资源
    最近更新 更多