Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsFormsForms ProgrammingQueriesModules / DAO / VBAReports / PrintingMacrosDatabase DesignSecurityConversionImporting / LinkingSQL Server / ADPMultiuser / NetworkingReplicationSetup / ConfigurationDeveloper ToolkitsActiveX ControlsNew UsersGeneral 1General 2
Access DirectoryToolsTutorialsUser Groups
Related Topics
SQL ServerOther DB ProductsMS OfficeMore Topics ...

MS Access Forum / New Users / July 2006

Tip: Looking for answers? Try searching our database.

Import Horizontal Text Data, Change to Vertical

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Ronster - 24 Jul 2006 19:11 GMT
I need to import a monthly expense text file into Access with the
following layout:

Field1 - SSN
Field2 - Name
Field3 - Month Ending

Starting at Field4 are 20 sets of expense data that requires 4 fields
each (80 fields total).  One row per employee.

FieldXX(1st) - Expense Date
FieldXX(2nd) - Expense Description
FieldXX(3rd) - Expense Code
FieldXX(4th) - Expense Amount

The next set of fields are the same, 20 sets total.  No, I can't get
the company to change the setup on this text file.  I wish.

I need to convert this horizontal data to vertical.  One way that seems
to work is running 20 different queries that always pulls field 1,2 and
3, then the next set of expense data.  For example Query1 pulls fields
1,2,3,4,5,6,7, Query2 pulls fields 1,2,3,8,9,10,11.  I then APPEND this
data to a predefined TABLE called Expense_DB.  I end up with all 20
sets fitting into a 7 field table, which is what I want.

My question is there must be an easier way to do this but I'm a newbie
and can't see any other way to get what I want.  Any ideas?
Duane Hookom - 24 Jul 2006 19:21 GMT
Have you considered a union query?

Signature

Duane Hookom
MS Access MVP

>I need to import a monthly expense text file into Access with the
> following layout:
[quoted text clipped - 23 lines]
> My question is there must be an easier way to do this but I'm a newbie
> and can't see any other way to get what I want.  Any ideas?
John Spencer - 24 Jul 2006 20:02 GMT
Import the data into a work table then use something like the following on a
table built.  This code is not fully developed, but it may help you.  USE IT
ON A COPY of your data.

Post back if you have problems with it.

Create a Destination table with the following 7 fields
SSN
EmployeeName
MonthEnding
ExpenseDate
ExpenseDescription
ExpenseCode
ExpenseAmount

After saving the code in a module, call the function in the immediate window
or from a code with"
   fMakeNormalizedTable "TheImportedTable", "TheDestinationTable", 3,0,0,4,
True

'================= CODE Begins =====================
'Turn non-normalized data (repeating fields) into a normalized table

Public Function fMakeNormalizedTable(strSource, strDestination _
        , intCountIdColumns _
        , Optional intStartField = 0, Optional intStopField = 0 _
        , Optional intGroupSize = 1 _
        , Optional tfIncludeNulls As Boolean = False)
'===============================================================================
' Procedure : fMakeNormalizedTable
' DateTime  : 5/11/2006 07:39
' Author    : John Spencer
' CopyRight: John Spencer
' Purpose   : Take a non-normalized table with repeating columns and
normalize
' the table.  Source table structure is expected to be one to n identifier
columns
' followed by many repeating columns.  For example
' FirstName LastName WorkPhone HomePhone MobilePhone FaxPhone AlternatePhone
' Destination table should already exist and should have a structure similar
to
' the source table.  The structure would be something like
' the Identifier fields, a field to hold the source's field name, and a
field to
' hold the data in the repeating fields.  For example
' FirstName LastName  PhoneType   PhoneNumber

'------------------------------------------------------------------------------
' strSource = Name of table with data
' strDestination = Name of destination table
' intCountIdColumns = number of identifier columns
' intStopField = Last Column to be used in building populating destination
table
' intStartField = First repeating column
' intGroupSize = Allows for regular group size (x columns in each group)
'                 # Gum Sold, Flavor
'                 # Chiclets, ChicletFlavor;  #Wrigley, WrigleyFlavor
' tfIncludeNulls = If True then make records for fields where the value is
null
'===============================================================================

Dim dbAny As DAO.Database
Dim strSqlBase As String, strSql As String, strSQLTarget As String
Dim strBuildTableSQL As String
Dim intLoop As Integer
Dim strFieldName As String
Dim rstAny As DAO.Recordset
Dim intLoop2 As Integer
Dim strAdd As String

Static iErrCount As Integer

  On Error GoTo ERROR_fMakeNormalizedTable
  '---------------------------------------------------------------
  ' Future Code Enhancements:
  ' -- Add ability to skip keyfield column in destination table
  ' -- add ability to start at any column in source table
  '---------------------------------------------------------------
  Set dbAny = CurrentDb()

  '------------------------------------------------------------------------------
  ' Determine number of times to loop
  '------------------------------------------------------------------------------
  iErrCount = 1   'set ierrCount to force stop
  If intStopField = 0 Or intStopField >
