Odd Oracle Error - c#

I'm having a small issue with an Oracle command, given below:
command.CommandText = "SELECT ID, NAME, RATING, LENGTH, STARTTIME FROM SCHEDULE WHERE ID=301 AND ROWNUM=1 AND SCHEDULE.STARTTIME <= SYSDATE ORDER BY STARTTIME DESC;";
It runs perfectly well in Oracle SQL Developer, returning exactly what I need, but in C#, i get the following error:
ORA-06550: line 1, column 186:
PLS-00103: Encountered the symbol "," when expecting one of the following:
. ( * # % & = - + < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec as between || indicator multiset member
submultiset
Can anyone see any issues with it, or anything that is illegal within C#?
EDIT: Execution code:
command.Connection = conSQL;
using (IDataReader reader = command.ExecuteReader())
{
do
{
int count = reader.FieldCount;
while (reader.Read())
{
for (int i = 0; i < count; i++)
{
string setting = reader.GetName(i).ToString();
object value = reader.GetValue(i);
** Data assigned to variables here, hidden due to length of code**
** Follows pattern: object.property(reader.name) = reader.value **
}
}
} while (reader.NextResult());
}

dot not put ; at the end of the command, that's a command line tool convention, not part of sql proper (sqlplus also uses / as terminator for instance)

Name and Id are both special keywords in Oracle SQL. Try:
SELECT "ID", "NAME"...

Remove the trailing semi-colon on the SQL statement.
Share and enjoy.

Related

Reading TCURR table with RFC_READ_TABLE truncates the rate value

I'm trying to read data from SAP ECC using Microsoft .NET. For this, I am using the SAP Connector for Microsoft .NET 3.0 Following is the code to retrieve the data, I'm getting the results too. However, I found that the exchange rate value is having a * if it exceeds 7 characters.
ECCDestinationConfig cfg = new ECCDestinationConfig();
RfcDestinationManager.RegisterDestinationConfiguration(cfg);
RfcDestination dest = RfcDestinationManager.GetDestination("mySAPdestination");
RfcRepository repo = dest.Repository;
IRfcFunction testfn = repo.CreateFunction("RFC_READ_TABLE");
testfn.SetValue("QUERY_TABLE", "TCURR");
// fields will be separated by semicolon
testfn.SetValue("DELIMITER", ";");
// Parameter table FIELDS contains the columns you want to receive
// here we query 3 fields, FCURR, TCURR and UKURS
IRfcTable fieldsTable = testfn.GetTable("FIELDS");
fieldsTable.Append();
fieldsTable.SetValue("FIELDNAME", "FCURR");
fieldsTable.Append();
fieldsTable.SetValue("FIELDNAME", "TCURR");
fieldsTable.Append();
fieldsTable.SetValue("FIELDNAME", "UKURS");
fieldsTable.Append();
fieldsTable.SetValue("FIELDNAME", "GDATU");
// the table OPTIONS contains the WHERE condition(s) of your query
// several conditions have to be concatenated in ABAP syntax, for instance with AND or OR
IRfcTable optsTable = testfn.GetTable("OPTIONS");
var dateVal = 99999999 - 20190701;
optsTable.Append();
optsTable.SetValue("TEXT", "gdatu = '" + dateVal + "' and KURST = 'EURX'");
testfn.Invoke(dest);
Values are as follows:
How to get the full value without any truncation?
You just ran into the worst limitation of RFC_READ_TABLE.
Its error is to return field values based on internal length and truncating the rest, rather than using the output length. TCURR-UKURS is a BCD decimal packed field of length 9,5 (9 bytes = 17 digits, including 5 digits after the decimal point) and an output length of 12. Unfortunately, RFC_READ_TABLE outputs the result on 9 characters, so a value of 105.48000- takes 10 characters is too long, so ABAP default logic is to set the * overflow character on the leftmost character (*5.48000-).
Either you create another RFC-enabled function module at SAP/ABAP side, or you access directly the SAP database (classic RDBMS connected to SAP server).
Just an addition to Sandra perfect explanation about this issue. Yes, the only solution here would be writing a custom module for fetching remote records.
If you don't want to rewrite it from scratch the simplest solution would be to copy RFC_READ_TABLE into Z module and change line 137
FIELDS_INT-LENGTH_DST = TABLE_STRUCTURE-LENG.
to
FIELDS_INT-LENGTH_DST = TABLE_STRUCTURE-OUTPUTLEN.
This solves the problem.
UPDATE: try BAPI_EXCHANGERATE_GETDETAIL BAPI, it is RFC-enabled and reads rates correctly. The interface is quite self-explanatory, the only difference is that date should be in native format, not in inverted:
CALL FUNCTION 'BAPI_EXCHANGERATE_GETDETAIL'
EXPORTING
rate_type = 'EURO'
from_curr = 'USD'
to_currncy = 'EUR'
date = '20190101'
IMPORTING
exch_rate = rates
return = return.
Use BBP_RFC_READ_TABLE. It is still not the best but it does one thing right which RFC_READ_TABLE did not: one additional byte for the decimal sign.
No need to go through all the ordeal if you only look for patching the decimal issue.
This is the sample code used with SAP connector for .NET, let it be helpful for someone who looks for the same. Thanks for all those who helped.
var RateForDate = 20190701;
ECCDestinationConfig cfg = new ECCDestinationConfig();
RfcDestinationManager.RegisterDestinationConfiguration(cfg);
RfcDestination dest = RfcDestinationManager.GetDestination("mySAPdestination");
RfcRepository repo = dest.Repository;
IRfcFunction sapFunction = repo.CreateFunction("RFC_READ_TABLE");
sapFunction.SetValue("QUERY_TABLE", "TCURR");
// fields will be separated by semicolon
sapFunction.SetValue("DELIMITER", ";");
// Parameter table FIELDS contains the columns you want to receive
// here we query 3 fields, FCURR, TCURR and UKURS
IRfcTable fieldsTable = sapFunction.GetTable("FIELDS");
fieldsTable.Append();
fieldsTable.SetValue("FIELDNAME", "FCURR");
//fieldsTable.Append();
//fieldsTable.SetValue("FIELDNAME", "TCURR");
//fieldsTable.Append();
//fieldsTable.SetValue("FIELDNAME", "UKURS");
// the table OPTIONS contains the WHERE condition(s) of your query
// here a single condition, KUNNR is to be 0012345600
// several conditions have to be concatenated in ABAP syntax, for instance with AND or OR
IRfcTable optsTable = sapFunction.GetTable("OPTIONS");
var dateVal = 99999999 - RateForDate;
optsTable.Append();
optsTable.SetValue("TEXT", "gdatu = '" + dateVal + "' and KURST = 'EURX'");
sapFunction.Invoke(dest);
var companyCodeList = sapFunction.GetTable("DATA");
DataTable Currencies = companyCodeList.ToDataTable("DATA");
//Add additional column for rates
Currencies.Columns.Add("Rate", typeof(double));
//------------------
sapFunction = repo.CreateFunction("BAPI_EXCHANGERATE_GETDETAIL");
//rate type of your system
sapFunction.SetValue("rate_type", "EURX");
sapFunction.SetValue("date", RateForDate.ToString());
//Main currency of your system
sapFunction.SetValue("to_currncy", "EUR");
foreach (DataRow item in Currencies.Rows)
{
sapFunction.SetValue("from_curr", item[0].ToString());
sapFunction.Invoke(dest);
IRfcStructure impStruct = sapFunction.GetStructure("EXCH_RATE");
item["Rate"] = impStruct.GetDouble("EXCH_RATE_V");
}
dtCompanies.DataContext = Currencies;
RfcDestinationManager.UnregisterDestinationConfiguration(cfg);

T-SQL processing speed slow down after loading 25 million records

The question is why am I having a slow down at 25 million records. Is this a SQL Server config issue, code or both?
After approximately 25 million records loaded, in the routine pGetOHLCBetweenTwoDates(...) (see code below) the following line
SqlDataReader rdr = sqlCmd.ExecuteReader();
takes 20 times as long to load records from via T-SQL (SQL Server). It does not matter how many records are loaded per pass (50k, 100k,250k) it is always at around 25m records that the slow down occurs (see logs excerpts below).
It is not a resource issue, the system this is running on has 128 gb memory, dual 8 cores and SQL Server has 8 gig of memory avail, SQL Server is running locally, SQL Server was increased to 32 gig to see if that would fix the issue, it did not. I see the same thing on the SQL server profiler side 500-600 ms jumping to 10,000 - 30,000 ms.
idxLoadPos 25249999 - Elapsed time 00:00:00.9609748
idxLoadPos 25099999 - Elapsed time 00:00:00.5936540
idxLoadPos 24949999 - Elapsed time 00:00:00.5890105
idxLoadPos 24799999 - Elapsed time 00:00:11.5260435 <---<< Approx 25 million records loaded
idxLoadPos 24649999 - Elapsed time 00:00:10.9329704
idxLoadPos 24499999 - Elapsed time 00:00:11.2460554
Code:
public static int GetOHLCBetweenTwoDates(ref OHLCArray ohlcArray, int currentIndex, DateTime fromDate, DateTime toDate, DataFeedConfig dataFeedConfig)
{
// loads an array bottom up to match the standards in TA-LIBRARY in C Sharp
DateTime fDate = fromDate;
DateTime tDate = toDate;
int recordCount = SQL.GetCountBetweenTwoDates(fromDate, toDate, ohlcArray.TimePeriod, dataFeedConfig);
int maxReturnCount = LoadRecordCount;
//int maxReturnCount = 100000;
int getRecordCount = maxReturnCount;
int remainingRecordCount = recordCount;
int idxArrayLoadPosition = currentIndex;
Console.WriteLine("SQL - int - GetOHLCBetweenTwoDates from: {0}, to: {1}, getRecordCount: {2} ", fDate.ToString(), tDate.ToString(), getRecordCount.ToString());
while (fDate <= tDate & remainingRecordCount > 1) //0
{
getRecordCount = (remainingRecordCount < maxReturnCount) ? remainingRecordCount : maxReturnCount;
fDate = SQL.pGetOHLCBetweenTwoDates(ref ohlcArray, ref idxArrayLoadPosition, getRecordCount, fDate, tDate, ohlcArray.TimePeriod, dataFeedConfig);
remainingRecordCount -= (getRecordCount - 1); // no -1
Console.WriteLine("SQL - GetOHLCBetweenTwoDates from: {0}, to: {1}, getRecordCount: {2} ", fDate.ToString(), tDate.ToString(), getRecordCount.ToString());
}
idxArrayLoadPosition++;
if (idxArrayLoadPosition == -1) { idxArrayLoadPosition = 0; }
return idxArrayLoadPosition;
}
private static DateTime pGetOHLCBetweenTwoDates(ref OHLCArray ohlcArray, ref int idxArrayLoadPosition, int recordCount, DateTime fromDate, DateTime toDate, Enums.TimePeriodTypes tpt, DataFeedConfig dataFeedConfig)
{
DateTime returnDate = new DateTime(1901, 01, 01);
string database = "" + dataFeedConfig.Exchange + "." + dataFeedConfig.Issue + ".Data"; //string database = "[" + Exchange + "." + Issue + ".Data]";
string userName = dataFeedConfig.sqlLoginCredentials.SQLUserName;
string password = dataFeedConfig.sqlLoginCredentials.SQLPassword;
string server = dataFeedConfig.sqlLoginCredentials.SQLServerName;
string tableName = "Data." + tpt;
string connString = "server=" + server + ";uid=" + userName + ";pwd=" + password + ";database=" + database + ";Integrated Security=True;";
string databaseAndTable = "[" + database + "].[dbo].[" + tableName + "]"; /* [database].[dbo].[table], database = [Exchange.Issue.Data], table = [Data.TimePeriods(enum)] */
string sqlQueryString = "SELECT TOP " + recordCount.ToString() + " * FROM " + databaseAndTable + " WHERE [dtTime] >= '" + fromDate.ToString() + "' AND [dtTime] <= '" + toDate.ToString() + "' ORDER BY [dtTime] ASC";
using (SqlConnection sqlConnection = new SqlConnection(connString))
{
sqlConnection.Open();
using (SqlCommand sqlCmd = new SqlCommand(sqlQueryString, sqlConnection))
{
SqlDataReader rdr = sqlCmd.ExecuteReader();
while (rdr.Read())
{
ohlcArray.dtTime[idxArrayLoadPosition] = (DateTime)(rdr.GetSqlDateTime(0));
ohlcArray.High[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(1));
ohlcArray.Low[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(2));
ohlcArray.Open[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(3));
ohlcArray.Close[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(4));
ohlcArray.Volume[idxArrayLoadPosition] = int.Parse(rdr.GetSqlInt32(5).ToString());
returnDate = ohlcArray.dtTime[idxArrayLoadPosition];
idxArrayLoadPosition--;
}
rdr.Close();
}
sqlConnection.Close();
}
return returnDate;
}
Any ideas on which direction to go next to solve this?
Edit: more info ... the tables have this structure:
string cTable = "CREATE TABLE " + dbAndTable + " ([dtTime] [datetime] NOT NULL,[Bid] [float] NULL, [Ask] [float] NULL,[Volume] [float] NULL) ON [PRIMARY] ";
string cIndex = "CREATE INDEX " + indexName + " ON " + dbAndTable + " (dtTime)";<br/>
Should the [dTime] column be a primary key as opposed to just an index?
My friend your biggest problem is the implicit data conversion you are forcing sql server to do for you by converting from the strings "fromdate" and "todate" to the datetime datatype you established with your provided CREATE TABLE statement.
This is punishing processing running on such a large table. I believe you should
Modify the CREATE TABLE statement to include a primary key with a clustered index on an identity(1,1) column for your table.
Modify the CREATE INDEX using the INCLUDED option for the columns Bid,Ask and Volume.
Write a stored procedure passing as parameters your desired TOP, LOWER DATE FLOOR AND UPPER DATE CEILING AS datatypes INT, DATETIME, DATETIME.
Refactor your calling code to execute the stored procedure.
These are all well established best practices as I understand them.
Followup: I noticed that you are implementing paging after bringing all records back from the db ... instead implementing paging with SQL SERVER using FETCH NEXT will speed processing. Implement the necessary parameters on the stored procedure.
First thing we need to know the delay type:
Please run sp_whoisactive #get_plans=1. Google and download whoisactive if you didn't have one.
Then check the wait type column. It would tell you the wait types. Please post here we can take a look.
Without knowing the wait types, there are a few possible reasons:
1.
Usually after loading 25m rows, your buffer pool would be affected: existing cached data or compiled plans might be pushed out back to make room for loaded rows.
You might have async_network_io wait type, it does not necessarily mean you have network delay one of possible reason was that SQL SERVER is waiting for the client to process the data before sending more data.

How to calculate hashbyte SHA1 using C#?

In a table I have a column URL which I am using to save urls. I am calculating the hash in another column by using formula (CONVERT([varbinary](20),hashbytes('SHA1',[URL]))). It's working fine.
Now I need to get similar function in C# to get hash so that I can compare and check that similar row doesnt exist before I insert a new row. I tried few links but no luck.
Here are the links:
http://weblogs.sqlteam.com/mladenp/archive/2009/04/28/Comparing-SQL-Server-HASHBYTES-function-and-.Net-hashing.aspx
How do I calculate the equivalent to SQL Server (hashbytes('SHA1',[ColumnName])) in C#?
** I found this link working. All I need to do is change formula in the db. but is it possible to make it in one line
**
http://forums.asp.net/t/1782626.aspx
DECLARE #HashThis nvarchar(4000);
DECLARE #BinHash varbinary(4000);
SELECT #HashThis = CONVERT(nvarchar(4000),'Password#Test');
SELECT #BinHash = HashBytes('SHA1', #HashThis);
SELECT cast(N'' as xml).value('xs:base64Binary(xs:hexBinary(sql:variable("#BinHash")))', 'nvarchar(4000)');
in c#
string pwd = "Password#Test";
var sha1Provider = HashAlgorithm.Create("SHA1");
var binHash = sha1Provider.ComputeHash(Encoding.Unicode.GetBytes(pwd));
Console.WriteLine(Convert.ToBase64String(binHash));
I am using sql server 2012. collation for the database is SQL_Latin1_General_CP1_CI_AS
Thanks
Paraminder
It's an encoding issue:
C#/.Net/CLR strings are, internally, UTF-16 encoded strings. That means each character is at least two bytes.
Sql Server is different:
char and varchar represent each character as a single byte using the code page tied to the collation used by that column
nchar and nvarchar represent each character as 2 bytes using the [old and obsolete] UCS-2 encoding for Unicode — something which was deprecated in 1996 with the release of Unicode 2.0 and UTF-16.
The big difference between UTF-16 and UCS-2 is that UCS-2 can only represent characters within the Unicode BMP (Basic Multilingual Plane); UTF-16 can represent any Unicode character. Within the BMP, as I understand it, UCS-2 and UTF-16 representations are identical.
That means that to compute a hash that is identical to the one that SQL Server computes, you're going to have to get a byte representation that is identical to the one that SQL Server has. Since it sounds like you're using char or varchar with the collation SQL_Latin1_General_CP1_CI_AS, per the documentation, the CP1 part means code page 1252 and the rest means case-insensitive, accent-sensitive. So...
You can get the encoding for code page 1252 by:
Encoding enc = Encoding.GetEncoding(1252);
Using that information, and given this table:
create table dbo.hash_test
(
id int not null identity(1,1) primary key clustered ,
source_text varchar(2000) collate SQL_Latin1_General_CP1_CI_AS not null ,
hash as
( hashbytes( 'SHA1' , source_text ) ) ,
)
go
insert dbo.hash_test ( source_text ) values ( 'the quick brown fox jumped over the lazy dog.' )
insert dbo.hash_test ( source_text ) values ( 'She looked like something that might have occured to Ibsen in one of his less frivolous moments.' )
go
You'll get this output
1: the quick brown fox jumped over the lazy dog.
sql: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F
c#: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F
2: She looked like something that might have occured to Ibsen in one of his less frivolous moments.
sql: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C
c#: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C
from this program
class Program
{
static byte[] Sha1Hash( string s )
{
SHA1 sha1 = SHA1.Create() ;
Encoding windows1252 = Encoding.GetEncoding(1252) ;
byte[] octets = windows1252.GetBytes(s) ;
byte[] hash = sha1.ComputeHash( octets ) ;
return hash ;
}
static string HashToString( byte[] bytes )
{
StringBuilder sb = new StringBuilder() ;
for ( int i = 0 ; i < bytes.Length ; ++i )
{
byte b = bytes[i] ;
if ( i > 0 && 0 == i % 4 ) sb.Append( ' ' ) ;
sb.AppendFormat( b.ToString("X2") ) ;
}
string s = sb.ToString() ;
return s ;
}
private static DataTable ReadDataFromSqlServer()
{
DataTable dt = new DataTable();
using ( SqlConnection conn = new SqlConnection( "Server=localhost;Database=sandbox;Trusted_Connection=True;"))
using ( SqlCommand cmd = conn.CreateCommand() )
using ( SqlDataAdapter sda = new SqlDataAdapter(cmd) )
{
cmd.CommandText = "select * from dbo.hash_test" ;
cmd.CommandType = CommandType.Text;
conn.Open();
sda.Fill( dt ) ;
conn.Close() ;
}
return dt ;
}
static void Main()
{
DataTable dt = ReadDataFromSqlServer() ;
foreach ( DataRow row in dt.Rows )
{
int id = (int) row[ "id" ] ;
string sourceText = (string) row[ "source_text" ] ;
byte[] sqlServerHash = (byte[]) row[ "hash" ] ;
byte[] myHash = Sha1Hash( sourceText ) ;
Console.WriteLine();
Console.WriteLine( "{0:##0}: {1}" , id , sourceText ) ;
Console.WriteLine( " sql: {0}" , HashToString( sqlServerHash ) ) ;
Console.WriteLine( " c#: {0}" , HashToString( myHash ) ) ;
Debug.Assert( sqlServerHash.SequenceEqual(myHash) ) ;
}
return ;
}
}
Easy!
I would suggest that that anytime a hash is created that it be done in a single place. Either in code or on the database. It will make your life easier in the long run. That would mean either changing you C# code to create the hash before inserting the record or doing the duplication check within a stored procedure instead.
Regardless though, the duplication check and insert should be synchronized such that no other inserts could occur between the time you check for any duplicates and when the record is actually inserted. Easiest way to do that would be to perform them both within the same transaction.
If you insist on leaving the logic as it stands I would then suggest that you create the hash in the database but expose it via a stored procedure or user defined function that could be called from your C# code.

Convert a file full of "INSERT INTO xxx VALUES" in to something Bulk Insert can parse

This is a followup to my first question "Porting “SQL” export to T-SQL".
I am working with a 3rd party program that I have no control over and I can not change. This program will export it's internal database in to a set of .sql each one with a format of:
INSERT INTO [ExampleDB] ( [IntField] , [VarcharField], [BinaryField])
VALUES
(1 , 'Some Text' , 0x123456),
(2 , 'B' , NULL),
--(SNIP, it does this for 1000 records)
(999, 'E' , null);
(1000 , 'F' , null);
INSERT INTO [ExampleDB] ( [IntField] , [VarcharField] , BinaryField)
VALUES
(1001 , 'asdg', null),
(1002 , 'asdf' , 0xdeadbeef),
(1003 , 'dfghdfhg' , null),
(1004 , 'sfdhsdhdshd' , null),
--(SNIP 1000 more lines)
This pattern continues till the .sql file has reached a file size set during the export, the export files are grouped by EXPORT_PATH\%Table_Name%\Export#.sql Where the # is a counter starting at 1.
Currently I have about 1.3GB data and I have it exporting in 1MB chunks (1407 files across 26 tables, All but 5 tables only have one file, the largest table has 207 files).
Right now I just have a simple C# program that reads each file in to ram then calls ExecuteNonQuery. The issue is I am averaging 60 sec/file which means it will take about 23 hrs for it to do the entire export.
I assume if I some how could format the files to be loaded with a BULK INSERT instead of a INSERT INTO it could go much faster. Is there any easy way to do this or do I have to write some kind of Find & Replace and keep my fingers crossed that it does not fail on some corner case and blow up my data.
Any other suggestions on how to speed up the insert into would also be appreciated.
UPDATE:
I ended up going with the parse and do a SqlBulkCopy method. It went from 1 file/min. to 1 file/sec.
Well, here is my "solution" for helping convert the data into a DataTable or otherwise (run it in LINQPad):
var i = "(null, 1 , 'Some''\n Text' , 0x123.456)";
var pat = #",?\s*(?:(?<n>null)|(?<w>[\w.]+)|'(?<s>.*)'(?!'))";
Regex.Matches(i, pat,
RegexOptions.IgnoreCase | RegexOptions.Singleline).Dump();
The match should be run once per value group (e.g. (a,b,etc)). Parsing of the results (e.g. conversion) is left to the caller and I have not tested it [much]. I would recommend creating the correctly-typed DataTable first -- although it may be possible to pass everything "as a string" to the database? -- and then use the information in the columns to help with the extraction process (possibly using type converters). For the captures: n is null, w is word (e.g. number), s is string.
Happy coding.
Apparently your data is always wrapped in parentheses and starts with a left parenthesis. You might want to use this rule to split(RemoveEmptyEntries) each of those lines and load it into a DataTable. Then you can use SqlBulkCopy to copy all at once into the database.
This approach would not necessarily be fail-safe, but it would be certainly faster.
Edit: Here's the way how you could get the schema for every table:
private static DataTable extractSchemaTable(IEnumerable<String> lines)
{
DataTable schema = null;
var insertLine = lines.SkipWhile(l => !l.StartsWith("INSERT INTO [")).Take(1).First();
var startIndex = insertLine.IndexOf("INSERT INTO [") + "INSERT INTO [".Length;
var endIndex = insertLine.IndexOf("]", startIndex);
var tableName = insertLine.Substring(startIndex, endIndex - startIndex);
using (var con = new SqlConnection("CONNECTION"))
{
using (var schemaCommand = new SqlCommand("SELECT * FROM " tableName, con))
{
con.Open();
using (var reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
{
schema = reader.GetSchemaTable();
}
}
}
return schema;
}
Then you simply need to iterate each line in the file, check if it starts with ( and split that line by Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries). Then you could add the resulting array into the created schema-table.
Something like this:
var allLines = System.IO.File.ReadAllLines(path);
DataTable result = extractSchemaTable(allLines);
for (int i = 0; i < allLines.Length; i++)
{
String line = allLines[i];
if (line.StartsWith("("))
{
String data = line.Substring(1, line.Length - (line.Length - line.LastIndexOf(")")) - 1);
var fields = data.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// you might need to parse it to correct DataColumn.DataType
result.Rows.Add(fields);
}
}

How can I rearrange string with SQL?

Declare #CustTotalCount as int
Declare #CustMatchCount as int
select #CustTotalCount = count(*) from ENG_CUSTOMERTALLY
select #CustMatchCount = count(*) from Task where MPDReference in(
select ENG_CUSTOMERTALLY_CUSTOMERTASKNUMBER from dbo.ENG_CUSTOMERTALLY)
if(#CustTotalCount>#CustMatchCount)
select distinct
substring(ENG_CUSTOMERMYCROSS_MYTECHNIC_TASK_NO, charindex('-', ENG_CUSTOMERMYCROSS_MYTECHNIC_TASK_NO)
+ 1, 1000)
from dbo.ENG_CUSTOMERMYCROSS where
ENG_CUSTOMERMYCROSS_CUSTOMER_NUMBER in(
select ENG_CUSTOMERTALLY_CUSTOMERTASKNUMBER from ENG_CUSTOMERTALLY1
except
select MPDReference from Task )
I can convert
- A320-200001-01-1(1)
- A320-200001-02-1(2)
- A320-200001-01-1(2)
- A320-200001-01-1(1)
- A320-200001-01-1(2)
- A320-200001-02-1(1)
TO
- 200001-01-1(1)
- 200001-02-1(2)
- 200001-01-1(2)
- 200001-01-1(1)
- 200001-01-1(2)
- 200001-02-1(1)
But I need to :
- 200001-01-1
- 200001-02-1
- 200001-01-1
- 200001-01-1
- 200001-01-1
- 200001-02-1
How can I do that in SQL and C#?
Is the pattern always the same, if so you could just use SUBSTRING to pull out the bit you want.
EDIT: To take in additional stuff asked in How can i use substring in SQL?
You could
SELECT DISTINCT SUBSTRING(....) FROM ...
as answered above, use the SUBSTRING method like you are but use a length of 11 instead of 1000 as long as the data is always in the format you show above.
In C# it would be:
string s = "A320-20001-01-1(1)";
string result = s.Substring(s.IndexOf('-'), 11);
again this is assuming the part you want is always 11 characters. Otherwise if it is always the first '(' you want to end before, you the IndexOf method/function again to find the end index and subtract the first index
Try substring and len, this sample cuts first 6 and last 4 (4 = 10-6) chars
declare #var varchar(50)
set #var = 'A320-200001-01-1(1)
select substring(#var, 6, len(#var) - 10)
output: 200001-01
In c#, functions are similar, exept zero-based index:
string var = "A320-200001-01-1(1)";
var = var.Substring(5, var.Length - 8);
Console.WriteLine(var);
Here's a technique that uses PATINDEX, which can use wild cards.
SUBSTRING(ENG_CUSTOMERMYCROSS_MYTECHNIC_TASK_NO,
PATINDEX('%[0-9]%', ENG_CUSTOMERMYCROSS_MYTECHNIC_TASK_NO),
PATINDEX('%(%', ENG_CUSTOMERMYCROSS_MYTECHNIC_TASK_NO)
- PATINDEX('%[0-9]%', ENG_CUSTOMERMYCROSS_MYTECHNIC_TASK_NO)
)
The start for your substring is the position of the first numeric value (%[0-9]%). The length value is the position of the first parenthesis ('%(%') less the starting position.

Categories

Resources