Как условно разобрать значение по умолчанию в строке, если отсутствует или нет - PullRequest
1 голос
/ 26 марта 2019

Я хотел бы условно определить, есть ли у меня значение по умолчанию в строке или нет (нули в моем 3-м значении в строке отображения ниже).

У меня есть следующая строка:

'PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|0'

Выше представлены SourceColumn | TargetColumn | DefaultValue, разделенные точкой с запятой. Таким образом, в моей строке есть два разделителя - труба и точка с запятой.

Я разделяю исходные, целевые и стандартные столбцы, и это хорошо работает в моем коде ниже:

DECLARE @Mapping NVARCHAR(max) = 'PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|0'
DECLARE @SourceTableColumns VARCHAR(256)
DECLARE @TargetTableColumns VARCHAR(256)
DECLARE @DefaultTableColumn VARCHAR(256)

    SELECT   @SourceTableColumns = isnull(@SourceTableColumns + ',', '') + SourceTableColumn
            ,@TargetTableColumns = isnull(@TargetTableColumns + ',', '') + TargetTableColumn
            ,@DefaultTableColumn = isnull(@DefaultTableColumn + ',', '') + DefaultTableColumn
    FROM (
        SELECT   parsename(replace(value, '|', '.'), 3) AS SourceTableColumn
                ,parsename(replace(value, '|', '.'), 2) AS TargetTableColumn
                ,parsename(replace(value, '|', '.'), 1) AS DefaultTableColumn
        FROM (
            SELECT *
            FROM String_split(@Mapping,';')
            ) a
        WHERE value <> ' '
        ) a

print 'Mapping: ' + @Mapping
print 'Source: ' + @SourceTableColumns
print 'Target: ' + @TargetTableColumns
print 'Default: ' + @DefaultTableColumn

Вот мои результаты, когда мое 3-е значение для значений по умолчанию всегда заполняется (нули в моем 3-м значении в строке отображения):

PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|0
Source: PriceSrc,CurrencySrc,ProductSrc
Target: PriceTrg,CurrencyTrg,ProductTrg
Default: 0,0,0

Однако, когда у меня даже есть одно пропущенное значение по умолчанию, например ниже (обратите внимание, что я исключил один из нулей в конце моей строки) ...

'PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|'

Вся моя логика ломается, и она исключает все мои переменные. Это дает мне следующий результат (только мое отображение):

Mapping: PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|

Обратите внимание, что функция третьего параметра значения по умолчанию заключается в том, чтобы служить в качестве значения переопределения, чтобы пользователи могли вводить любое строковое или числовое значение, если они захотят. Я не хочу всегда принудительно устанавливать значение по умолчанию, если оно равно NULL, поскольку это не всегда требуется.

Как сделать условие по умолчанию (т.е. DefaultTableColumn) в строке сопоставления условным? Как уже упоминалось, у меня не всегда может быть значение по умолчанию, но я все же хотел бы сохранить мои переменные @SourceTableColumns и @TargetTableColumns нетронутыми.


Модифицированная логика, предложенная Зохаром Пеледом:

SELECT   @SourceTableColumns = isnull(@SourceTableColumns + ',', '') + SourceTableColumn
        ,@TargetTableColumns = isnull(@TargetTableColumns + ',', '') + TargetTableColumn
        ,@DefaultTableColumn = isnull(@DefaultTableColumn + ',', '') + DefaultTableColumn
FROM (

SELECT  
        JSON_VALUE(JsonMapping, '$.V[0]') As SourceTableColumn,
        JSON_VALUE(JsonMapping, '$.V[1]') As TargetTableColumn,
        NULLIF(JSON_VALUE(JsonMapping, '$.V[2]'), '') As DefaultTableColumn
    FROM String_split(@Mapping, ';')
    CROSS APPLY
    (
        SELECT '{"V":["' + REPLACE([value], '|', '", "') +'"]}' As JsonMapping
    ) JsonData

    ) a

print 'Mapping: ' + @Mapping
print 'Source: ' + @SourceTableColumns
print 'Target: ' + @TargetTableColumns
print 'Default: ' + @DefaultTableColumn

Вот что я получаю в результате:

Mapping: PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|
Source: PriceSrc,CurrencySrc,ProductSrc
Target: PriceTrg,CurrencyTrg,ProductTrg

Я не получаю правильные результаты, так как я получаю все NULL для моего DefaultTableColumn.

Ожидаемое значение для @DefaultTableColumn будет 0,0,

С уважением, Шон

1 Ответ

2 голосов
/ 26 марта 2019

Во-первых, начиная с версии 2016 года, SQL Server имеет встроенную функцию string_split, которая превосходит любую пользовательскую функцию.

Во-вторых, явероятно, будет использовать replace для создания массива json из строки, а затем json_value для получения значений:

DECLARE @Mapping NVARCHAR(max) = 'PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|'


SELECT  JSON_VALUE(JsonMapping, '$.V[0]') As SourceColumn,
        JSON_VALUE(JsonMapping, '$.V[1]') As TargetColumn,
        -- json_value returns an empty string if no value found, nullif converts it to a null
        NULLIF(JSON_VALUE(JsonMapping, '$.V[2]'), '') As DefaultValue
FROM string_split(@Mapping, ';')
CROSS APPLY
(
    SELECT '{"V":["' + REPLACE([value], '|', '", "') +'"]}' As JsonMapping
) As JsonData

Результаты: (Примечаниечто последнее значение по умолчанию отсутствует)

SourceColumn    TargetColumn    DefaultValue
PriceSrc        PriceTrg        0
CurrencySrc     CurrencyTrg     0
ProductSrc      ProductTrg      NULL

Обновление
Чтобы получить результаты в переменные, вы можете использовать другую встроенную функцию (начиная с версии 2017 года) с именем string_agg:

DECLARE @Mapping NVARCHAR(max) = 'PriceSrc|PriceTrg|0;CurrencySrc|CurrencyTrg|0;ProductSrc|ProductTrg|',
        @SourceTableColumns NVARCHAR(max),
        @TargetTableColumns NVARCHAR(max),
        @DefaultTableColumn NVARCHAR(max)

SELECT   @SourceTableColumns = STRING_AGG(JSON_VALUE(JsonMapping, '$.V[0]'), ',')
        ,@TargetTableColumns = STRING_AGG(JSON_VALUE(JsonMapping, '$.V[1]'), ',')
        ,@DefaultTableColumn = STRING_AGG(NULLIF(JSON_VALUE(JsonMapping, '$.V[2]'), ''), ',')
FROM String_split(@Mapping, ';')
CROSS APPLY
(
    SELECT '{"V":["' + REPLACE([value], '|', '", "') +'"]}' As JsonMapping
) As JsonData

print 'Mapping: ' + @Mapping
print 'Source: ' + @SourceTableColumns
print 'Target: ' + @TargetTableColumns
print 'Default: ' + @DefaultTableColumn

Вы можете увидеть живое демо на db <> fiddle

...