SQL Server, T-SQL: странное поведение в «инструкции INSERT INTO с несколькими значениями» + столбец типа sql_variant

Написав сценарий для экспериментов с sql_variant типом данных и SQL_VARIANT_PROPERTY функцией (для восстановления информации о данных из sql_variant столбца) на SQL Server, я случайно обнаружил то, что я считаю неожиданным поведением оператора с несколькими значениями INSERT INTO.

Следующий сценарий иллюстрирует поведение:

BEGIN
    DECLARE @TblVariant AS TABLE (
         rowid int identity
        ,VariantValue sql_variant
        ,AsStringColumn varchar(max)
        ,AsStringTypeInfo varchar(max)
        ,AsStringValue varchar(max)
        ,Result varchar(max)
    )

    --Inserting multiple values with one INSERT INTO statement
    INSERT INTO @TblVariant (VariantValue)
    VALUES (convert(float        ,10.25))
          ,(convert(int          ,11.00))
          ,(convert(numeric(10,0),12.15))
          ,(convert(numeric(10,2),13.50))
          ,(convert(bigint       ,14.75))
          ,(null)

    UPDATE @TblVariant 
    SET AsStringColumn = convert(varchar(max),VariantValue)
          ,AsStringTypeInfo = 
                 'BaseType='  +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'BaseType')),'NULL')
               +';Precision=' +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'Precision')),'NULL')
               +';Scale='     +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'Scale')),'NULL')
               +';TotalBytes='+isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'TotalBytes')),'NULL')
               +';Collation=' +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'Collation')),'NULL')
               +';MaxLength=' +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'MaxLength')),'NULL')

    SELECT *
    FROM @TblVariant

    DELETE @TblVariant

    -- Multiple insert statements 
    INSERT INTO @TblVariant (VariantValue) VALUES (convert(float, 10.25))
    INSERT INTO @TblVariant (VariantValue) VALUES (convert(int, 11.00))
    INSERT INTO @TblVariant (VariantValue) VALUES (convert(numeric(10, 0), 12.15))
    INSERT INTO @TblVariant (VariantValue) VALUES (convert(numeric(10, 2), 13.50))
    INSERT INTO @TblVariant (VariantValue) VALUES (convert(bigint, 14.75))
    INSERT INTO @TblVariant (VariantValue) VALUES (NULL)

    UPDATE @TblVariant 
    SET AsStringColumn = convert(varchar(max),VariantValue)
          --Ojo a este comportamiento. Al 
          ,AsStringTypeInfo = 
                 'BaseType='  +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'BaseType')),'NULL')
               +';Precision=' +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'Precision')),'NULL')
               +';Scale='     +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'Scale')),'NULL')
               +';TotalBytes='+isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'TotalBytes')),'NULL')
               +';Collation=' +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'Collation')),'NULL')
               +';MaxLength=' +isnull(try_convert(varchar(max),SQL_VARIANT_PROPERTY(VariantValue,'MaxLength')),'NULL')

    SELECT *
    FROM @TblVariant
END

Сценарий выше использует табличную переменную @TblVariant со столбцом sql_variant с именем VariantValue для хранения некоторых данных, вставляет некоторые значения в @TblVariant, а затем использует SQL_VARIANT_PROPERTY для восстановления информации о типе данных из столбца VariantValue.

Первый сценарий вставляет несколько значений с помощью одного оператора INSERT INTO, после удаления данных из @TblVariant второй сценарий повторяет процесс с использованием нескольких операторов INSERT INTO для повторного заполнения @TblVariant теми же данными.

Результат выглядит следующим образом

Как мы видим, в обоих сценариях значения в VariantValue и AsStringColumn выглядят одинаковыми для всех строк, но вычисляемый столбец AsStringTypeInfo выглядит по-разному в каждом сценарии.

Для сценария с одним оператором INSERT INTO результаты почти для всех строк (за исключением строки с нулевым значением в столбце VariantValue) одинаковы; в то время как, с другой стороны, для сценария с несколькими операторами INSERT INTO значение, рассчитанное для AsStringTypeInfo, выглядит по-разному для каждой строки, предоставляя более точную информацию для значения, вставленного / сохраненного в столбце VariantValue, для каждой строки.

Мой вопрос: в чем разница между выполнением одного оператора INSERT INTO для вставки нескольких значений строки и выполнением нескольких операторов INSERT INTO для вставки одних и тех же значений, и почему эта разница влияет на поведение функции SQL_VARIANT_PROPERTY?

Values() — это конструктор табличных значений: learn.microsoft.com/en-us/sql/t-sql/queries/… . Каждый столбец values() (поскольку это конструктор таблицы) должен иметь один и тот же тип данных. Первый, множественный, оператор значений имеет несколько типов данных, тот, у которого наивысший приоритет, - это число с плавающей запятой, значения выводят число с плавающей запятой, которое преобразуется в вариант при вставке в таблицу. Короче говоря, values() выполняет «объединение всех» каждой строки (из плана выполнения, постоянного сканирования, <OutputList><ColumnReference Column = "Union1009">..

lptr 31.03.2023 19:36

Вы можете привести/преобразовать одно из значений в sql_variant, тогда вариант имеет наивысший приоритет. ), (преобразовать (числовой (10,0), 12,15))….

lptr 31.03.2023 19:46

Спасибо за ваш комментарий @lptr. Насколько я понимаю ваше объяснение и я прочитал из документации, которую вы публикуете, при вставке через оператор Table Value Constructor Values ​​() значения за пределами первой строки «приводятся» к типу с наивысшим приоритетом в этом случае ´ float», в результате чего столбец VariantValue для всех строк в @TblVariant сохраняется как sql_variant(float). Я думаю, что это ответ, вы можете обновить свой комментарий как ответ.

Mauricio Ortega 31.03.2023 22:05
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
3
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как ответил @lptr в комментариях:

Values() — это конструктор табличных значений. Каждый столбец values() (поскольку это конструктор таблицы) должен иметь один и тот же тип данных.

Первый оператор множественных значений имеет несколько типов данных, поэтому тот, у которого наивысший приоритет, — float. values выводит float, который преобразуется в sql_variant при вставке в таблицу. Короче говоря, values() выполняет union all каждой строки (из плана выполнения, constant scan, <OutputList><ColumnReference Column = "Union1009">

Вы можете привести/преобразовать одно из значений в sql_variant, тогда sql_variant имеет наивысший приоритет

INSERT INTO @TblVariant (VariantValue) VALUES
(convert(sql_variant, convert(float ,10.25))),
(convert(int,11.00)),
(convert(numeric(10,0),12.15))

Другие вопросы по теме