I'm trying to use the openedge jdbc connector to pull data from an existing progress db but im running into column width issues.
Here is the error that is holding me up.
[DataDirect][OpenEdge JDBC Driver][OpenEdge] Column TabDisplayName in table PUB.Menu has value exceeding its max length or precision.
I've looked at many posts, each offering different advice, and here's what I've given a go this far:
Manually modify the SQL width via the data dictionary.
I ran a quick check on PUB.Menu.TabDisplayName to find a max value of 44 Characters
Set the width to x(50) to no avail and then x(100) out of a fix of irrational rage, again with no luck.
Use the SUBSTR() SQL Function to truncate the field -not optimum but better than nothing
I get weird results with this. It works fine in sqlexp but in a java environment its like the column is never selected.
Use the dbtool to automatically fix width problems with option #2
After selecting all tables and "areas" (not sure what those are...) and submitting the final option I am returned to the proenv cmdline as if nothing ever happened.
Modify the sql width programmatically via 4gl
This is the only option I found that I have yet to try.
I am a little reluctant to try this only because a manual modification failed. Also this is a live development environment(for me only) and Im trying to mess it up too terribly, although i am taking snaps regularly.
Running progress 10.2B on a unix machine.
Any comments and suggestions would be appreciated.
-Thanks
The dbtool option is the best. It is designed for this. From proenv you should see something like this:
proenv> dbtool s2k
DATABASE TOOLS MENU - 10.2B
---------------------------
1. SQL Width & Date Scan w/Report Option
2. SQL Width Scan w/Fix Option
3. Record Validation
4. Record Version Validation
5. Read or Validate Database Block(s)
6. Record Fixup
7. Schema Validation
9. Enable/Disable File Logging
Q. Quit
Choice: 2
: (0=single-user 1=self-service >1=#threads)? 1
Padding % above current max: 100
: (Table number or all)? all
: (Area number or all)? all
: (verbose level 0-3)? 0
Total records read: 31357
SQLWidth errors found: 0, Date errors found: 0
SQLWidth errors fixed: 0
If your db has a server up & running choose "1" at the connect: prompt. If not, choose "0".
Pick 100 for padding to double the width of fields.
Try it on a copy of the "sports" database if you are unsure. Use a higher level of verboseness if you want some insight into what it is doing.
It does not take very long to run on a small development database. (It is basically instantaneous on "sports".)
It is possible to create views with substring (field.name,1,maxlength) option and use PUB2.viewname instead pub.tablename
DROP VIEW PUB2."accounts";
CREATE VIEW PUB2."accounts" (
"ACC-TYPE",
"ACCOUNT-NAME",
ANALITIC,
ARCH,
COUNT1,
CURRENCY,
PLAN,
QUANTITY,
"RID-ANOBJECT",
"RID-APP",
TRANSIT )
AS select "acc-type",
SUBSTRING("account-name", 1, 130),
"analitic",
"arch",
"count1",
"currency",
"plan",
"quantity",
"rid-anobject",
"rid-app",
"transit"
FROM PUB."accounts";
COMMIT;
use sqlexp for automatic creation:
sqlexp account -H localhost -S ' + db-port + ' -user sysprogress -password sysprogress -infile recreateSQLviews.sql -outfile recreateSQLviews.log
here is code:
def var num-port as integer.
for first _Servers where _Servers._Server-Type = "Login" no-lock:
num-port = _Servers._Server-PortNum.
end.
if num-port < 0 then num-port = num-port + 65536.
if num-port = 0 then do:
message "Define -S parameter for Database" view-as alert-box.
RETURN.
end.
message num-port.
/* ttSQLWidth table: SQL WIDTH for all tables */
def var execstr as char.
def var rez-str as char.
def var db-port as char. /* -S port */
db-port = STRING(num-port).
DEFINE TEMP-TABLE ttSQLWidth NO-UNDO
FIELD tableName AS CHARACTER
FIELD tableNum AS INTEGER
FIELD fieldName AS CHARACTER
FIELD sqlWidth AS INTEGER
FIELD requireFix AS LOGICAL INIT FALSE
FIELD actualWidth AS INTEGER
FIELD newWidth AS INTEGER
INDEX tableNum tableNum
INDEX tableName tableName.
FOR EACH _File NO-LOCK WHERE _Tbl-Type = "T":
FOR EACH _Field OF _File WHERE _Field._Data-type = "character":
if _field._extent > 0 then next.
CREATE ttSQLWidth.
ASSIGN tableName = _File._File-name
tableNum = _File._File-num
fieldName = _Field._Field-name
sqlWidth = _Field._Width.
RELEASE ttSQLWidth.
END. /* FOR EACH _Field */
END. /* FOR EACH _File */
DEFINE VARIABLE bTab AS HANDLE NO-UNDO.
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE queryString AS CHARACTER NO-UNDO.
FOR EACH ttSQLWidth:
CREATE BUFFER bTab FOR TABLE tableName.
CREATE QUERY hQuery.
hQuery:ADD-BUFFER(bTab).
message tablename.
queryString = "FOR EACH " + tableName + " WHERE LENGTH(" + fieldName + ") >= " + STRING(sqlWidth) + " BY LENGTH(" + fieldName + ") DESC".
hQuery:QUERY-PREPARE(queryString).
hQuery:QUERY-OPEN().
IF hQuery:GET-NEXT() THEN DO:
ASSIGN actualWidth = LENGTH(bTab:BUFFER-FIELD(fieldName):BUFFER-VALUE)
requireFix = TRUE.
END. /* IF .. THEN DO */
hQuery:QUERY-CLOSE.
DELETE OBJECT hQuery.
bTab:BUFFER-RELEASE().
DELETE OBJECT bTab.
END. /* FOR EACH ttSQLWidth */
def var add-pr as integer initial 10. /* % from max */
def var maxWidth as integer initial 249. /* maxwidth */
FOR EACH ttSQLWidth WHERE ttSQLWidth.requireFix = TRUE:
ttSQLWidth.newWidth = TRUNCATE ( (ttSQLWidth.actualWidth + add-pr) / add-pr, 0 ) * add-pr.
ttSQLWidth.newWidth = INTEGER( ttSQLWidth.newWidth).
if ttSQLWidth.newWidth > maxWidth then ttSQLWidth.newWidth = maxWidth.
END.
/* sql script generation */
OUTPUT TO value("recreateSQLviews.sql").
def var lst-field as char.
FOR EACH ttSQLWidth WHERE BREAK BY ttSQLWidth.tableName:
IF FIRST-OF(ttSQLWidth.tableName)
THEN run MakeSQLViews(ttSQLWidth.tableName).
END.
OUTPUT CLOSE.
/* sql script execution */
execstr = 'sqlexp account -H localhost -S ' + db-port + ' -user sysprogress -password sysprogress -infile recreateSQLviews.sql -outfile recreateSQLviews.log'.
input through value(execstr).
repeat:
IMPORT UNFORMAT rez-str.
message rez-str.
end.
INPUT CLOSE.
RETURN.
PROCEDURE MakeSQLViews:
define input parameter tableName as character.
def var str_tmp as char.
def var str_tmp1 as char.
def var str as char initial "count,sum,double,row,date,level,area,number,primary".
def var fieldName as char.
def var fieldName1 as char.
FOR EACH _file WHERE _file._file-name = tableName AND
_file._file-num GT 0 AND _file._file-num LT 32000 NO-LOCK:
fieldName = "".
FOR EACH _Field OF _File NO-LOCK:
str_tmp = '"' + _Field._Field-name + '"'.
FOR FIRST ttSQLWidth where ttSQLWidth.tableName = _file._file-name and
ttSQLWidth.fieldName = _Field._Field-name and
ttSQLWidth.requireFix = TRUE:
str_tmp = 'SUBSTRING("' + _Field._Field-name + '", 1, ' + STRING(ttSQLWidth.newWidth) + ')'.
END.
fieldName = fieldName + (IF(fieldName = "") THEN ("") ELSE ("," + chr(10) + chr(9))) + str_tmp.
str_tmp1 = ( IF ( INDEX ( _Field._Field-name, "-" ) = 0 )
THEN ( _Field._Field-name )
ELSE ( '"' + _Field._Field-name + '"' )).
if LOOKUP ( _Field._Field-name, str, "," ) > 0 then str_tmp1 = '"' + _Field._Field-name + '"'.
fieldName1 = fieldName1 + (IF(fieldName1 = "") THEN ("") ELSE ("," + chr(10) + chr(9))) + UPPER(str_tmp1).
END. /* FOR EACH _Field */
PUT UNFORMATTED 'DROP VIEW PUB2."' + _file._file-name + '";' SKIP.
PUT UNFORMATTED 'CREATE VIEW PUB2."' + _file._file-name + '" ( ' + chr(10) chr(9) + fieldName1 + ' ) ' + chr(10) +
'AS select ' + fieldName + chr(10) +
'FROM PUB."' + _file._file-name + '";' SKIP.
PUT UNFORMATTED 'COMMIT;' SKIP(1).
END.
END.
Related
I'm trying to get the source of a view in my .net app.
To do this, I query DBA_VIEWS: it has a column TEXT with exactly what I need. The type is LONG.
If I do it using the Unmanaged driver, everything works as expected.
The same code with Managed driver results in ORA-01009: missing mandatory parameter.
Adding a transaction around the command and using breakpoint and "slow" steps sometimes results in the same code working.
ODP.NET version is 19, Oracle DB is 18c Express Edition. Strangely enough, the same code works just fine with Oracle Database 12c regardless of driver type.
Is there maybe some setting I need to change on the database or in code? I'm completely lost here.
Code I'm using for testing:
Imports System.Data.Common
Imports Oracle.ManagedDataAccess
'Imports Oracle.DataAccess
Module Views
Function CreateCommand(Connection As DbConnection) As System.Data.Common.DbCommand
Dim cmd As Data.Common.DbCommand = Connection.CreateCommand()
With CType(cmd, Client.OracleCommand)
.BindByName = True
.FetchSize = &H100000 '1 Mb
.InitialLONGFetchSize = -1 'the entire LONG or LONG RAW data is prefetched and stored in the fetch array.
.InitialLOBFetchSize = -1 'the entire LOB data is prefetched and stored in the fetch array.
End With
Return cmd
End Function
Sub query()
Try
Using DBConnection = New Client.OracleConnection("User ID=TESTUSER;Password=TESTPWD;Data Source=TESTDB;Pooling=True")
DBConnection.Open()
Using DBConnection.BeginTransaction()
Using cmdSQL = CType(CreateCommand(DBConnection), Client.OracleCommand)
cmdSQL.CommandText = "select TEXT from DBA_VIEWS where VIEW_NAME = :0"
Dim p = cmdSQL.CreateParameter()
p.ParameterName = "0"
p.Value = "TEST_VIEW"
cmdSQL.Parameters.Add(p)
Dim sw = Stopwatch.StartNew
Using rdr = cmdSQL.ExecuteReader
rdr.FetchSize = 2 ^ 20
While rdr.Read
Dim row(rdr.FieldCount - 1) As Object
rdr.GetProviderSpecificValues(row)
Dim x = row(0)
Console.WriteLine($"{x.ToString.Length} bytes")
End While
End Using
Console.WriteLine($"{sw.ElapsedMilliseconds} ms")
End Using
End Using
End Using
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub
End Module
You can use an anonymous block with output parameter and a call to ExecuteNonQuery. Your command text will be
"begin select TEXT into :0 from DBA_VIEWS where VIEW_NAME = :1; end;"
Add 2 parameters. Make sure that
' Parameter #1 has
p.Direction = ParameterDirection.Output
p.OracleDbType = OracleDbType.Long
p.Size = 1000000
And use command cmd.ExecuteNonQuery(). Then, when parameter is retrieved, just use its value
Dim txt As String = cmd.Parametersp[0].Value.ToString()
It's a pity, Oracle deprecated LONG data type for ages but LONG data is still used many times for internal data.
You could write a function and then get the data by calling the function:
create or replace function GetViewText(v in varchar2) return clob is
ret CLOB;
BEGIN
FOR aRow IN (SELECT TEXT FROM DBA_VIEWS WHERE VIEW_NAME = v) LOOP
ret := aRow.TEXT;
-- or ret := TO_CLOB(aRow.TEXT);
END LOOP;
RETURN ret;
END;
Yet another way from this answer is to (ab)use dbms_xmlgen.getxml.
We can either use it to query a single view's code (as in my original question)
with input as (
select
:0 as VIEW_NAME
from dual
)
SELECT
substr(
text_xml,
instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'),
instr(text_xml, '</LONGCOL>', -1) - (instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'))
) as TEXT
from
(
-- getxml can return malformed xml (which is good in this case)
-- while getxmltype can not.
select dbms_xmlgen.getxml(q'{
SELECT TEXT as LONGCOL
FROM SYS.DBA_VIEWS
WHERE VIEW_NAME = '}' || input.VIEW_NAME || q'{'
}') as text_xml
from input
)
or create our own DBA_VIEWS version.
create or replace view APP_SCHEMA.DBA_VIEWS
as
select
OWNER, VIEW_NAME, TEXT_LENGTH,
case
when (TEXT_VC is not null and TEXT_LENGTH <= 4000)
then to_clob(TEXT_VC)
when TEXT is NULL
then NULL
else (
SELECT
substr(
text_xml,
instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'),
--instr(text_xml, '</LONGCOL>', -1) - (instr(text_xml, '<LONGCOL>') + length('<LONGCOL>'))
TEXT_LENGTH
) as TEXT
from
(
-- getxml can return malformed xml (which is good in this case)
-- while getxmltype can not.
select dbms_xmlgen.getxml(q'{
SELECT TEXT as LONGCOL
FROM SYS.DBA_VIEWS
WHERE OWNER = '}' || OWNER || q'{'
and VIEW_NAME = '}' || VIEW_NAME || q'{'
}') as text_xml
from dual
)
)
end as TEXT,
TEXT_VC, TYPE_TEXT_LENGTH, TYPE_TEXT, OID_TEXT_LENGTH, OID_TEXT, VIEW_TYPE_OWNER, VIEW_TYPE, SUPERVIEW_NAME, EDITIONING_VIEW, READ_ONLY, CONTAINER_DATA, BEQUEATH, ORIGIN_CON_ID, DEFAULT_COLLATION, CONTAINERS_DEFAULT, CONTAINER_MAP, EXTENDED_DATA_LINK, EXTENDED_DATA_LINK_MAP, HAS_SENSITIVE_COLUMN
from sys.dba_views
;
I have to change a very old application written in Vb6 with Data Report.
Actually displays a query records with only one field named txtdata.
Now I would display always one field (txtdata) but with different text size and style depending on whether it starts with a # or not.
I thought to check records for records if it starts with # or not and set text style and size for each record.
How can I do?
Dim rs As Adodb.Recordset
Dim sql As String
Dim regtratt As
.................
' I have a Data Report with textbox named txtdata in Section1
sql = ""
sql = sql + "SELECT txtdata "
sql = sql + "FROM journal "
sql = sql + "WHERE cod=421 "
sql = sql + "ORDER BY id "
Set rs = xOpenRecordset(sql, cnOnline)
If rs.RecordCount > 0 Then
Set regtratt.DataSource = rs
regtratt.DataMember = ""
' I want to change the font according to the text but I don't know how to because DataSource=rs takes the records.
'If InStr("#", regtratt.Sections("Section1").Controls(1).Item.Value) Then
' regtratt.Sections("Section1").Controls(1).Font.size = 20
' regtratt.Sections("Section1").Controls(1).Font.Bold = True
'End If
regtratt.Orientation = rptOrientLandscape
regtratt.WindowState = vbMaximized
regtratt.Font.Name = "courier new"
regtratt.Refresh
regtratt.Show vbModal
Unload regtratt
Else
MsgBox ("Sorry No data")
End If
Is their any command in Foxpro that convert the DBF into a particular excel sheet.
I have three DBF(dbf_1, dbf_2, dbf_3). My current program convert the file using copy to "filename.xls" type fox2x and then I will manually copy the consolidate all the sheet into one excel. For me, this method I using is alright but what if their are 20 or more dbf that I will consolidate. Is their any command in foxpro that convert the dbf's into one excel file. I already use the foxpro Automation but it is to slow.
No there isn't.
Also "copy to ... type fox2x". although better than many other type selections (such as csv and xls) should not be chosen when there are better ways.
You are saying automation is slow, but don't know if you are really finding automation slow, or if you have tried it in the ways that you shouldn't use to transfer data to Excel. The sample below, use one of the variations of my "vfp2excel" function and automation. It transfers sample Customer, Employee, Orders, OrdItems and Products data in 2.5 seconds on my machine. If you really meant it as slow then no dice, otherwise here is the sample:
* These represent complex SQL as a sample
Select emp_id,First_Name,Last_Name,;
Title,Notes ;
from (_samples+'\data\employee') ;
into Cursor crsEmployee ;
readwrite
Replace All Notes With Chrtran(Notes,Chr(13)+Chr(10),Chr(10))
Select cust_id,company,contact,Title,country,postalcode ;
from (_samples+'\data\customer') ;
into Cursor crsCustomer ;
nofilter
Select * ;
from (_samples+'\data\orders') ;
into Cursor crsOrders ;
nofilter
Select * ;
from (_samples+'\data\orditems') ;
into Cursor crsOrderDetail ;
nofilter
Select * ;
from (_samples+'\data\products') ;
into Cursor crsProducts ;
nofilter
* Now we want to get these on 3 sheets
* Sheet1: Employees only
* Sheet2: Customers only
* Sheet3: Orders, ordItems, Products layed out horizontally
Local oExcel
oExcel = Createobject("Excel.Application")
With oExcel
.DisplayAlerts = .F.
.Workbooks.Add
.Visible = .T.
With .ActiveWorkBook
For ix = 1 To 3 && We want 3 Sheets
If .sheets.Count < m.ix
.sheets.Add(,.sheets(.sheets.Count)) && Add new sheets
Endif
Endfor
* Name the sheets
.WorkSheets(1).Name = "Employees"
.WorkSheets(2).Name = "Customers"
.WorkSheets(3).Name = "Order, OrderDetail, Products" && max sheetname is 31 chars
* Start sending data
* First one has headers specified
VFP2Excel('crsEmployee', .WorkSheets(1).Range("A1"), ;
"Id,First Name,Last Name,Employee Title,Comments about employee" ) && To sheet1, start at A1
VFP2Excel('crsCustomer', .WorkSheets(2).Range("A1") ) && To sheet2, start at A1
VFP2Excel('crsOrders', .WorkSheets(3).Range("A1") ) && To sheet3, start at A1
* Need to know where to put next
* Leave 2 columns empty - something like 'G1'
lcRange = _GetChar(.WorkSheets(3).UsedRange.Columns.Count + 3) + '1'
* To sheet3, start at next to previous
VFP2Excel('crsOrderDetail', .WorkSheets(3).Range(m.lcRange) )
lcRange = _GetChar(.WorkSheets(3).UsedRange.Columns.Count + 3) + '1'
* To sheet3, start at next to previous
VFP2Excel('crsProducts', .WorkSheets(3).Range(m.lcRange) )
#Define xlJustify -4130
#Define xlTop -4160
* I just happen to know notes in at column 5 from SQL
* No need to query from excel to keep code simple
* Lets format that column specially instead of leaving
* at the mercy of Excel's autofitting
.WorkSheets(1).UsedRange.VerticalAlignment = xlTop && set all to top
With .WorkSheets(1).Columns(5)
.ColumnWidth = 80 && 80 chars width
.WrapText = .T.
* .HorizontalAlignment = xlJustify && doesn't work good always
Endwith
* Finally some cosmetic stuff
For ix=1 To 3
With .WorkSheets(m.ix)
.Columns.AutoFit
.Rows.AutoFit
Endwith
Endfor
.WorkSheets(1).Activate
Endwith
Endwith
* Author: Cetin Basoz
* This is based on earlier VFP2Excel function codes
* that has been published on the internet, at various sites
* since 2001. Not to be messed with others' code who named the same but has
* nothing to do with the approaches taken here (unless copy & pasted and claimed
* to be their own work, < s > that happens).
Procedure VFP2Excel(tcCursorName, toRange, tcHeaders, tnPrefferredWidthForMemo)
* tcCursorName
* toRange
* tcHeaders: Optional. Defaults to field headers
* tnPrefferredWidthForMemo: Optional. Default 80
* Function VFP2Excel
tcCursorName = Evl(m.tcCursorName,Alias())
tnPrefferredWidthForMemo = Evl(m.tnPrefferredWidthForMemo,80)
Local loConn As AdoDB.Connection, loRS As AdoDB.Recordset,;
lcTemp,lcTempDb, oExcel,ix, lcFieldName, lcHeaders
lnSelect = Select()
lcTemp = Forcepath(Sys(2015)+'.dbf',Sys(2023))
lcTempDb = Forcepath(Sys(2015)+'.dbc',Sys(2023))
Create Database (m.lcTempDb)
Select * From (m.tcCursorName) Into Table (m.lcTemp) Database (m.lcTempDb)
Local Array aMemo[1]
Local nMemoCount
nMemoCount = 0
lcHeaders = ''
For ix = 1 To Fcount()
lcFieldName = Field(m.ix)
If Type(Field(m.ix))='M'
nMemoCount = m.nMemoCount + 1
Dimension aMemo[m.nMemoCount]
aMemo[m.nMemoCount] = m.ix
Replace All &lcFieldName With Chrtran(&lcFieldName,Chr(13)+Chr(10),Chr(10))
Endif
lcHeaders = m.lcHeaders + Iif(Empty(m.lcHeaders),'',',')+Proper(m.lcFieldName)
Endfor
tcHeaders = Evl(m.tcHeaders,m.lcHeaders)
Use In (Juststem(m.lcTemp))
Close Databases
Set Database To
loStream = Createobject('AdoDb.Stream')
loConn = Createobject('ADODB.Connection')
loRS = Createobject("ADODB.Recordset")
loConn.ConnectionString = "Provider=VFPOLEDB;Data Source="+m.lcTempDb
loConn.Open()
loRS = loConn.Execute("select * from "+m.lcTemp)
loRS.Save( loStream )
loRS.Close
loConn.Close
Erase (m.lcTemp)
* Use first row for headers
Local Array aHeader[1]
loRS.Open( loStream )
toRange.Offset(1,0).CopyFromRecordSet( loRS ) && Copy data starting from headerrow + 1
Set Safety Off
Delete Database (m.lcTempDb) Deletetables
Select (m.lnSelect)
For ix=1 To Iif( !Empty(m.tcHeaders), ;
ALINES(aHeader, m.tcHeaders,1,','), ;
loRS.Fields.Count )
toRange.Offset(0,m.ix-1).Value = ;
Iif( !Empty(m.tcHeaders), ;
aHeader[m.ix], ;
Proper(loRS.Fields(m.ix-1).Name) )
toRange.Offset(0,m.ix-1).Font.Bold = .T.
Endfor
#Define xlJustify -4130
#Define xlTop -4160
* This part is cosmetic
toRange.WorkSheet.Activate
With toRange.WorkSheet.UsedRange
.VerticalAlignment = xlTop && set all to top
For ix=1 To m.nMemoCount
With .Columns(aMemo[m.ix])
.ColumnWidth = m.tnPrefferredWidthForMemo && 80 chars width
.WrapText = .T.
Endwith
Endfor
.Columns.AutoFit
.Rows.AutoFit
Endwith
Endproc
* Return A, AA, BC etc noation for nth column
Function _GetChar
Lparameters tnColumn && Convert tnvalue to Excel alpha notation
If m.tnColumn = 0
Return ""
Endif
If m.tnColumn <= 26
Return Chr(Asc("A")-1+m.tnColumn)
Else
Return _GetChar(Int(Iif(m.tnColumn % 26 = 0,m.tnColumn - 1, m.tnColumn) / 26)) + ;
_GetChar((m.tnColumn-1)%26+1)
Endif
Endfunc
This is what I was looking for :-) I was trying with my knowledge of Excel Automation programming in Visual FoxPro but always got errors. My task was to create "n" Sheets from one big cursors which I want to parse regarding customer selection of attribute name from cursor to get also "n" Sheets. This sample is for 3 cursors and 3 Sheets and it is generic. But I need this for "n" cursors and one attribute which customer select to distinct and get "n" Sheets in one Excel file. So now I have dynamic procedure. I customized this code and solve my problem which I am trying to end for about 4 days. So again thank you for this code and off course I will not modify VFP2Excel procedure and wrote somewhere else my name. Thanks for help !
There is no native VFP function to do this, BUT, there is an awesome open source project which has a class that will make this very easy:
VFPx Workbook Xlsx - See it here on Github: XLSX Workbook for FoxPro
It has 3 magical functions that will do exactly what you asked for:
CreateWorkbook()
AddSheet()
SaveTableToWorkbook()
(Repeat commands 2 and 3 above for each DBF/Sheet you want to create)
It is well documented with a 54-page PDF and code sample that explains everything you'll need to know.
So I have 13 binary values, which I call b_1... b_13, and based off these values I'd like to either set something I call indic_j to a previously defined string called inf_j, or nothing at all. Is it possible to do this without using 13 "If..." statements? What I have tried is below:
inf_1 = "aaaaa"
inf_2 = "bbbbb"
... and so on defining 13 infs, where aaaaa, bbbbb etc are names of columns in a table that I want to select.
FOR j = 1 to 13
IF b_j = 1 THEN "indic_"+j = inf_j + ",";
ELSE "indic_"+j = ""
ENDIF
ENDFOR
Also, before this I haven't introduced anything called indic_1, indic_2, etc. Is this needed?
My end goal is to transfer selected columns over to Excel. I've no problems doing this with predetermined columns, but I'm not sure how to allow for selected columns only.
I've tried using 13 IF statements, but I'm getting operator/operand type mismatch errors. My code currently is
IIF(b_1 = 1, indic_1 = inf_1 + ",",indic_1 = "")
IIF(b_2 = 1, indic_1 = inf_2 + ",",indic_1 = "")
IIF(b_3 = 1, indic_1 = inf_3 + ",",indic_1 = "")
and so on for 13 times, and then
SELECTIONRANG = indic_1 + indic_2 + indic_3 + indic_4 + indic_5 + indic_6 +indic_7 + indic_8 + indic_9 + indic_10 + indic_11 + indic_12 + indic_13
SELECTIONRANGE = LEFT(SELECTIONRANG,LEN(Selectionrang)-1)
You could create te variable name as a string and use it with &
As:
ind = 13
Var = "inf_" + ind
&Var ** inf_13
var query = from s in bv.baParticularHeaders
from v in bv.baPlanColumnStructures
where x.Contains(s.Particular_Num)
select new LevelList
{
Value = 'Level ' + LTRIM(Rtrim(Convert(Char,P.Level_Num))) + ' - ',
id = 'Column ' + LTRIM(Rtrim(Convert(Char,P.Column_Num))) + ' ',
Text = v.Column_Description
};
return query.Distinct().OrderBy(o => o.Value).AsQueryable<LevelList>();
Error getting this both lines of code.
Value = 'Level ' + LTRIM(Rtrim(Convert(Char,P.Level_Num))) + ' - ',
id = 'Column ' + LTRIM(Rtrim(Convert(Char,P.Column_Num))) + ' ',
Can any body help me out how to convert this in LINQ?
Thanks
You can't just cut and paste SQL, rearrange it and hope to get a valid LINQ query. The aim is to write the appropriate C# code, which is translated into SQL. In this case I suspect you want:
var query = from s in bv.baParticularHeaders
from v in bv.baPlanColumnStructures
where x.Contains(s.Particular_Num)
select new LevelList
{
Value = "Level " + P.Level_Num + " - ";
id = "Column " + p.Column_Num + " ",
Text = v.Column_Description
};
return query.Distinct().OrderBy(o => o.Value).AsQueryable();
Note the string literals - "Level " not 'Level '. The code has to be valid C# first.
(Assuming Level_Num and Column_Num are numbers, I can't see why it would make sense to trim them.)