Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Ersetzen von Alphabeten durch Null in einer beliebigen Zeichenfolge in SQL

Dies erfordert eine Reihe von etwas fortgeschrittenen Techniken, die kombiniert werden, um dies zu tun. Das erste Problem ist, dass Sie Daten mit Trennzeichen haben. Dies verstößt gegen 1NF, wenn Sie mehrere Werte in eine einzelne Zelle packen. Das zweite Teil des Puzzles besteht darin, wie man diese Daten in eine dynamische Anzahl von Spalten PIVOTET. Die meisten Leute in SO ziehen es vor, einen dynamischen PIVOT zu verwenden. Ich bevorzuge stattdessen eine dynamische Kreuztabelle. Die Syntax finde ich weniger stumpfsinnig und sogar etwas performanter als eine dynamische Kreuztabelle.

Sie können hier über den Splitter lesen, den ich normalerweise verwende. http://www.sqlservercentral.com/articles/Tally+Table/72993/ Der Hauptvorteil dieses Splitters gegenüber den meisten anderen ist, dass er die Zeilennummer des Elements innerhalb der Werteliste zurückgibt. Dies ist unglaublich nützlich für diese Art von Situation. Wenn Sie wirklich in die Splitterwelt eintauchen möchten, finden Sie hier einige andere hervorragende Optionen. http://sqlperformance.com/2012/07/t-sql -Abfragen/Split-Strings

Hier können Sie mehr über dynamische Kreuztabellen lesen. http://www.sqlservercentral.com/articles/Crosstab/65048/

Ich verstehe nicht wirklich, was die Tabelle #STATICFILTER damit zu tun hat, also habe ich sie einfach ignoriert.

Stellen Sie sicher, dass Sie diesen Code verstehen, bevor Sie ihn implementieren. Die Artikel, auf die verwiesen wird, gehen sehr detailliert auf diese Techniken ein.

if OBJECT_ID('tempdb..#MathTemp1') is not null
    drop table #MathTemp1

CREATE TABLE #MathTemp1
(
    IDNUM INTEGER IDENTITY(1,1),
    YEARMONTH VARCHAR(256),
    OutputFormula VARCHAR(256),
    Timedimensiondate Date
)

INSERT INTO #MathTemp1 (YEARMONTH,OUTPUTFORMULA,Timedimensiondate)
VALUES ('CV(N2)  1989: 1','2641.000 + Import - Consumption customs value(1540) + Import - Consumption customs value(1541)','1989-01-01')
,('CV(N2)  1989: 10','54407.000 + Import - Consumption customs value(1540) + 63906.000','1989-10-01')
,('CV(N2)  1990: 11','Import - Consumption customs value(2266) + Import - Consumption customs value(1540) + 53088.000','1990-11-01')
,('CV(N2)  1994: 5','32852.000 + Import - Consumption customs value(1540) + Import - Consumption customs value(1541)','1994-05-01')

declare @StaticPortion nvarchar(2000) = 
    'with OrderedResults as
    (   
        select mt.IDNUM
            , mt.OutputFormula
            , mt.Timedimensiondate
            , mt.YEARMONTH
            , x.ItemNumber
            , LTRIM(RTRIM(x.Item)) as Item
        from #MathTemp1 mt
        cross apply dbo.DelimitedSplit8K(mt.OutputFormula, ''+'') x
    )
    Select IDNUM';

declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by IDNUM order by IDNUM';  

with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS 
(
    SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)

select @DynamicPortion = @DynamicPortion + 
    ', MAX(Case when ItemNumber = ' + CAST(N as varchar(6)) + 'then case when ISNUMERIC(Item) = 1 then convert(numeric(9,3), ltrim(rtrim(Item))) else 0 end end) as Value' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <= 
(
    select MAX(LEN(OutputFormula) - LEN(replace(OutputFormula, '+', ''))) + 1
    from #MathTemp1
)


declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;

--select @SqlToExecute
exec sp_executesql @SqlToExecute