我有一个这样的表(第一列包含id adn第二列是varchar,其中包含字符串(一些公式)) -
column_id column_formula
4686 4686 = 4684 - 4685
4687 4687 = ( 4681 / 1.205 / 4684 * 1000 )
4717 4717 = ( 4711 + 4712 + 4713 + 4714 + 4715 + 4716 )/6
4719 4719 = abs( 4716 - 4715 )
4787 4787 = max(max(max(max(max( 4780 , 4781 ), 4782 ), 4783 ), 4784 ), 4785 ) - min(min(min(min(min( 4780 , 4781 ), 4782 ), 4783 ), 4784 ), 4785 )
现在需要一些查询,它将提供如下输出 -
col1 col2
4686 4684
4686 4685
4687 4681
4687 4684
4717 4711
4717 4712
依此类推..(只有小于4位数的数字,如1.205左右......和1000)
很难在这个上使用patindex
any1可以给我一个解决方案吗
答案 0 :(得分:1)
您需要具有将逗号分隔的字符串拆分为单独行的函数。以下是Jeff Moden的DelimitedSplit8K函数:
CREATE FUNCTION [dbo].[DelimitedSplit8K](
@pString NVARCHAR(4000), @pDelimiter NCHAR(1)
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,E2(N) AS (SELECT 1 FROM E1 a, E1 b)
,E4(N) AS (SELECT 1 FROM E2 a, E2 b)
,cteTally(N) AS(
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
,cteStart(N1) AS(
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(
SELECT
s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
我的想法是REPLACE
首先是所有数学字符:+
,-
,*
,/
,(
,{{1带有逗号)
的{}},=
。这是必需的,因此我们可以稍后拆分操作数。接下来调用拆分器函数以逗号,
作为分隔符拆分行。完成拆分后,使用,
过滤所有数值。您希望将NOT LIKE '[^0-9]%' AND Item <> ''
的结果设为INSERT
。然后,来自Temp Table
的{{1}} SELECT
个Temp Table
子句:
WHERE
<强> RESULT 强>
;WITH cteSanitized AS(
SELECT
t.Column_Id,
Item =
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
SUBSTRING(t.Column_Formula, CHARINDEX('=', t.Column_Formula), LEN(t.Column_Formula) - CHARINDEX('=', t.Column_Formula) + 1)
,'+',','
), '-',','
), '/',','
), '*',','
), ')', ',)'
), '(',','
), '=',','
)
FROM Test t
)
,CteSplitted AS(
SELECT
s.Column_Id,
ItemNumber,
Item = LTRIM(RTRIM(x.Item))
FROM cteSanitized s
CROSS APPLY dbo.DelimitedSplit8K(s.Item, ',') x
)
SELECT
Column_Id,
ItemNumber,
Item = CONVERT(NUMERIC, ITEM)
INTO #TempTable
FROM CteSplitted
WHERE
Item NOT LIKE '[^0-9]%'
AND Item <> ''
SELECT DISTINCT
Col1 = Column_Id,
Col2 = Item
FROM #TempTable
WHERE Item > 1000
DROP TABLE #TempTable
答案 1 :(得分:1)
这是没有用户定义功能的解决方案。它应该快得多:
DECLARE @t TABLE ( ID INT, F NVARCHAR(MAX) )
INSERT INTO @t
VALUES ( 4686, '4686 = 4684 - 4685' ),
( 4687, '4687 = ( 4681 / 1.205 / 4684 * 1000 )' ),
( 4717, '4717 = ( 4711 + 4712 + 4713 + 4714 + 4715 + 4716 )/6' ),
( 4719, '4719 = abs( 4716 - 4715 ) ' ),
( 4787,
'4787 = max(max(max(max(max( 4780 , 4781 ), 4782 ), 4783 ), 4784 ), 4785 ) - min(min(min(min(min( 4780 , 4781 ), 4782 ), 4783 ), 4784 ), 4785 )' )
DECLARE @chars TABLE ( ID INT, c NVARCHAR(MAX) )
INSERT INTO @chars
VALUES ( 1, ' ' ),
( 2, '(' ),
( 3, ')' ),
( 4, '/' ),
( 5, '*' ),
( 6, '+' ),
( 7, '-' ),
( 8, 'max' ),
( 9, 'min' ),
( 10, 'abs' ),
( 11, '=' )
DECLARE @count INT
SELECT @count = COUNT(*) FROM @chars;
WITH recursion
AS ( SELECT t.ID ,
REPLACE(F, ' ', ',') + ',' AS F ,
1 AS CharID
FROM @t t
UNION ALL
SELECT t.ID ,
REPLACE(t.F, c.c, ',') AS F ,
t.CharID + 1 AS CharID
FROM recursion t
JOIN @chars c ON c.ID = t.CharID + 1
WHERE t.CharID < @count
),
commastrings
AS ( SELECT ID ,
STUFF(F, LEN(F), 1, '') AS F
FROM ( SELECT ID ,
REPLACE(REPLACE(REPLACE(F, ',', '{}'), '}{', ''), '{}', ',') AS F
FROM recursion
WHERE CharID = @count
) a
),
final ( ID, Number, rght, idx )
AS ( SELECT t.ID ,
LEFT(t.F, CHARINDEX(',', t.F) - 1) ,
SUBSTRING(t.F, CHARINDEX(',', t.F) + 1, LEN(t.F)) ,
0
FROM commastrings t
UNION ALL
SELECT c.id ,
CASE WHEN CHARINDEX(',', c.rght) = 0 THEN c.rght
ELSE LEFT(c.rght, CHARINDEX(',', c.rght) - 1)
END ,
CASE WHEN CHARINDEX(',', c.rght) > 0
THEN SUBSTRING(c.rght, CHARINDEX(',', c.rght) + 1, DATALENGTH(c.rght))
ELSE ''
END ,
idx + 1
FROM final c
WHERE LENGTH(c.rght) > 0
)
SELECT DISTINCT
ID ,
Number
FROM final
WHERE idx <> 0
AND CAST(Number AS DECIMAL(20, 10)) > 1000