Sql 以相同条件将列一分为二
我有一个名为X的列,在这个列中实际上存储了两个不同的信息。我知道如何分割它们,但我希望得到优化的东西,或者至少比我的查询更优化的东西 我有一个查询正在工作,但我希望它在处理大量数据时遇到困难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
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进行比较。)交叉应用程序不从表中选择,它只是使用记录的值。所以它应该是好的(可能)。这实际上更多的是一种只定义拆分位置一次的方法。