character encoding for SQL Server to Oracle linked server - sql-server

This linked server worked fine before we upgraded from SQL Server 2005 to 2008R2, but now it throws this error when querying from certain tables (it still works for other tables):
"linked server "PROD" reported an error. The provider did not give any information about the error...Cannot fetch a row from OLE DB provider "OraOLEDB.Oracle" for linked server "PROD".
I can narrow the problem to one row and when I run this query for that row I get a different error:
select * from openquery( PROD, 'SELECT ID, NAME FROM ITEMS WHERE ID = 5437')
Error:
OLE DB provider "OraOLEDB.Oracle" for linked server "PROD" returned message "01".
OLE DB provider "OraOLEDB.Oracle" for linked server "PROD" returned message "ORA-29275: partial multibyte character".
And I can query the offending NAME column as a DUMP, like this:
select * from openquery( PROD, 'SELECT DUMP(NAME) FROM ITEMS WHERE ID = 5437')
Which returns:
Typ=1 Len=16: 77,73,88,84,69,67,79,32,68,69,32,84,73,68,65,193
then rebuild using SELECT CHAR(77) + CHAR(73) + ..., and I get "MIXTECO DE TIDAƁ". Bottom line, it seems, is that CHAR(193) in the Oracle data is causing my query to fail. But how to fix?
Oracle (https://forums.oracle.com/forums/thread.jspa?threadID=551784) provides this mysterious clue:
ORA-29275: partial multibyte character
Cause: The requested read operation could not complete because a partial multibyte character was found at the end of the input.
Action: Ensure that the complete multibyte character is sent from the remote server and retry the operation. Or read the partial multibyte character as RAW.
However, I don't know how to "Ensure..." and I don't know how to "read... as RAW".
SQL Server is a 64-bit version running on a 64-bit windows server 2008R2 system and has the 64-bit Oracle 11gR2 client installed.
column in SQL: NAME nvarchar(60) NULL
column in Oracle: NAME varchar2(60)
In SQL, sp_helpsort returns:
Latin1-General, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive for Unicode Data, SQL Server Sort Order 52 on Code Page 1252 for non-Unicode Data
In Oracle, the NLS_CHARACTERSET is: AL32UTF8
Any help re: why this is not working or how to get this working? Let me know if need further info.

The 193 stored in the Oracle database is not a valid character in the UTF-8 character set. UTF-8 encodes the first 128 characters (0-127) using a single byte but anything beyond 7-bit ASCII requires two or more bytes of storage. Whatever application inserted this data appears to be doing so incorrectly, most likely because it is misconfigured to bypass the character set conversion that is supposed to happen when data is transferred between the client and the database.
What language/ framework/ API is the application that inserted the data into the Oracle database using? What is the client NLS_LANG parameter?

Related

T-SQL Openquery - error due to space in the table name

I have the below query that is trying to pull data from Sage 50 pervasive 13 database into SQL server using a link server. I've been able to pull all data from all tables into SQL Server except for this one table because it has a space in the table name.
I've not been successful with anything I've changed it to. Can anyone help me get this query working?
select *
from openquery(ARKSAGE,'select * from NEPHROPATHOLOGYASSO1.Budget Details')
When I change the above query to this:
select *
from openquery(ARKSAGE,'select * from NEPHROPATHOLOGYASSO1.[Budget Details]')
I get this error message:
OLE DB provider "MSDASQL" for linked server "ARKSAGE" returned message "[PSQL][ODBC Client Interface][LNA][PSQL][SQL Engine]Syntax Error: select * from NEPHROPATHOLOGYASSO1.<< ??? >>[Budget Details]".
Msg 7321, Level 16, State 2, Line 61
An error occurred while preparing the query "select * from NEPHROPATHOLOGYASSO1.[Budget Details]" for execution against OLE DB provider "MSDASQL" for linked server "ARKSAGE".
The PSQL in the error message tells me the linked server is probably running Postgresql, rather than SQL Server. Postgresql marks object names with double quotes instead of brackets. Therefore you should try this:
select *
from openquery(ARKSAGE,'select * from NEPHROPATHOLOGYASSO1."Budget Details"')
Additionally, I'm not sure what the << ??? >> text is for, but it looks a little like it's complaining about an odd unicode character in there somewhere. So look out for invisible whitespace. Or maybe it's just part of how the error message is formatted in the context of a linked Postgresql server.

Insert on linked table (from MS Access to SQL Server) fails because of field length

I'm trying to do an append query from MS Access into SQL server. The SQL server column is varchar(max) which I thought meant it can accept more than 4000 characters
I get the following error when running this query from VBA in MS Access
Run Time Error 3155 ODBC - insert on a linked table
failed [Microsoft] [SQL Server Native Client 10.0] {SQL Server] The
size (7596) given to the parameter '#P6' exceeds the maximum allowed
(4000). (#2717)
adding my queries
this query is based on an linked outlook folder, Deleted Items
SELECT Trim(Mid([contents],InStr([contents],"Short Description: ")+19,(InStr([contents],"Requestor: ")-1)-(InStr([contents],"Short Description: ")+19)-3)) AS ShortDesc, Trim(Mid([contents],InStr([contents],"Requestor: ")+10,(InStr([contents],"Requestor EMail: ")-1)-(InStr([contents],"Requestor: ")+10)-3)) AS Requester, Trim(Mid(Mid([contents],InStr([contents],"Office Location: ")+3),InStr(Mid([contents],InStr([contents],"Office Location: ")),"Description:")+13,(InStr(Mid([contents],InStr([contents],"Office Location: ")),"Assigned Task: ")-1)-(InStr(Mid([contents],InStr([contents],"Office Location: ")),"Description:")+13)-3)) AS Description, Trim(Mid([contents],InStr([contents],"Request Item: ")+14,12)) AS TicketNoText, Val(Mid([contents],InStr([contents],"Request Item: ")+19,7)) AS TicketNo, Val(Mid([contents],InStr([contents],"Assigned Task: ")+19,7)) AS TaskNo, Mid([contents],InStr([contents],"Delivery Date: ")+15,10) AS DeliveryDate, Trim(Mid([contents],InStr([contents],"Requestor EMail: ")+17,(InStr([contents],"Office Location: ")-1)-(InStr([contents],"Requestor EMail: ")+17)-3)) AS RequesterEMail
FROM [Deleted Items]
WHERE ((([Deleted Items].From)="xxxxxxx#service-now.com") AND (([Deleted Items].Subject)="you just assigned a ticket to yourself"));
then, the append query is based on this one and a few other ones
INSERT INTO PROJECTS ( TaskNo, RequesterID, Description, TicketNo, ProjectFolderLink, SNLink, OpenedOn, DateDue )
SELECT QSNNew.taskno, cmbRequesters.RequesterID, "SHORT DESCRIPTION: " & [shortdesc] & Chr(13) & Chr(10) & Chr(13) & Chr(10) & "DESCRIPTION: " & [Description] AS Expr4, QSNNew.TicketNo, "#\\link to a network folder" & lpad([ticketno],"0",7) & "\#" AS Expr1, "#https://xxxx.service-now.com/nav_to.do?uri=sc_task.do?sysparm_query=number=TASK" & lpad([taskno],"0",7) & "#" AS Expr2, Now() AS Expr3, Mid([DeliveryDate],6,2) & "/" & Right([DeliveryDate],2) & "/" & Left([DeliveryDate],4) AS Expr5
FROM (QSNNew LEFT JOIN PROJECTS ON QSNNew.TicketNo = PROJECTS.TicketNo) LEFT JOIN cmbRequesters ON QSNNew.[Requester] = cmbRequesters.RequesterName
WHERE (((PROJECTS.TicketNo) Is Null));
in case anyone is wondering what I'm doing, I'm loading tickets from Service Now into an Access database and there's no other way of doing it, other than parsing notification emails i get from Service Now when a ticket is assigned to me.
So I'm parsing those emails and creating my own version with links to the ServiceNow page, network folders for the ticket, etc.
It's a matter of driver (SQL Native Client and ODBC Driver 17 are limited to 4000 chars). If you use SQL Server Driver (10.09.18362.01) limit is 64000 chars.
As yu2 suggested ADODB query would avoid that (ODBC Passthrough should do it too).
The parameter #P6 is produced by ODBC see Optimizing Microsoft Office Access Applications Linked to SQL Server Understanding Dynasets
This is answer for your question
3155 Insert into Linked Table error
On this link Microsoft recommends to use ADODB instead of ODBC if you can't decrease field size in application.
ODBC protocol is generally for big data -- sql server -- which uses "Fire Hose" bandwith. Access uses (my term) garden hose bandwith (with all due respect for mini RDBMSs) because Access is basically a mini RDBMS (relational database management system) which is also file based. Unless everything (front/back ends) is set up perfectly and conditions are ideal -- you will encounter the problem you are having. Microsoft came up with ADODB as a workaround for this problem. When I have to interface between sql server and Access -- I use ADODB. This has proven to be much more reliable and consistent between the small and large RDBMSs. Here is some sample ADODB code for reading from and writing to a Sql Server from Access
'--add a reference in Tools/References to Microsoft ActiveX Data Objects 2.x Library '--(2.5 or higher)
...
The Access "Long Text" column can contain a text string up to a gigabyte in size. The message says you are trying to fit 7596 characters into a 4000 character field.
If so, your SQL server database should be exposing an ODBC LongVarChar column instead of VarChar.
LongVarChar is an ODBC type. The mapping is done by the ODBC driver. If you use an ODBC driver that maps VarChar(MAX) to a VarChar ODBC column, you can either get a different driver, or, possibly, use a SQL SERVER 'TEXT' column instead. TEXT is the old SQL Server column type, from when VarChar could only go to 4000. Old ODBC drivers recognize that TEXT columns map to LongVarChar.
I think the error message is quite helpful.
You are trying to fit a string with length of 7596 while your maximum varchar length is 4000.
I guess you either truncate it or store it as a blob.

why 12c with extended varchar2 limit still converting sql server varchar(max) to long

Oracle version 12.1.0.2
max_string_size=extended
I am using sql server ODBC to connect to sql server database via Oracle gateway to sql server, the connection is working fine and i am able to access sql server tables.
However, as per Oracle documentation starting 12c and with extended limit on varchar2 data type the conversion of sqlserver varchar(max) to oracle Long will only happen if the length of sql server data is more than 32k.
My sql server table has few columns defined as varchar(max) in and all of those i see getting converted to LONG when i try to describe the table over dblink.
I need to load the data from sql server to oracle and the above problem is making it very difficult as more than one long columns can not be copied over dblink.
Any help will be deeply appreciated.
I created a view on the SQL server side that uses substr(column,1,4000) to fit within the old Oracle max 4000 character length. This worked quite well with Oracle 11.
I am in the process of migrating to a new Oracle 18 instance that uses character set AL32UTF8 instead of WE8MSWIN1252. The exact same SQL is now getting:
ORA-28500: connection from ORACLE to a non-Oracle system returned this message:
[Microsoft][ODBC Driver Manager] Program type out of range {HY003}
ORA-02063: preceding 2 lines from CEAV195
Fortunately I don't have a tight deadline for working this out.
Comment: I am now getting
[Error] Execution (8: 17): ORA-00997: illegal use of LONG datatype
despite using the following in the view on the SQL Server side:
cast(substring(cr.response,1,2000) as varchar(2000)) response
As I said earlier, this worked perfectly fine with Oracle 11 and the WE8MSWIN1252 character set.
I hit the same issue and found this solution elsewhere
set serverout on
DECLARE
l_cursor BINARY_INTEGER;
l_id VARCHAR2(60);
l_temp VARCHAR2(250);
l_notes VARCHAR2(32767);
BEGIN
l_cursor := DBMS_HS_PASSTHROUGH.open_cursor#remotedb;
DBMS_HS_PASSTHROUGH.parse#remotedb(
l_cursor,
'select "RecId","Notes" from "MySqlServerTable"'
);
LOOP
DBMS_HS_PASSTHROUGH.get_value#remotedb(l_cursor, 1, l_id);
DBMS_HS_PASSTHROUGH.get_value#remotedb(l_cursor, 2, l_notes);
DBMS_OUTPUT.put_line(l_id || ' ' || l_notes);
END LOOP;
exception
when others then
DBMS_HS_PASSTHROUGH.close_cursor#remotedb(l_cursor);
raise;
END;
/

How do I convert an Oracle TIMESTAMP data type to SQL Server DATETIME2 data type while connected via Link Server.?

I have tried some examples but so far not working.
I have a Link Server (SQL Server 2014) to an Oracle 12C Database.
The table contain a datatype TIMESTAMP with data like this:
22-MAR-15 04.18.24.144789000 PM
When attempting to query this table in SQL Server 2014 via link server I get the following error using this code:
SELECT CAST(OracleTimeStampColumn AS DATETIME2(7)) FROM linkServerTable
Error:
Msg 7354, Level 16, State 1, Line 8
The OLE DB provider "OraOLEDB.Oracle" for linked server "MyLinkServer" supplied invalid metadata for column "MyDateColumn". The data type is not supported.
While the error is self explanatory, I am not certain how to resolve this.
I need to convert the timestamp to datetime2. Is this possible?
You can work around this problem by using OPENQUERY. For me, connecting to Oracle 12 from SQL 2008 over a linked server, this query fails:
SELECT TOP 10 TimestampField
FROM ORACLE..Schema.TableName
...with this error:
The OLE DB provider "OraOLEDB.Oracle" for linked server "ORACLE" supplied invalid metadata for column "TimestampField". The data type is not supported.
This occurs even if I do not include the offending column (which is of type TIMESTAMP(6). Explicitly casting it to DATETIME does not help either.
However, this works:
SELECT * FROM OPENQUERY(ORACLE, 'SELECT "TimestampField" FROM SchemaName.TableName WHERE ROWNUM <= 10')
...and the data returned flows nicely into a DATETIME2() field.
One way to solve the problem is to create a view in oracle server and convert the OracleTimeStampColumn compatible with sql server's datetime2datatype. You can change the time format to 24 hours format in oracle server's view and mark the field as varchar. Then you can convert the varchar2 column to datetime2 when selecting the column in SQL Server.
In Oracle Server
Create or Replace View VW_YourTableName As
select to_char(OracleTimeStampColumn , 'DD/MM/YYYY HH24:MI:SS.FF') OracleTimeStampColumn from YourTableName
In SQL Server
SELECT CAST(OracleTimeStampColumn AS DATETIME2(7)) FROM **linkServerVIEW**

insert and select chinese word from oracle database

I am trying to insert chinese word into oracle database but anyhow it failed to display properly , here is my setting for database
SQL> select * FROM nls_database_parameters where parameter='NLS_NCHAR_CHARACTERSET';
PARAMETER
------------------------------
VALUE
--------------------------------------------------------------------------------
NLS_NCHAR_CHARACTERSET
AL16UTF16
SQL> select * FROM nls_database_parameters where parameter='NLS_CHARACTERSET';
PARAMETER
------------------------------
VALUE
--------------------------------------------------------------------------------
NLS_CHARACTERSET
AL32UTF8
The chinese character will be ".." when I copy/paste into my SQLPLUS to run the query.
The version I using is Oracle Database 11g Release 11.2.0.3.0 - 64bit.
Any hints ?
There can be several issues:
1) The characters can not be stored in the database.
2) The characters may be converted to something else depending on client language settings.
3) The tool you are working with cannot display the characters.
--
1) Check the byte values of the character as it is stored in the table.
select dump(column) from table where ...
The dump function will show the byte values and you can check if the correct bytes are stored in the column.
2) Check the NLS_LANG setting on your client.
3) If the correct bytes are stored in the table and they are not being converted to something else due to a NLS_LANG mismatch between server and client then maybe your tool cannot display the characters correctly. I'm pretty sure SQLPlus has a very limited interface. Maybe SQL Developer can display a wider range of characters.

Resources