Visual Basic 6 and dbf: issues with 'join' and 'where' - sql

I need to modify an old vb6 application that needs to import some data from a dBase IV database.
In the past the selection query involved a single table (dbf file) and used to work perfectly.
Now i need to edit this query to introduce a join on a second table, using multiple fields.
This is a simplified version of my code:
Dim cnn As New Connection
Dim rs As New Recordset
Dim sql As String
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Extended properties=dBase IV;Data source=d:\100\db;"
sql = "..." 'see below!
rs.CursorLocation = adUseClient
rs.Open sql, cnn, adOpenDynamic, adLockOptimistic
debug.print rs.RecordCount
rs.Close
cnn.Close
These two tables have a typical master-detail structure; I checked the db documentation and inspected TABFAT01 and TABFAT02, so I can assume that:
Join between these tables is [TABFAT01] 1 <-> n [TABFAT02], and is done on
TIPDOC (text), ANNDOC (text) and NUMDOC (numeric) fields.
Each row in TABFAT01 has at least 1 joined row in TABFAT02.
Each row in TABFAT02 has 1 joined row in TABFAT02.
TABFAT01 has 63 records.
TABFAT02 has 907 records.
First issue
My first query is:
select t.TIPDOC, t.NUMDOC, t.ANNDOC, t.DATDOC, t.LIBER03, c.LIBER04
from TABFAT01 t inner join
TABFAT02 c on t.TIPDOC = c.TIPDOC and t.ANNDOC = c.ANNDOC and t.NUMDOC = c.NUMDOC
This query returns 0 records.
If I change conditions order this way:
select t.TIPDOC, t.NUMDOC, t.ANNDOC, t.DATDOC, t.LIBER03, c.LIBER04
from TABFAT01 t inner join
TABFAT02 c on t.ANNDOC = c.ANNDOC and t.NUMDOC = c.NUMDOC and t.TIPDOC = c.TIPDOC
the query returns 907 records.
I don't understand how and why conditions order has impact on query results.
Second issue
If I add a where clause:
select t.TIPDOC, t.NUMDOC, t.ANNDOC, t.DATDOC, t.LIBER03, c.LIBER04
from TABFAT01 t inner join
TABFAT02 c on t.ANNDOC = c.ANNDOC and t.NUMDOC = c.NUMDOC and t.TIPDOC = c.TIPDOC
where c.LIBER04 = 'a'
the query returns 0 records.
However, if I run this query:
select * from TABFAT02 c where LIBER04 = 'a'
it returns 1 record, with TIPDOC = 'F2', ANNDOC = '2018', NUMDOC = 1854.
A subsequent query:
select * from TABFAT01 t where t.TIPDOC = 'F2' and t.ANNDOC = '2018' and t.NUMDOC = 1854
returns 1 record, as expected.
This happens for every field I tried to put in where clause with joined tables, except TIPDOC.
If I filter by TIPDOC, results are correct.
Third issue
The first time I run my code after opening vb6 IDE it gives the following error:
Run-time error '-2147467259 (80004005)': Selected Collating sequence Not Supported by the operating system.
(I actually use the Italian version of vb6, and the original error message says "Sequenza di ordinamento selezionata non supportata dal sistema operativo.".
I guess that the message I written above is the right match for the English version.)
This error is not displayed on subsequent runs, until I close and reopen vb6.

I agree with thx1138v2 about not specifically using the Jet OleDB driver, but one more specific to the source. You mention dBASE IV. Is this accurate or is it really with Visual FoxPro. You could confirm if the table has indexes and note (memo) fields the file names would be suffixed as
YourTable.dbf (actual table)
YourTable.cdx (compound index file)
YourTable.fpt (notes/memo file content is table has such columns).
Having confirmed, and if it IS Visual Foxpro, I would get the Microsoft driver directly from Microsoft
If the data table is being updated from a source outside VFP, then it is possible that the indexes may be out of sync as the other drivers won't necessarily open the index file (cdx) correctly to keep the new records in synch. So when trying to do the join based on one series of join clauses it does use the non-synched index. But changing the order forces to default to the natural order, thus seeing all possible records to resolve.
See and hopefully this makes sense and helps to tune-in on the missing link in your querying issue.

