MS SQL 到 Oracle 链接服务器。列的元数据无效
MS SQL to Oracle linked server. Invalid metadata for column
我需要将数据从 MS SQL (AWS EC2) table 复制到 Oracle (AWS RDS) 实例。在几次失败的方法之后,我决定在 SQL 中创建一个连接到 Ora 数据库的链接服务器,并在触发事件时插入新数据。到目前为止,还不错。
现在我正尝试将数据从 [相同] SQL table 插入到单个 Oracle table,但收到以下错误
"The OLE DB provider "OraOLEDB.Oracle" 用于链接服务器 "desora12" 为列 "CREATE_DATE" 提供的元数据无效。不支持该数据类型。"
我试过从插入语句中取出 CREATE_DATE,但收到同样的错误。我还尝试在 select 语句中转换和转换 CreateDate。同样的错误。
Oracle 中的 CREATE_DATE 列类型是 TIMESTAMP(6)。
SQL 中对应的 CreateDate 列类型是可为空的 DateTime
table中有 31 列,这里是插入的缩略版。
INSERT INTO [desora12]..[DATAENTRY].[TBL_API_ITEM_TYPEID1_LBL_TEST]
([SITE_ID]
,[USER_ID]
,[CREATE_DATE]
,[TRANSFER_DATE]
,[TRANSFER_STATUS])
SELECT TOP 1 SiteID,
UserID,
CreateDate,
TransferDate,
TransferStatus
FROM API.ItemDataTypeID1Label
WHERE TransferDate is null
AND TransferStatus is null
AND ReturnStatus=200
有什么帮助吗?
我总是"pulls" 来传输数据,而不是像您那样"push"。拉动确保您在刷新开发或测试数据库时不会损害生产数据库。就日期而言,我在 Oracle 和 SQL Server 之间的日期类型上遇到了困难。我最终将我的 Oracle 日期转换为文本(记住我正在拉)并允许 SQL 服务器自动将文本转换为日期。您可以在下面我对 bindvar 的调用中看到这一点,我将 Oracle 日期转换为字符串。
如果您从 Oracle 中提取数据,请查看 DBMS_HS_PASSTHROUGH。它比通过数据库选择 link 快很多倍。我一次获取 200 万条记录,我的 运行 时间从 4 1/2 小时减少到不到 5 分钟。
PROCEDURE bindvar (
p_cursor IN INTEGER
, p_pos IN INTEGER
, p_value IN VARCHAR2
)
AS
l_routine CONSTANT oracleobj_t := 'bindvar';
BEGIN
DBMS_HS_PASSTHROUGH.bind_variable@intervaldata.world (p_cursor, p_pos, p_value);
EXCEPTION
WHEN OTHERS
THEN
make_log_error_entry (
p_routine => l_routine
, p_message => cealogging.activity_log_maintenance_pkg.labels (
'p_cursor'
, p_cursor
, 'p_pos'
, p_pos
, 'p_value'
, p_value
)
);
RAISE;
END;
-- ***********************************************************************
-- Fetch Interval Data
-- Purpose:
-- Retrieve interval data from SQL*Server
-- Arguments:
-- p_earliestintervaldate - earliest interval date from which data will be fetched
-- p_latestintervaldate - latest interval date from which data will be fetched
-- p_earliestlogtime - earliest log date for which data will be fetched
-- p_latestlogtime - latest log date for which data will be fetched
-- p_maxrecords - maximum records to fetch from SQL Server
-- ***********************************************************************
FUNCTION fetch_intervaldata (
p_earliestintervaldate IN DATE
, p_latestintervaldate IN DATE
, p_earliestlogdate IN DATE
, p_latestlogdate IN DATE
, p_meterno IN VARCHAR2 DEFAULT NULL
, p_maxrecords IN INTEGER DEFAULT NULL
)
RETURN PLS_INTEGER
AS
l_routine CONSTANT oracleobj_t := 'fetch_intervaldata';
l_format CONSTANT oracleobj_t := 'YYYYMMDD HH24:MI:SS';
l_cnt PLS_INTEGER;
l_cursor INTEGER;
l_earliestlogdate DATE := p_earliestlogdate;
l_numrows INTEGER;
l_row intervaldata_load%ROWTYPE;
l_ret PLS_INTEGER := 0;
l_sql VARCHAR2 (200)
:= ';select * from cea.fetchCisIntervalData( ?, ?, ?, ?, ?) where interval_read is not null';
l_latestlogtimearg DATE;
BEGIN
close_databaselink (p_link => 'INTERVALDATA.WORLD');
EXECUTE IMMEDIATE 'truncate table intervaldata_load';
-- set l_cnt = 1 to allow the first pass to run
-- thereafter it is the number or records returned by the pass that will
-- be tested for continuation
l_cnt := 1;
WHILE l_earliestlogdate <= p_latestlogdate
AND l_cnt > 0
AND (p_maxrecords IS NULL
OR l_ret < p_maxrecords)
LOOP
make_log_entry (
p_routine => l_routine
, p_message => 'processing starting for ' || TO_CHAR (l_earliestlogdate, c_intervaldateformat)
);
l_cursor := DBMS_HS_PASSTHROUGH.open_cursor@intervaldata.world;
DBMS_HS_PASSTHROUGH.parse@intervaldata.world (l_cursor, l_sql);
bindvar (p_cursor => l_cursor, p_pos => 1, p_value => TO_CHAR (l_earliestlogdate, l_format));
bindvar (
p_cursor => l_cursor
, p_pos => 2
, p_value => TO_CHAR (l_earliestlogdate + INTERVAL '6' HOUR - INTERVAL '1' SECOND, l_format)
);
bindvar (p_cursor => l_cursor, p_pos => 3, p_value => TO_CHAR (p_earliestintervaldate, l_format));
bindvar (p_cursor => l_cursor, p_pos => 4, p_value => TO_CHAR (p_latestintervaldate, l_format));
bindvar (p_cursor => l_cursor, p_pos => 5, p_value => p_meterno);
l_cnt := 0;
LOOP
l_numrows := DBMS_HS_PASSTHROUGH.fetch_row@intervaldata.world (l_cursor);
EXIT WHEN l_numrows = 0
OR (p_maxrecords IS NOT NULL
AND l_ret >= p_maxrecords);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 1, l_row.meterno);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 2, l_row.interval_start);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 3, l_row.endpointid);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 4, l_row.logtime);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 5, l_row.interval_read);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 6, l_row.buy_back);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 7, l_row.phase_a);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 8, l_row.phase_b);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 9, l_row.phase_b);
EXIT WHEN l_row.logtime > p_latestlogdate;
INSERT INTO intervaldata_load
VALUES l_row;
l_cnt := l_cnt + 1;
l_ret := l_ret + 1;
END LOOP;
DBMS_HS_PASSTHROUGH.close_cursor@intervaldata.world (l_cursor);
make_log_entry (
p_routine => l_routine
, p_message => LPAD (l_cnt, 10)
|| ' records retrieved for '
|| TO_CHAR (l_earliestlogdate, c_intervaldateformat)
|| ' to '
|| TO_CHAR (l_earliestlogdate + INTERVAL '6' HOUR, c_intervaldateformat)
);
l_earliestlogdate := l_earliestlogdate + INTERVAL '6' HOUR;
END LOOP;
RETURN l_ret;
EXCEPTION
WHEN OTHERS
THEN
make_log_error_entry (
p_routine => l_routine
, p_message => 'processing ' || TO_CHAR (l_earliestlogdate, l_format)
);
DBMS_HS_PASSTHROUGH.close_cursor@intervaldata.world (l_cursor);
RAISE;
END fetch_intervaldata;
我需要将数据从 MS SQL (AWS EC2) table 复制到 Oracle (AWS RDS) 实例。在几次失败的方法之后,我决定在 SQL 中创建一个连接到 Ora 数据库的链接服务器,并在触发事件时插入新数据。到目前为止,还不错。
现在我正尝试将数据从 [相同] SQL table 插入到单个 Oracle table,但收到以下错误
"The OLE DB provider "OraOLEDB.Oracle" 用于链接服务器 "desora12" 为列 "CREATE_DATE" 提供的元数据无效。不支持该数据类型。"
我试过从插入语句中取出 CREATE_DATE,但收到同样的错误。我还尝试在 select 语句中转换和转换 CreateDate。同样的错误。
Oracle 中的 CREATE_DATE 列类型是 TIMESTAMP(6)。 SQL 中对应的 CreateDate 列类型是可为空的 DateTime
table中有 31 列,这里是插入的缩略版。
INSERT INTO [desora12]..[DATAENTRY].[TBL_API_ITEM_TYPEID1_LBL_TEST]
([SITE_ID]
,[USER_ID]
,[CREATE_DATE]
,[TRANSFER_DATE]
,[TRANSFER_STATUS])
SELECT TOP 1 SiteID,
UserID,
CreateDate,
TransferDate,
TransferStatus
FROM API.ItemDataTypeID1Label
WHERE TransferDate is null
AND TransferStatus is null
AND ReturnStatus=200
有什么帮助吗?
我总是"pulls" 来传输数据,而不是像您那样"push"。拉动确保您在刷新开发或测试数据库时不会损害生产数据库。就日期而言,我在 Oracle 和 SQL Server 之间的日期类型上遇到了困难。我最终将我的 Oracle 日期转换为文本(记住我正在拉)并允许 SQL 服务器自动将文本转换为日期。您可以在下面我对 bindvar 的调用中看到这一点,我将 Oracle 日期转换为字符串。
如果您从 Oracle 中提取数据,请查看 DBMS_HS_PASSTHROUGH。它比通过数据库选择 link 快很多倍。我一次获取 200 万条记录,我的 运行 时间从 4 1/2 小时减少到不到 5 分钟。
PROCEDURE bindvar (
p_cursor IN INTEGER
, p_pos IN INTEGER
, p_value IN VARCHAR2
)
AS
l_routine CONSTANT oracleobj_t := 'bindvar';
BEGIN
DBMS_HS_PASSTHROUGH.bind_variable@intervaldata.world (p_cursor, p_pos, p_value);
EXCEPTION
WHEN OTHERS
THEN
make_log_error_entry (
p_routine => l_routine
, p_message => cealogging.activity_log_maintenance_pkg.labels (
'p_cursor'
, p_cursor
, 'p_pos'
, p_pos
, 'p_value'
, p_value
)
);
RAISE;
END;
-- ***********************************************************************
-- Fetch Interval Data
-- Purpose:
-- Retrieve interval data from SQL*Server
-- Arguments:
-- p_earliestintervaldate - earliest interval date from which data will be fetched
-- p_latestintervaldate - latest interval date from which data will be fetched
-- p_earliestlogtime - earliest log date for which data will be fetched
-- p_latestlogtime - latest log date for which data will be fetched
-- p_maxrecords - maximum records to fetch from SQL Server
-- ***********************************************************************
FUNCTION fetch_intervaldata (
p_earliestintervaldate IN DATE
, p_latestintervaldate IN DATE
, p_earliestlogdate IN DATE
, p_latestlogdate IN DATE
, p_meterno IN VARCHAR2 DEFAULT NULL
, p_maxrecords IN INTEGER DEFAULT NULL
)
RETURN PLS_INTEGER
AS
l_routine CONSTANT oracleobj_t := 'fetch_intervaldata';
l_format CONSTANT oracleobj_t := 'YYYYMMDD HH24:MI:SS';
l_cnt PLS_INTEGER;
l_cursor INTEGER;
l_earliestlogdate DATE := p_earliestlogdate;
l_numrows INTEGER;
l_row intervaldata_load%ROWTYPE;
l_ret PLS_INTEGER := 0;
l_sql VARCHAR2 (200)
:= ';select * from cea.fetchCisIntervalData( ?, ?, ?, ?, ?) where interval_read is not null';
l_latestlogtimearg DATE;
BEGIN
close_databaselink (p_link => 'INTERVALDATA.WORLD');
EXECUTE IMMEDIATE 'truncate table intervaldata_load';
-- set l_cnt = 1 to allow the first pass to run
-- thereafter it is the number or records returned by the pass that will
-- be tested for continuation
l_cnt := 1;
WHILE l_earliestlogdate <= p_latestlogdate
AND l_cnt > 0
AND (p_maxrecords IS NULL
OR l_ret < p_maxrecords)
LOOP
make_log_entry (
p_routine => l_routine
, p_message => 'processing starting for ' || TO_CHAR (l_earliestlogdate, c_intervaldateformat)
);
l_cursor := DBMS_HS_PASSTHROUGH.open_cursor@intervaldata.world;
DBMS_HS_PASSTHROUGH.parse@intervaldata.world (l_cursor, l_sql);
bindvar (p_cursor => l_cursor, p_pos => 1, p_value => TO_CHAR (l_earliestlogdate, l_format));
bindvar (
p_cursor => l_cursor
, p_pos => 2
, p_value => TO_CHAR (l_earliestlogdate + INTERVAL '6' HOUR - INTERVAL '1' SECOND, l_format)
);
bindvar (p_cursor => l_cursor, p_pos => 3, p_value => TO_CHAR (p_earliestintervaldate, l_format));
bindvar (p_cursor => l_cursor, p_pos => 4, p_value => TO_CHAR (p_latestintervaldate, l_format));
bindvar (p_cursor => l_cursor, p_pos => 5, p_value => p_meterno);
l_cnt := 0;
LOOP
l_numrows := DBMS_HS_PASSTHROUGH.fetch_row@intervaldata.world (l_cursor);
EXIT WHEN l_numrows = 0
OR (p_maxrecords IS NOT NULL
AND l_ret >= p_maxrecords);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 1, l_row.meterno);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 2, l_row.interval_start);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 3, l_row.endpointid);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 4, l_row.logtime);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 5, l_row.interval_read);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 6, l_row.buy_back);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 7, l_row.phase_a);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 8, l_row.phase_b);
DBMS_HS_PASSTHROUGH.get_value@intervaldata (l_cursor, 9, l_row.phase_b);
EXIT WHEN l_row.logtime > p_latestlogdate;
INSERT INTO intervaldata_load
VALUES l_row;
l_cnt := l_cnt + 1;
l_ret := l_ret + 1;
END LOOP;
DBMS_HS_PASSTHROUGH.close_cursor@intervaldata.world (l_cursor);
make_log_entry (
p_routine => l_routine
, p_message => LPAD (l_cnt, 10)
|| ' records retrieved for '
|| TO_CHAR (l_earliestlogdate, c_intervaldateformat)
|| ' to '
|| TO_CHAR (l_earliestlogdate + INTERVAL '6' HOUR, c_intervaldateformat)
);
l_earliestlogdate := l_earliestlogdate + INTERVAL '6' HOUR;
END LOOP;
RETURN l_ret;
EXCEPTION
WHEN OTHERS
THEN
make_log_error_entry (
p_routine => l_routine
, p_message => 'processing ' || TO_CHAR (l_earliestlogdate, l_format)
);
DBMS_HS_PASSTHROUGH.close_cursor@intervaldata.world (l_cursor);
RAISE;
END fetch_intervaldata;