I need to create data files from our OpenEdge database for import to another system. The files are required to have no formatting or delimiters but to use fixed length fields. For example, the importing system is looking for something like what is below, where each field always starts at same place in the file, regardless of the length of the data or even if there is data in that field.
For example, if I export the a temp-table called "contact" that contains first-name, last-name, city, state, spouse-name, and favorite-color, I need the first name to always start on position 1, the last name to always start on position 16, the city to always start on position 31, and so on. It should look like:
Jane Doe Acme NY John Blue
Joe Sixpack Spingfield IL Grey
I can use PUT UNFORMATTED to get rid of the double-quotes around CHAR fields and export without delimiters, but have not been able to force each field to start at the exact same position each time. It comes out looking like:
JaneDoeAcmeNYJohnBlue
JoeSixpackSpringfieldILGrey
Is there a way to do this?
What I've been doing is:
DEF TEMP-TABLE contact
FIELD first-name as CHAR FORMAT "x(15)"
FIELD last-name as CHAR FORMAT "x(15)"
FIELD city as CHAR FORMAT "x(12)"
......
FOR EACH CONTACT:
PUT UNFORMATTED first-name last-name city....
END.
You are so close. Just remove UNFORMATTED and you're there...
UNFORMATTED tells you just that - ignore the format.
Related
I have read data from a csv file containing many duplicate email addresses into a temp table. The format is essentially id, emailtype-description, email.
Here is an example of some data:
id emailtype-description email
1 E-Mail john#gmail.com
1 preferred E-mail john#gmail.com
2 2nd E-mail stacey#yahoo.com
2 preferred-Email sth#yahoo.com
2 family E-Mail sth#yahoo.com
cInputFile = SUBSTITUTE(cDataDirectory, "Emails").
INPUT STREAM csv FROM VALUE(cInputFile).
IMPORT STREAM csv DELIMITER "," ^ NO-ERROR.
REPEAT TRANSACTION:
CREATE ttEmail.
IMPORT STREAM csv DELIMITER ","
ttEmail.uniqueid
ttEmail.emailTypeDescription
ttEmail.emailAddr
.
END.
INPUT STREAM csv CLOSE.
I want to dedupe the rows, but I don't want to do this randomly. I want to make sure that certain types take priority over others. For instance, some are marked with the type "preferred E-mail" and those should always remain if they exist, additional types take precedent over others, so "E-mail" will take precedent over "2nd-Email" or "family E-Mail".
I'd like to do in Progress code the equivalent of a custom sort of emailtype-description, then a de-dupe. That way I could define the sort order and then dedupe to retain the emails and the types by priority.
Is there a way to do this to my table in Progress? I want to sort first by uniqueid, then by emailtype-description, but I want a custom sort, not an alphabetical sort. What is the best approach?
When you say that you want a custom sort, not alphabetical do you mean that you want to sort by the emailtype in a non-alphabetical way? If so then I think that you would need to translate the email type into a field that sorts the way that you wish. Something along these lines:
/* first add a field to your ttEmail called emailTypeSortOrder */
define variable emailTypeSortOrderList as character no-undo.
emailTypeSortOrderList = "preferred E-mail,E-mail,2nd-Email,family E-mail".
cInputFile = SUBSTITUTE(cDataDirectory, "Emails").
INPUT STREAM csv FROM VALUE(cInputFile).
IMPORT STREAM csv DELIMITER "," ^ NO-ERROR.
REPEAT TRANSACTION:
CREATE ttEmail.
IMPORT STREAM csv DELIMITER ","
ttEmail.uniqueid
ttEmail.emailTypeDescription
ttEmail.emailAddr
.
/* classify the email type sort order
*/
ttEmail.emailTypeSortOrder = lookup( emailTypeDescription, emailTypeSortOrderList ).
if ttEmail.emailTypeSortOrder <= 0 then emailTypeSortOrder = 9999999.
END.
INPUT STREAM csv CLOSE.
And now you can sort and de-duplicate using the newly ordered field:
for each ttEmail break by ttEmail.emailAddr by ttEmail.emailTypeSortOrder:
if first-of( ttEmail.emailAddr ) then
next. /* always keep the first one */
else
delete ttEmail. /* remove unwanted duplicates... */
end.
How do you let user input a lengthy string into a variable?
I know this is trivial but I haven't been able to achieve it yet.
Here is what I've tried :
DEF VAR filter AS CHAR NO-UNDO.
UPDATE filter.
The value was always truncated to only a few characters. So, I've tried adding a format like so.
UPDATE filter FORMAT "X(318)":U.
Which give error
FILL-IN filter will not fit in FRAME
This program is only used by power user, so it doesn't have a frame to make thing pretty.
The basic console is all that is needed.
318 characters would have been better than nothing, but it would still not be ideal because user may copy-paste a longer string. Note that user wouldn't not paste any string that exceed 32000 characters.
Here is what the user input would looks like.
value1,value2,value3,value4,value5,value6,value7,value8,value9,value10,value11
I occasionally use something along these lines:
/* editlong.p
*
*/
define variable longText as character no-undo format "x(1000)"
view-as fill-in size 40 by 1
label "Long Text"
.
update longText "...".
The format "x(1000)" could just as easily be format "x(32000)". But whatever it is, it will be the hard limit on what someone can enter.
You could also do multi-line entry like this:
define variable longText as character no-undo format "x(1000)"
view-as editor inner-chars 30 inner-lines 5
large no-word-wrap
label "Long Text"
.
update longText "...".
I use below code and its working fine. I don't want to change temp table field(dActiveDate) type but please help me to change the date format.
Note - Date format can be changed by user. It can be YY/MM/DD or DD/MM/YYYY or MM/DD/YY and so on...
DEFINE TEMP-TABLE tt_data NO-UNDO
FIELD cName AS CHARACTER
FIELD dActiveDate AS DATE.
CREATE tt_data.
ASSIGN
tt_data.cName = "David"
dActiveDate = TODAY
.
OUTPUT TO value("C:\Users\ast\Documents\QRF\data.csv").
PUT UNFORMATTED "Name,Activedate" SKIP.
FOR EACH tt_data NO-LOCK:
EXPORT DELIMITER "," tt_data. /* There are more than 15 fields available so using export delimeter helps to have less lines of code*/
END.
OUTPUT CLOSE.
As this a "part two" of this question: How to change date format based on variable initial value? why not build on the answer there?
Wrap the dateformat part in a function/procedure/method and call it in the EXPORT statement. The only change required will be to specify each field rather than just the temp-table.
EXPORT DELIMITER ","
dateformat(tt_data.dactivedate, cDateFormat)
tt_data.cName
This assumes that there's a function called dateformat that takes the date and format and returns a string with the formatted date (as in the previous question).
"and so on..." needs to be specified. Depending on the specification you may have to resort to a custom function like Jensd's answer.
If you can constrain the formats allowed, you can use normal handling by using:
session:date-format = "ymd" / "mdy" / "dmy".
session:year-offset = 1 / 1950. // for four vs two digit year
How you populate these two variables can be done in similar fashion as in the other question.
You may need to reset these session attributes to their initial state in a finally block.
I'm coming from a Java/.NET background and trying to learn ABL but the difference in structure and the limited information on the internet is making it hard. What I want to do is import data from a text file which is in the following format:
john smith 52 ceo
...
line by line, and take the different parts based on the position of the character. For example, positions 1-10 are for the first name, 10-20 second name and so on... Do I have to use entry for that? If so can someone more experienced give an example how to do it cause I'm quite confused. Then I need to add a record for each line to a temp-table I have created called tt-employee. How do I go about doing that?
I apologise if my question is a bit vague but as I said, I am new to this so I'm still figuring things out.
If space is a delimiter you can use the IMPORT statement.
DEFINE TEMP-TABLE tt-employee NO-UNDO
FIELD firstname AS CHARACTER
FIELD lastname AS CHARACTER
FIELD age AS INTEGER
FIELD empTitle AS CHARACTER.
INPUT FROM c:\temp\indata.dat.
REPEAT:
CREATE tt-employee.
IMPORT DELIMITER " " tt-employee.
END.
INPUT CLOSE.
However if there isn't a delimiter but rather a fixed record with (as you mention) you can do something like this (error checking and correct record lengths needs to be applied).
/* Skipping temp-table definition - copy-paste from above */
DEFINE VARIABLE cRow AS CHARACTER NO-UNDO.
INPUT FROM c:\temp\indata.dat.
REPEAT:
IMPORT UNFORMATTED cRow.
/* You could replace 0 with a higher number that qualifies a record so
SUBSTRING doesn't return an error if reading past end of line */
IF LENGTH(cRow) > 0 THEN DO:
CREATE tt-employee.
ASSIGN
tt-employee.firstname = SUBSTRING(cRow, 1, 10)
tt-employee.lastname = SUBSTRING(cRow, 11, 10)
tt-employee.age = INTEGER(SUBSTRING(cRow, 21, 2))
tt-employee.empTitle = SUBSTRING(cRow, 23, 10) NO-ERROR.
END.
END.
INPUT CLOSE.
There are several places on the web to look for OpenEdge information:
Official knowledgebase - http://knowledgebase.progress.com/
Official community - https://community.progress.com/?Redirected=true
More communities - http://www.progresstalk.com/ and http://oehive.org/
I have several Wordpress HTML pages for import through CSV/excel. One of the fields is content for the Wordpress page. Since these pages are all the same except for in 3 places (2 names, 1 IMG URL) I'm trying to be efficient and upload an excel with custom fields.
What I'd like to do is merge the IMG urls and Product Names into the appropriate spot in the Excel cell text so it's imported as a complete page. I'm trying to avoid all the cutting and pasting when adding 100's of similar pages with only a few different spots.
Any tips or advice on where I can accomplish this? I haven't been able to figure it out or find help online.
Cell Data Example:
<div id="productimage" style="float:left;width:380px;">
<img alt="alternate" src="imagesource" />
</div>
<div id="productspecs" style="float:left;padding-left:25px;">
<h2><strong>Product Name</strong></h2>
</div>
"Product Name", "alternate", and "imagesource" I have fields for in a spreadsheet .. I just don't know how to merge them into this Cell Data Example to auto-populate these new pages.
Thanks!
If I understand your question correctly, you have html in an Excel cell and you want to make parts of that html dynamic by referencing content in other cells of the workbook.
I assume that in your example you want to make the imagesource and the Product Name dynamic.
You can copy and paste the html into the Excel formula editor. You can increase its height, so you see more than one line at a time. The formula editor can handle line breaks.
If you want to build a string that contains double quotes, you will need to use two double quotes if the quote is inside the string and three double quotes in a row if it is at the beginning or end of a string. You can use the ampersand to concatenate strings and cell references.
With your specific example above, the formula in Excel would read somewhere along these lines (replace Sheet2!A2 etc. with the cell that holds your data. Arrange that data in a table with a row for each product, then you can copy this formula down to get the desired result.
="<div id=""productimage"" style=""float:left;width:380px;"">
<img alt=""alternate"" src="""&Sheet2!A2&""" />
</div>
<div id=""productspecs"" style=""float:left;padding-left:25px;"">
<h2><strong>"&Sheet2!B2&"</strong></h2>
</div>"
Turn on "Wrap Text" in the cell format, otherwise you will see it all in one line of code. The screenshot below uses two rows of data with different texts for image source and product name in sheet 2.
EDIT: I tried to post this in a comment, but the double and triple quotes don't make it and get replaced with just one quote.
Also, you managed to delete some of the & signs that concatenate the different strings. Please look again at the original formula I've posted. Replace the cell references with yours, but don't mangle the code. The principle is this:
="First String"&A1&"Next String"
If the string has quotes inside, double them
="He said "Please" but nobody heard him"&A1&"next string"
If the string has quotes at the beginning of the string, then you need the opening quote for the string and the double quote for the quote inside the string. Likewise for quotes at the end of the string: duplicate the quote in the string and then add the closing quote.
="""Please" - he said"&A1&"and she answered "OK."""