First clear up your error message. "Selected Collating sequence Not Supported by the operating system." probably means you didn't specify a collating sequence or the Jet.OLEDB driver doesn't support whatever collating sequence you specified.
I never got the Jet.OLEDB drivers to work with my application. My guess is because the files I was dealing with were created by FoxPro. So I used the Visual Fox Pro ODBC drivers. Here's an example connection.
"DSN=BCLVariance;UID=;SourceDB=C:\AMSI\BCLTemp;SourceType=DBF;Exclusive=Yes;BackgroundFetch=No;Collate=Machine;Null=Yes;Deleted=Yes;"
You will see that it allows you to control various parameters that you aren't controlling in your Jet.OLEDB connection string. The ODBC data source is setup under System Data Sources tab in ODBC Data Source Administrator.
I never understood exactly why but the sequence you state the table names in a SQL query does make a difference. It has to do with how the internal query interpreter handles them. You need to specify the detail table first and the master is joined to the detail. Like this:
select t.TIPDOC, t.NUMDOC, t.ANNDOC, t.DATDOC, t.LIBER03, c.LIBER04
from TABFAT02 c inner join
TABFAT01 t on t.TIPDOC = c.TIPDOC and t.ANNDOC = c.ANNDOC and t.NUMDOC = c.NUMDOC
That may also clear up your other problems. Give it a try.
BTW, you'll also need to change your initial code to:
if Not rs.BOF then
rs.MoveLast
debug.print "rs.RecordCount=";rs.RecordCount
else
debug.print "rs.BOF = True"
end if

Related

SQL code using 'as' resulting in not being able to run

