【问题标题】:timestamp column in MySQL detected as nvarchar in SqlServer via linked serverMySQL 中的时间戳列通过链接服务器在 Sql Server 中检测为 nvarchar
【发布时间】:2022-01-16 10:49:37
【问题描述】:

我通过 SQL Server 执行查询以从 MySQL 数据库中检索数据,如下所示:

SELECT * FROM OPENQUERY(MyLinkedServerNameToMySQL, 
                        'SELECT actor_id, first_name, last_Name, last_update 
                         FROM sakila.actor')

其中last_update 列数据类型为timestamp。 通过Microsoft ADODataSet库执行查询并检索DataSet中的数据后,DataSetlast_update的数据类型为nvarchar,而我期望datetime。 谁能解释为什么会出现这个问题?

更新:

这是我的代码:

unit GetDataFormMySQLU;

interface

procedure GetDataFromMySQL;

implementation

uses DB, ADODB, Variants;

procedure DoSomthingForBoolean(AValue: Variant);
begin
end;

procedure DoSomthingForDateTime(AValue: Variant);
begin
end;

procedure DoSomthingForNumber(AValue: Variant);
begin
end;

procedure DoSomthingForString(AValue: Variant);
begin
end;

procedure GetDataFromMySQL;
var
  LADOConn: TADOConnection;
  LDS: TADODataSet;
  i: Integer;
  LValue: Variant;
begin
  LADOConn := TADOConnection.Create(nil);
  try
    //:
    LDS := TADODataSet.Create(nil);
    try
      LDS.Connection := LADOConn;
      LDS.CommandText := 'SELECT * FROM ' +
                         'OPENQUERY(MyLinkedServerNameToMySQL, ' +
                            '''SELECT actor_id, first_name, last_Name, last_update ' +
                              'FROM sakila.actor'')';
      LDS.Open;
      while not LDS.Eof do
      begin
        for i := 0 to LDS.Fields.Count - 1 do
        begin
          LValue := LDS.Fields[i].Value;

          case LDS.Fields[i].DataType of
            ftBoolean: DoSomthingForBoolean(LValue);

            ftDate,
            ftTime,
            ftDateTime: DoSomthingForDateTime(LValue); (*this branch will not be invoked for
                                                         timestamp or datetime column of MySQL*)
            ftSmallint,
            ftInteger,
            ftWord,
            ftFloat,
            ftCurrency,
            ftBCD,
            ftAutoInc,
            ftLongWord,
            ftShortint,
            ftExtended,
            ftSingle: DoSomthingForNumber(LValue);

            else DoSomthingForString(LValue); (*actually timestamp and datetime data type of MySQL
                                                will be detected as ftWideString(nvarchar) and this
                                                branch will be invoked*)
          end;
        end;
        LDS.Next;
      end;
    finally
      LDS.Free;
    end;
  finally
    LADOConn.Free;
  end;
end;

end.

【问题讨论】:

  • 可能是因为TIMESTAMP Transact-SQL timestamp data type is different from the timestamp data type defined in the ISO standard. It has nothing to do with date and time. Timestamp is a synonym for rowversion.
  • 您可以尝试使用测试表执行相同的查询,但将timestamp 更改为datetime 并检查它是否产生相同的错误?
  • 如何得出这个专栏是nvarchar的结论?
  • @Luuk 在我的代码中,我检查了每一列的数据类型
  • 顺便说一句:linked_server 周围不应有引号,请参阅OPENQUERY中的示例

标签: mysql sql sql-server delphi linked-server


【解决方案1】:

在 MySQL 中使用这个:

create table timestamps(t timestamp primary key);
insert into timestamps select current_timestamp;
insert into timestamps select current_timestamp;
insert into timestamps select current_timestamp;
insert into timestamps select current_timestamp;
insert into timestamps select current_timestamp;

您可以使用以下方法从链接服务器获取数据:

SELECT *
FROM OPENQUERY(MYLINKEDSERVERNAMETOMYSQL,'SELECT t  FROM test.timestamps');

但也使用:

SELECT t FROM  MYLINKEDSERVERNAMETOMYSQL.test..timestamps;

以上两条语句产生如下结果:

t
---------------------------
2022-01-16 14:43:42.0000000
2022-01-16 14:43:43.0000000
2022-01-16 14:43:44.0000000
2022-01-16 14:43:45.0000000
2022-01-16 14:43:46.0000000

使用TYPE_NAME() 会产生错误:

SELECT t, TYPE_NAME(t) FROM  MYLINKEDSERVERNAMETOMYSQL.test..timestamps;

错误:

Msg 206, Level 16, State 2, Line 18
Operand type clash: datetime2 is incompatible with int

还有:

SELECT t, SUBSTRING(t,1,7) FROM  MYLINKEDSERVERNAMETOMYSQL.test..timestamps;

生产:

Msg 8116, Level 16, State 1, Line 25
Argument data type datetime2 is invalid for argument 1 of substring function.

结论:MySQL中的timestamp转换为MS-SQL中的datetime2

编辑:Charlieface 指出我使用 SQL_VARIANT_PROPERTY,这样做时:

SELECT last_update, SQL_VARIANT_PROPERTY(CAST(last_update AS sql_variant), 'BaseType')
FROM OPENQUERY(MyLinkedServerNameToMySQL, 
                        'SELECT actor_id, first_name, last_Name, last_update 
                         FROM sakila.actor');

回复是:

last_update                 
--------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2006-02-15 04:34:33.0000000 datetime2
2006-02-15 04:34:33.0000000 datetime2
2006-02-15 04:34:33.0000000 datetime2
2006-02-15 04:34:33.0000000 datetime2
2006-02-15 04:34:33.0000000 datetime2
... 

注意:以上是 MySQL 8.0.27 和 MS-SQL 15.0

【讨论】:

  • 谢谢你。您在 SSMS 中发现 MySQL 的 timestamp 被识别为 MS-SQL 的 datetime2。但 Microsoft ADO 数据集检测为 nvarchar
猜你喜欢
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
  • 2015-02-08
  • 1970-01-01
  • 2021-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多