dbAny.TableDefs(strSource).Fields.Count Then
     intStopField = dbAny.TableDefs(strSource).Fields.Count - 1
  Else
     intStopField = intStopField - 1
  End If

  If intStartField > intStopField Then
     MsgBox "Stop! Start field is after stop field.", , "Please fix"
     Exit Function
  End If

  If intStartField = 0 Or intStartField < intCountIdColumns Then
     intStartField = intCountIdColumns
  Else
     intStartField = intStartField - 1
  End If

  'Check numbers to make sure they work
  If intGroupSize <> 1 Then
     If (1 + intStopField - intStartField) Mod intGroupSize <> 0 Then
        'adjust intstopfield down
        intStopField = intStopField - (1 + intStopField - intStartField)
Mod intGroupSize <> 0
     End If
  End If

  '------------------------------------------------------------------------------
  ' Get field names in destination Table and build insert statement
  '------------------------------------------------------------------------------
  iErrCount = 0   'initialize errCount
  With dbAny.TableDefs(strDestination)   'if this errors then attempt to
build table

     For intLoop = 0 To .Fields.Count - 1
        strSQLTarget = strSQLTarget & ", [" & .Fields(intLoop).name & "]"
     Next intLoop
  End With    'dbAny.TableDefs(strDestination)

  strSQLTarget = Mid(strSQLTarget, 3) 'Strip off beginning ", "
  strSQLTarget = "INSERT INTO [" & strDestination & "] (" & _
                 strSQLTarget & ") "

  'Build SELECT clause for SELECT query portion of Insert query

  'Add Identifier fields
  With dbAny.TableDefs(strSource)
     If .Fields.Count < intCountIdColumns + 1 Then
        MsgBox "Not enough fields in destination table", , "Sorry"
        Exit Function
     End If

     strAdd = vbNullString
     For intLoop = 0 To intCountIdColumns - 1
        strAdd = strAdd & ", [" & .Fields(intLoop).name & "]"
     Next intLoop

     strSqlBase = "SELECT " & Mid(strAdd, 3) 'Strip off beginning ", "

  'Populate the table
  For intLoop = intStartField To intStopField Step intGroupSize
     strSql = vbNullString
     strAdd = vbNullString
     For intLoop2 = 0 To intGroupSize - 1
        strFieldName = .Fields(intLoop + intLoop2).name
        strAdd = strAdd & ", """ & strFieldName & """, " & _
              "[" & strFieldName & "] "

     Next intLoop2

     strSql = strAdd & " FROM [" & strSource & "] "
     strAdd = vbNullString

     If tfIncludeNulls = False Then
        'Build where clause if nulls are to be excluded
        For intLoop2 = 0 To intGroupSize - 1
           strFieldName = .Fields(intLoop + intLoop2).name
           strAdd = strAdd & "[" & strFieldName & "] is not Null OR "
        Next intLoop2
        strSql = strSql & " WHERE " & Left(strAdd, Len(strAdd) - 4) 'Strip
off last Or
     End If

     strSql = strSQLTarget & " " & strSqlBase & " " & strSql

     dbAny.Execute strSql, dbFailOnError

  Next intLoop

  End With

EXIT_fMakeNormalizedTable:
  On Error GoTo 0
  Exit Function

ERROR_fMakeNormalizedTable:
  If Err.Number = 3265 And iErrCount = 0 Then
     iErrCount = iErrCount + 1
'------------------------------------------------------------------------------
' Build the destination table based on the source table
'------------------------------------------------------------------------------
     'Identifier fields
     With dbAny.TableDefs(strSource)
        For intLoop = 0 To intCountIdColumns - 1
           strBuildTableSQL = strBuildTableSQL & ", " & _
              .Fields(intLoop).name & " " &
fGetFieldTypeName(.Fields(intLoop).Type)
        Next intLoop

        'Repeating value fields
        For intLoop = intStartField To intStartField + intGroupSize - 1
           strBuildTableSQL = strBuildTableSQL & ", " & _
              .Fields(intLoop).name & " Text(64)"

           strBuildTableSQL = strBuildTableSQL & ", " & _
              .Fields(intLoop).name & "Value " & _
                 fGetFieldTypeName(.Fields(intStartField).Type)
        Next intLoop

        strBuildTableSQL = Mid(strBuildTableSQL, 3)

        strBuildTableSQL = "Create Table " & strDestination & _
           "( " & strBuildTableSQL & ")"
        dbAny.Execute strBuildTableSQL, dbFailOnError

     End With

     dbAny.TableDefs.Refresh
     Resume
  Else
     MsgBox "Error " & Err.Number & vbCrLf & Err.Description & vbCrLf & _
          " in procedure fMakeNormalizedTable"
     Err.Clear
  End If
Stop: Resume   'Debug purposes only.  Remove from final code
End Function

Private Function fGetFieldTypeName(fldAnyType) As String
'returns string field type
Dim strAny As String
  Select Case fldAnyType
'     Case dbBigInt
'        strAny = "Big Integer"
     Case dbBinary
        strAny = "Binary"
     Case dbBoolean
        strAny = "Boolean"
     Case dbByte
        strAny = "Byte"
'     Case dbChar
'        strAny = "Char"
     Case dbCurrency
        strAny = "Currency"
     Case dbDate
        strAny = "DateTime"
     Case dbDecimal
        strAny = "Decimal"
     Case dbDouble
        strAny = "Double"
     Case dbFloat
        strAny = "Double"
     Case dbGUID
        strAny = "GUID"
     Case dbInteger
        strAny = "Integer"
     Case dbLong
        strAny = "Long"
'      Case dbLongBinary
'         strAny = "Long Binary (OLE Object)"
     Case dbMemo
        strAny = "Memo"
     Case dbNumeric
        strAny = "Numeric"
     Case dbSingle
        strAny = "Single"
     Case dbText
        strAny = "Text"
     Case dbTime
        strAny = "Time"
'      Case dbTimeStamp
'         strAny = "Time Stamp"
'      Case dbVarBinary
'         strAny = "VarBinary"
'      Case Else
'         strAny = "Unknown Type"
  End Select

  fGetFieldTypeName = strAny

End Function
>I need to import a monthly expense text file into Access with the
> following layout:
[quoted text clipped - 23 lines]
> My question is there must be an easier way to do this but I'm a newbie
> and can't see any other way to get what I want.  Any ideas?
Ronster - 24 Jul 2006 23:00 GMT
The above looks like it has possibilities but I can't get it to run.  I
tried what you wrote in the code:

fMakeNormalizedTable "Deductions_1", "DeductNormal", 3, 4, 60, 3, True

(I have 3 repeat fields not 4)

Deductions_1 is the import table and DeductNormal is the 7 field table
that is empty.

I keep getting a 3346 error, "Number of Query Values and Destination
fields are not the same."  I have 6 fields in my destination table and
the first 6 fields in the my import table are the same.  Groups start
repeating at column 4.  4,5,6 then 7,8,9, etc.  I tried running the
following but got same eror:

fMakeNormalizedTable "Deductions_1", "DeductNormal", 3, 4, 9, 3, True

Number of Identifier fields - 3
First field to start repeat - 4
Last field to stop repeat - 9
Number of repeat fields - 3

What am I doing wrong?
Ronster - 25 Jul 2006 18:43 GMT
I decided to try a UNION query but I keep getting that SYNTAX ERROR IN
FROM CLAUSE on the following code (this is my first UNION query):

SELECT [SSN], [Last], [PeriodDate], [VendCode], [Type], [Amount]
FROM Deductions_1
UNION ALL
SELECT [SSN], [Last], [PayPeriodDate], [Vendor_Code], [VendorType],
[VendorAmount]
FROM DeductNormal
SELECT [SSN], [Last], [PeriodDate], [VendCode2], [Type2], [Amount2]
FROM Deductions_1
UNION ALL
SELECT [SSN], [Last], [PayPeriodDate], [Vendor_Code], [VendorType],
[VendorAmount]
FROM DeductNormal;

Runs OK if I use only one SELECT.  I still need to add another 18
SELECTs to move all the data to my DeductNormal table.

Any ideas on this one?
Duane Hookom - 26 Jul 2006 02:43 GMT
You are missing a UNION ALL in the middle.

Signature

Duane Hookom
MS Access MVP

>I decided to try a UNION query but I keep getting that SYNTAX ERROR IN
> FROM CLAUSE on the following code (this is my first UNION query):
[quoted text clipped - 16 lines]
>
> Any ideas on this one?
Ronster - 26 Jul 2006 16:54 GMT
> You are missing a UNION ALL in the middle.
>
[quoted text clipped - 22 lines]
> >
> > Any ideas on this one?

Thank you.  Posting corrected code.

SELECT [SSN], [Last], [PeriodDate], [VendCode], [Type], [Amount]
FROM Deductions_1
UNION ALL SELECT [SSN], [Last], [PayPeriodDate], [Vendor_Code],
[VendorType], [VendorAmount]
FROM DeductNormal
UNION ALL SELECT [SSN], [Last], [PeriodDate], [VendCode2], [Type2],
[Amount2]
FROM Deductions_1
UNION ALL SELECT [SSN], [Last], [PayPeriodDate], [Vendor_Code],
[VendorType], [VendorAmount]
FROM DeductNormal;
Duane Hookom - 26 Jul 2006 20:49 GMT
Are we to assume you have your issue resolved?

Signature

Duane Hookom
MS Access MVP

>> You are missing a UNION ALL in the middle.
>>
[quoted text clipped - 36 lines]
> [VendorType], [VendorAmount]
> FROM DeductNormal;
Ronster - 26 Jul 2006 22:08 GMT
Yes.  Works great.  Thank you.

> Are we to assume you have your issue resolved?
>
[quoted text clipped - 42 lines]
> > [VendorType], [VendorAmount]
> > FROM DeductNormal;
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.