SQL microsoft server
I’m quite close with this piece of code… having said that I haven’t got it to run successfully yet… there seems to be issues with me naming ‘tableabc’ (At the end of the first ‘from’).
Ie the line: WHERE R.PE.d_R_month = (SELECT MAX(d_R_month) FROM R.PE)) AS tableabc
The error I am getting is: “The column 'id' was specified multiple times for 'tableabc'.”
Just for a bit of context, the code does the following:
‘tableabc’ left joins to A.PS table, based on different conditions (As listed).
(I have named the following output as ‘tableabc’. A new column in the R.PAS table is added (and is a summation of the ‘date and month’ creating a column called ‘newdate.’) It then right joins to another table (R.PE) and there are additional conditions applied (ie the maximum dates are only shown)
Select
A.PS.id,
A.PS.name,
A.PS.current_phase,
A.PS.asset_id,
A.PS.production_category,
tableabc.*
FROM
(select R.PAS.*, R.PE.*, DATEADD(month, [R].[PAS].[months_accelerated], [R].[PE].[d_date]) as 'newdate'
from R.PAS
Right join R.PE
On [R].[PAS].[id] = [R].[PE].[id]
WHERE R.PE.d_R_month = (SELECT MAX(d_R_month) FROM R.PE)) AS tableabc
LEFT JOIN A.PS
ON tableabc.id = A.PS.id
Where A.PS.prod = 'Include' OR A.PS.R_category <> 'Can' or A.PS.R_category <> 'Hold';

Oracle non Ansi to Ansi T-SQL

I am a SQL server guy, with limited Oracle coding. I have inherited a bunch of views that I need to convert to ANSI. What I am looking for is someone to educate me, if possible, on a systematic way to do this in steps. I have junior guys that would read and understand TSQL style code, instead of the way it is. I want to take this knowledge, and have them start working on them; there are many. A conversion tool will not work, we don't have time to play with one, no budget to buy it, and our IT department will not let us install anything. (We have to do this manually)
I would like to know the steps (systematic approach) based on interpreting the code, not learn the data or try to understand why the existing code was written the way it was.
For example, are these the steps:
Reorder the tables to match how they are in the where clause.
Separate the lines in the where clause based on their table, so that it is easier to read.
Replace the Oracle join operators with left, right, outer, etc.
Leave the lines with defined values in the where clause, or should I include them with an "AND" in the table join.
This task will be done by junior SQL server guys, so it has to be as simple and straight forward as possible.
FROM WORK MECHANISMS WM,
WT_MANPOWER_RESOURCES WTMR,
LOGICAL_ITEMS LI,
APSWHS.WMX_LOG_REL_ELEM WLRE,
WMECH_DSGN_COMP_ELEMENTS WDCE,
WORK_TASKS WT,
persons_v per,
APSWHS.WMX_WO_WF_STATUS WFA,
RT_DETAILS RTD
WHERE
WFA.WF_SEQ > 639
AND WTMR.WTASK_WMECH_DB_ID = WM.DB_ID
AND WTMR.WTASK_DB_ID = 0
AND WTMR.WTMANPOW_TYPE = ‘LEAD’
AND WT.WMECH_DB_ID = WM.DB_ID
AND WT. DB_ID= 0
AND WFA.WM_DB_ID = WM.DB_ID
AND PER.per_db_id = wm.assigned_to_per_db_id
AND RTD.WMECH_DB_ID = WM.DB_ID
AND WDCE .WMECH_DB_ID = WFA.WM_DB_ID
AND WDCE.LITM_ID = WLRE.LITM_ID
AND WDCE.LITM_ID = LI.ID
AND WDCE.PRIMARY_DCID_FLAG = ‘Y’
I'm assuming that you want to migrate from table lists (join predicates in WHERE clause) to ANSI JOIN syntax. This has nothing to do with T-SQL.
Ideally, you'll take an ERD and check in what order the tables should be listed, visually. I personally find that easier than from mere text. Although, it is possible to do with plain text as well. Here are the steps:
Take the first table and all its non-join predicates:
FROM WORK_MECHANISMS WM
WHERE 1 = 1 -- No predicates on this table
Take the next table that you can join to the first one, and all of its join and non-join predicates
FROM WORK_MECHANISMS WM
JOIN WT_MANPOWER_RESOURCES WTMR
ON WTMR.WTASK_WMECH_DB_ID = WM.DB_ID
WHERE WTMR.WTASK_DB_ID = 0
AND WTRM.WTMANPOW_TYPE = 'LEAD'
And the next table...
Observe that this isn't the next table in your original table list, but another one, i.e. the next one that can be joined to the existing join graph without creating a cartesian product. In particular, I skipped (for now) LOGICAL_ITEMS and APSWHS.WMX_LOG_REL_ELEM and WMECH_DSGN_COMP_ELEMENTS. I will add them to the graph later.
FROM WORK_MECHANISMS WM
JOIN WT_MANPOWER_RESOURCES WTMR
ON WTMR.WTASK_WMECH_DB_ID = WM.DB_ID
JOIN WORK_TASKS WT
ON WT.WMECH_DB_ID = WM.DB_ID
WHERE WTMR.WTASK_DB_ID = 0
AND WTRM.WTMANPOW_TYPE = 'LEAD'
AND WT.DB_ID = 0
And the next table...
You continue adding tables to your new statement, until you've added all tables. If you ever encounter a (+) operator, "just" get the LEFT JOIN semantics right.

Query with multiple Left Joins to ODBC tables fails

I posted this originally without all the ODBC information. After further investigation the problem appears to the ODBC related. Given the change, I wanted to report and see if an ODBC guru might be "listening".
I have the following queries in Access...
Query #1
SELECT aa.DocNum, b.QualityClass
FROM dbo_TransferHistory AS aa LEFT JOIN PCQualityClass AS bb ON aa.DocNum = bb.DocumentNum
WHERE (((aa.DocNum)=[Enter Doc Num]));
Which I want to expand to...
Query #2
SELECT aa.DocNum, bb.QualityClass, cc.BldgCond
FROM (dbo_TransferHistory AS aa LEFT JOIN PCQualityClass AS bb ON aa.DocNum = bb.DocumentNum)
LEFT JOIN PCBldgCond AS cc ON aa.DocNum = cc.DocumentNum
WHERE (((aa.DocNum)=[Enter Doc Num]));
dbo_TransferHistory is an table I access through an ODBC connector.
PCQualityClass and PCBldgCond are two queries that are based off another ODBC table. The SQL for those queries is ...
Query for PCQualityClass
SELECT aa.DocumentNum, aa.Value AS QualityClass, aa.ResourceID, aa.BldgSeqNum
FROM dbo_PCBldgDetail AS aa
WHERE (((aa.DocumentNum)=[Enter Doc Num]) AND ((aa.ResourceID)="QualityClass") AND ((aa.BldgSeqNum)=[Enter Bldg Num]));
Query for PCBldgCond
SELECT aa.DocumentNum, aa.Value AS BldgCond, aa.BldgSeqNum, aa.ResourceID
FROM dbo_PCBldgDetail
WHERE (((aa.DocumentNum)=[Enter Doc Num]) AND ((aa.BldgSeqNum)=[Enter BldgNum]) AND ((aa.ResourceID)="Condition"));
DocNum and DocumentNum are the same type ("Short Text" and a length of 12) and while I would like to make the names the same, I cannot.
When the query is run, an Inputbox pops up and [Enter Doc Num] is replaced with the Document Number I want the data for.
The queries were created in Access using the Create Query tool. Access is willing to create the query and the SQL looks good.
The problem is that while Query #1 will work, Query #2 causes the error "Invalid Operation". As a note, if I take the first join out of query #2 and run the remainder as a single join, the query works.
Changing to inner joins will allow Query #2 to function but will cause issues as there are times that one or both of the two sub queries do not have data but I still need the data from the primary table.
Changing from ODBC tables to local tables solves the problem but is not a viable solution as the ODBC tables cannot be local.
Does anyone have any insight into the inter-workings of Access and ODBC? I have a hard time believing that I am the first person who has tried to build an Access/Odbc query with more than one join. Yet I have not been able to Google a solution to this problem.

MS Access-Return Record Below Current Record

I am very new to Access, and what I am trying to do seems like it should be very simple, but I can't seem to get it.
I am a structural engineer by trade and am making a database to design buildings.
My Diaphragm Analysis Table includes the fields "Floor_Name", "Story_Number", "Wall_Left", and "Wall_Right". I want to write a new query that looks in another query called "Shear_Wall_incremental_Deflection" and pulls information from it based on input from Diaphragm Analysis. I want to take the value in "Wall_Right" (SW01), find the corresponding value in "Shear_Wall_incremental_Deflection", and report the "Elastic_Deflection" corresponding to the "Story_Below" instead of the "Story_Number" in the Diaphragm Analysis Table. In the case where "Story_Number" = 1, "Story_Below" will be 0 and I want the output to be 0.
Same procedure for "Wall_Left", but I'm just taking it one step at a time.
It seems that I need to use a "DLookup" in the expression builder with TWO criteria, one that Wall_Right = Shear_Wall and one that Story_Number = Story_Below, but when I try this I just get errors.
"Shear_Wall_incremental_Deflection" includes shearwalls for all three stories, i.e. it starts at SW01 and goes through SWW for Story Number 3 and then starts again at SW01 for Story Number 2, and so on until Story Number 1. I only show a part of the query results in the image, but rest assured, there are "Elastic_Deflection" values for story numbers below 3.
Here is my attempt in the Expression Builder:
Right_Defl_in: IIf(IsNull([Diaphragm_Analysis]![Wall_Right]),0,DLookUp("[Elastic_Deflection_in]","[Shear_Wall_incremental_Deflection]","[Shear_Wall_incremental_Deflection]![Story_Below]=" & [Diaphragm_Analysis]![Story_Number]))
I know my join from Diaphragm_Analysis "Wall_Left" and "Wall_Right" must include all records from Diaphragm_Analysis and only those from "Shear_Wall_incremental_Deflection"![Shear_Walls] where the joined fields are equal, but that's about all I know.
Please let me know if I need to include more information or send out the database file.
Thanks for your help.
Diaphragm Analysis (Input Table)
Shear_Wall_incremental_Deflection (Partial Image of Query)
I think what you are missing is that you can and should join to Diaphragm_Analysis twice, first time to get the Story_Below value and second to use it to get the corresponding Elastic_Deflection value.
To handle the special case where Story_Below is zero, I would write a separate query (only requires one join this time) and 'OR together' the two queries using the UNION set operation (note the following SQL is untested):
SELECT swid.Floor_Name,
swid.Story_Number,
swid.Wall_Left,
da2.Elastic_Deflection AS Story_Below_Elastic_Deflection
FROM ( Shear_Wall_incremental_Deflection swid
INNER JOIN Diaphragm_Analysis da1
ON da1.ShearWall = swid.Wall_Left )
INNER JOIN Diaphragm_Analysis da2
ON da2.ShearWall = swid.Wall_Left
AND da2.Story_Number = da1.Story_Below
UNION
SELECT swid.Floor_Name,
swid.Story_Number,
swid.Wall_Left,
0 AS Story_Below_Elastic_Deflection
FROM Shear_Wall_incremental_Deflection swid
INNER JOIN Diaphragm_Analysis da1
ON da1.ShearWall = swid.Wall_Left
WHERE da1.Story_Below = 0;
I've assumed that there is no data where Story_Number is zero.

Access query returns empty fields depending on how table is linked

I've got an Access MDB I use for reporting that has linked table views from SQL Server 2005. I built a query that retrieves information off of a PO table and categorizes the line item depending on information from another table. I'm relatively certain the query was fine until approximately a month ago when we shifted from compatibility mode 80 to 90 on the Server as required by our primary application (which creates the data). I can't say this with 100% certainty, but that is the only major change made in the past 90 days. We noticed that suddenly data was not showing up in the query making the reports look odd.
This is a copy of the failing query:
SELECT dbo_porel.jobnum, dbo_joboper.opcode, dbo_porel.jobseqtype,
dbo_opmaster.shortchar01,
dbo_porel.ponum, dbo_porel.poline, dbo_podetail.unitcost
FROM ((dbo_porel
LEFT JOIN dbo_joboper ON (dbo_porel.assemblyseq = dbo_joboper.assemblyseq)
AND (dbo_porel.jobseq = dbo_joboper.oprseq)
AND (dbo_porel.jobnum = dbo_joboper.jobnum))
LEFT JOIN dbo_opmaster ON dbo_joboper.opcode = dbo_opmaster.opcode)
LEFT JOIN dbo_podetail ON (dbo_porel.poline = dbo_podetail.poline)
AND (dbo_porel.ponum = dbo_podetail.ponum)
WHERE (dbo_porel.jobnum="367000003")
It returns the following:
jobnum opcode jobseqtype shortchar01 ponum poline unitcost
367000003 S 6624 2 15
The query normally should have displayed a value for opcode and shortchar01. If I remove the linked table dbo_podetail, it properly displays data for these fields (although I obviously don't have unitcost anymore). At first I thought it might be a data issue, but I found if I nested the query and then linked the table, it worked fine.
For example the following code works perfectly:
SELECT qryTest.*, dbo_podetail.unitcost
FROM (
SELECT dbo_porel.jobnum, dbo_joboper.opcode, dbo_porel.jobseqtype,
dbo_opmaster.shortchar01, dbo_porel.ponum, dbo_porel.poline
FROM (dbo_porel
LEFT JOIN dbo_joboper ON (dbo_porel.jobnum=dbo_joboper.jobnum)
AND (dbo_porel.jobseq=dbo_joboper.oprseq)
AND (dbo_porel.assemblyseq=dbo_joboper.assemblyseq))
LEFT JOIN dbo_opmaster ON dbo_joboper.opcode=dbo_opmaster.opcode
WHERE (dbo_porel.jobnum="367000003")
) As qryTest
LEFT JOIN dbo_podetail ON (qryTest.poline = dbo_podetail.poline)
AND (qryTest.ponum = dbo_podetail.ponum)
I'm at a loss for why it works in the latter case and not in the first case. Worse yet, it seems to work intermittently for some records and not for others (it's consistent about the ones it does and does not work for).
Do any of you experts have any ideas?
You definitely need to use subqueries for multiple left/right joins in Access.
I think it's a limitation of the Jet optimizer that gets confused if you're just chaining left/right joins.
You can see that this is a recurrent problem that surfaces often.
I'm always confused by Access' use of brackets in joins. Try stripping out the extra brackets.
FROM
dbo_porel
LEFT JOIN
dbo_joboper ON (dbo_porel.assemblyseq = dbo_joboper.assemblyseq)
AND (dbo_porel.jobseq = dbo_joboper.oprseq)
AND (dbo_porel.jobnum = dbo_joboper.jobnum)
LEFT JOIN
dbo_opmaster ON (dbo_joboper.opcode = dbo_opmaster.opcode)
LEFT JOIN
dbo_podetail ON (dbo_porel.poline = dbo_podetail.poline)
AND (dbo_porel.ponum = dbo_podetail.ponum)
OK the above doesn't work - Sorry I give up