Multiple Left Joins in the same query causes "Invalid Operation" Error - sql

I have the following queries ...
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]));
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. Both of these queries have only the two respective fields referenced in the main query.
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.
The problem is that while Query #1 will work, Query #2 causes the error "Invalid Operation".
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.
Please help, I am at my wits end as to why this is not working. Is this an Access 2013 bug that will not allow for two Left Joins in the same query or something else I am missing?

The SQL looks like it should work, so the problem is probably the combination of the base queries plus the two left joins.
My general experience with Access queries on ODBC tables and with multiple outer joins is: even if you get them to work, they usually perform pretty badly.
So my suggestion is: Re-create the whole thing as view on SQL Server, and link that view. Then your Access query becomes something trivial like
SELECT * FROM dbo_ViewTransferHistory
WHERE DocNum=[Enter Doc Num]

Ok, so this is frustrating the absolute !##$% out of me. The syntax is correct and everything I see online says it should work. Out of pure frustration and some curiosity, I imported the ODBC tables into Access as local tables and changed the table references in the queries to use the local tables. OMG, now it works. Same data, same structure, different table type, and it !##$ing works. So it looks like the problem is in attempting to make multiple joins using ODBC. Unfortunately, I cannot create local tables from the ODBC every time this query gets run. Going to keep looking into this and see if I can find another workaround. Any other ideas?
Basically, Access will not allow multiple Outer Joins when using ODBC data sources. I am going to mark this as answered and rephrase the question in a new post.
Thank you.

Related

ms access query (ms access freezes)

I have this report and need to add totals for each person (the red circle)
existing report
new report
I cannot change the existing report so I export data from MS SQL to MS Access and create a new report there. I got it working for one employee but have trouble with a query which would for multiple employees.
This query extract data use as input:
SELECT [TIME].[RCD_NUM], [TIME].[EMP_ID], [TIME].[PPERIOD], [TIME].[PRUN], [TIME].[TDATE], [TIME].[PC], [TIME].[RATE], [TIME].[HOURS], [TIME].[AMOUNT], [TIME].[JOB_ID], [TIME].[UPDATED], [TIME].[UPDATED_BY], [TIME].[LOG_DATE], [TIME].[ORIGINAL_REC_NUM]
FROM [TIME]
WHERE ((([TIME].[EMP_ID])=376) And (([TIME].[TDATE])<=#12/31/2006# And ([TIME].[TDATE])>=#1/1/2006#) And (([TIME].[PC])<599));
this query populates the report:
SELECT *
FROM TIME1
WHERE RCD_NUM = (SELECT Max(RCD_NUM) FROM [TIME1] UQ WHERE UQ.PPERIOD = [TIME1].PPERIOD AND UQ.PC = [TIME1].PC);
the problem is if I remove EMP_ID from the first query like this
SELECT [TIME].[RCD_NUM], [TIME].[EMP_ID], [TIME].[PPERIOD], [TIME].[PRUN], [TIME].[TDATE], [TIME].[PC], [TIME].[RATE], [TIME].[HOURS], [TIME].[AMOUNT], [TIME].[JOB_ID], [TIME].[UPDATED], [TIME].[UPDATED_BY], [TIME].[LOG_DATE], [TIME].[ORIGINAL_REC_NUM]
FROM [TIME]
WHERE ((([TIME].[TDATE])<=#12/31/2006# And ([TIME].[TDATE])>=#1/1/2006#) And (([TIME].[PC])<599));
then the second query doesn't work and ms access freezes when running this query.
any help/idea please?
Caveat: I won't pretend to know the precise cause of the problem, but I have had to repeatedly refactor queries in Access to get them working even though the original SQL statements are completely valid in regards to syntax and logic. Sometimes I've had to convolute a sequence of queries just to avoid bugs in Access. Access is often rather dumb and will simply (re)execute queries and subqueries exactly as given without optimization. At other times Access will attempt to combine queries by performing some internal optimizations, but sometimes those introduce frustrating bugs. Something as simple as a name change or column reordering can be the difference between a functioning query and one that crashes or freezes Access.
First consider:
Can you leave the data on SQL Server and link to the results in Access (rather than export/importing it into Access)? Even if you need or prefer to use Access for creating the actual report, you could use all the power of SQL Server for querying the data--it is likely less buggy and more efficient.
Common best practice is to create SQL Server stored procedures that return just what data you need in Access. A pass-through query is created in Access to retrieve the data, but all data operations are performed on the server.
Perhaps this is just a performance issue where limiting the set by [EMP_ID] selects a small subset, but the full table is large enough to "freeze" Access.
How long have you let Access remain frozen before killing the process? Be patient... like many, many minutes (or hours). Start it in the morning and check after lunch. :) It might eventually return a result set. This does not imply it is tolerable or that there is no other solution, but it can be useful to know if it eventually returns data or not.
How many possible records are there?
Are the imported data properly indexed? Add indexes to all key fields and those which are used in WHERE clauses.
Is the database located on a network share or is it local? Try copying the database to a local drive.
Other hints:
Try the BETWEEN operator for dates in the WHERE clause.
Try refactoring the "second" query by performing a join in the FROM clause rather than the WHERE clause. In doing this, you may also want to save the subquery as a named query (just as [TIME1] is saved). Whether or not a query is saved or embedded in another statement CAN change the behavior of Access (see caveat) even though the results should be identical.
Here's a version with the embedded aggregate query. Notice how all column references are qualified with the source. Some of the original query's columns do not have a source alias prefixing the column name. Remember the caveat... such picky details can affect Access behavior.:
SELECT TIME1.*
FROM TIME1 INNER JOIN
(SELECT UQ.PPERIOD, UQ.PC, Max(UQ.RCD_NUM) As Max_RCD_NUM
FROM [TIME1] UQ
GROUP BY UQ.PPERIOD, UQ.PC) As TIMEAGG
ON (TIME1.PPERIOD = TIMEAGG.PPERIOD) And (TIME1.PC = TIMEAGG.PC)
AND (TIME1.RCD_NUM = TIMEAGG.Max_RCD_NUM)

Learning ExecuteSQL in FMP12, a few questions

I have joined a new job where I am required to use FileMaker (and gradually transition systems to other databases). I have been a DB Admin of a MS SQL Server database for ~2 years, and I am very well versed in PL/SQL and T-SQL. I am trying to pan my SQL knowledge to FMP using the ExecuteSQL functionaloty, and I'm kinda running into a lot of small pains :)
I have 2 tables: Movies and Genres. The relevant columns are:
Movies(MovieId, MovieName, GenreId, Rating)
Genres(GenreId, GenreName)
I'm trying to find the movie with the highest rating in each genre. The SQL query for this would be:
SELECT M.MovieName
FROM Movies M INNER JOIN Genres G ON M.GenreId=G.GenreId
WHERE M.Rating=
(
SELECT MAX(Rating) FROM Movies WHERE GenreId = M.GenreId
)
I translated this as best as I could to an ExecuteSQL query:
ExecuteSQL ("
SELECT M::MovieName FROM Movies M INNER JOIN Genres G ON M::GenreId=G::GenreId
WHERE M::Rating =
(SELECT MAX(M2::Rating) FROM Movies M2 WHERE M2::GenreId = M::GenreId)
"; "" ; "")
I set the field type to Text and also ensured values are not stored. But all I see are '?' marks.
What am I doing incorrectly here? I'm sorry if it's something really stupid, but I'm new to FMP and any suggestions would be appreciated.
Thank you!
--
Ram
UPDATE: Solution and the thought process it took to get there:
Thanks to everyone that helped me solve the problem. You guys made me realize that traditional SQL thought process does not exactly pan to FMP, and when I probed around, what I realized is that to best use SQL knowledge in FMP, I should be considering each column independently and not think of the entire result set when I write a query. This would mean that for my current functionality, the JOIN is no longer necessary. The JOIN was to bring in the GenreName, which is a different column that FMP automatically maps. I just needed to remove the JOIN, and it works perfectly.
TL;DR: The thought process context should be the current column, not the entire expected result set.
Once again, thank you #MissJack, #Chuck (how did you even get that username?), #pft221 and #michael.hor257k
I've found that FileMaker is very particular in its formatting of queries using the ExecuteSQL function. In many cases, standard SQL syntax will work fine, but in some cases you have to make some slight (but important) tweaks.
I can see two things here that might be causing the problem...
ExecuteSQL ("
SELECT M::MovieName FROM Movies M INNER JOIN Genres G ON
M::GenreId=G::GenreId
WHERE M::Rating =
(SELECT MAX(M2::Rating) FROM Movies M2 WHERE M2::GenreId = M::GenreId)
"; "" ; "")
You can't use the standard FMP table::field format inside the query.
Within the quotes inside the ExecuteSQL function, you should follow the SQL format of table.column. So M::MovieName should be M.MovieName.
I don't see an AS anywhere in your code.
In order to create an alias, you must state it explicitly. For example, in your FROM, it should be Movies AS M.
I think if you fix those two things, it should probably work. However, I've had some trouble with JOINs myself, as my primary experience is with FMP, and I'm only just now becoming more familiar with SQL syntax.
Because it's incredibly hard to debug SQL in FMP, the best advice I can give you here is to start small. Begin with a very basic query, and once you're sure that's working, gradually add more complicated elements one at a time until you encounter the dreaded ?.
There's a number of great posts on FileMaker Hacks all about ExecuteSQL:
Since you're already familiar with SQL, I'd start with this one: The Missing FM 12 ExecuteSQL Reference. There's a link to a PDF of the entire article if you scroll down to the bottom of the post.
I was going to recommend a few more specific articles (like the series on Robust Coding, or Dynamic Parameters), but since I'm new here and I can't include more than 2 links, just go to FileMaker Hacks and search for "ExecuteSQL". You'll find a number of useful posts.
NB If you're using FMP Advanced, the Data Viewer is a great tool for testing SQL. But beware: complex queries on large databases can sometimes send it into fits and freeze the program.
The first thing to keep in mind when working with FileMaker and ExecuteSQL() is the difference between tables and table occurrences. This is a concept that's somewhat unique to FileMaker. Succinctly, tables store the data, but table occurrences define the context of that data. Table occurrences are what you're seeing in FileMaker's relationship graph, and the ExecuteSQL() function needs to reference the table occurrences in its query.
I agree with MissJack regarding the need to start small in building the SQL statement and use the Data Viewer in FileMaker Pro Advanced, but there's one more recommendation I can offer, which is to use SeedCode's SQL Explorer. It does require the adding of table occurrences and fields to duplicate the naming in your existing solution, but this is pretty easy to do and the file they offer includes a wizard for building the SQL query.

ERROR in CREATE VIEW

I tried to create a new view in my MS Access database so I can select better from it but I wonder what's happening here.
CREATE VIEW new
AS
SELECT msthread.id,
msthread.threadname,
Count(msthread.threadname) AS TotalPost,
threadcategory
FROM msthread
LEFT OUTER JOIN msposts
ON msthread.threadname = msposts.threadname
GROUP BY msthread.id,
msthread.threadname,
msthread.threadcategory
Access gives me this error message when I try to execute that statement.
Syntax error in create table statement
Is there specific problems in creating view with JOINs? I'm trying to access 2 tables.
CREATE VIEW was introduced with Jet 4 in Access 2000. But you must execute the statement from ADO/OleDb. If executed from DAO, it triggers error 3290, "Syntax error in CREATE TABLE statement", which is more confusing than helpful.
Also CREATE VIEW can only create simple SELECT queries. Use CREATE PROCEDURE for any which CREATE VIEW can't handle.
But CREATE VIEW should handle yours. I used a string variable to hold the DDL statement below, and then executed it from CurrentProject.Connection in an Access session:
CurrentProject.Connection.Execute strSql
That worked because CurrentProject.Connection is an ADO object. If you will be doing this from outside Access, use an OleDb connection.
Notice I made a few changes to your query. Most were minor. But I think the query name change may be important. New is a reserved word so I chose qryNew instead. Reserved words as object names seem especially troublesome in queries run from ADO/OleDb.
CREATE VIEW qryNew
AS
SELECT
mst.id,
mst.threadname,
mst.threadcategory,
Count(mst.threadname) AS TotalPost
FROM
msthread AS mst
LEFT JOIN msposts AS msp
ON mst.threadname = msp.threadname
GROUP BY
mst.id,
mst.threadname,
mst.threadcategory;
Going out on a limb here without the error message but my assumption is that you need an alias in front of your non-aliased column.
You may also have a problem titling the view as new. This is a problem with using a generic name for a view or table. Try giving it a distinct name that matters. I'll use msThreadPosts as an example.
CREATE VIEW msThreadPosts
AS
SELECT msthread.id,
msthread.threadname,
Count(msthread.threadname) AS TotalPost,
msposts.threadcategory --Not sure if you want msposts or msthread just pick one
FROM msthread
LEFT OUTER JOIN msposts
ON msthread.threadname = msposts.threadname
GROUP BY msthread.id,
msthread.threadname,
msthread.threadcategory
As long as we are looking at this query lets fix some other things that are being done in a silly way.
Lets start off with aliasing. If you alias a column you can very easily make your query easy to understand and read to anyone who is inclined to read it.
CREATE VIEW msThreadPosts
AS
SELECT mt.id,
mt.threadname,
Count(mt.threadname) AS TotalPost,
mp.threadcategory
FROM mtas mt
LEFT OUTER JOIN msposts mp
ON mt.threadname = mp.threadname
GROUP BY mt.id,
mt.threadname,
mt.threadcategory
There now doesn't that look better.
The next thing to look as if your column names. msthread has an id column. That column name is incredibly generic. This can cause problems when a column isn't aliased and an id exists in mulitple places or there are muliple id columns. Now if we change that column name to msthreadID it makes things much clearer. The goal is to design your tables in a way that anyone working on your database can imidiatley tell what a column is doing.
The next thing to look at is your join. Why are you joining on thread name? threadname is likely a character string and therefore not terribly efficient for joins. if msthread as an id column and needs to be joined to msposts then shouldn't msposts also have that id column to match up on to make joins more efficient?

SQL Developer "disconnected from the rest of the join graph"

I have the following SQL:
select <misc things>
from pluspbillline
left outer join workorder
on workorder.siteid=pluspbillline.siteid
and workorder.wonum = pluspbillline.refwo
and workorder.orgid = pluspbillline.orgid
left outer join ticket
on ticket.ticketid = pluspbillline.ticketid
and ticket.class=pluspbillline.ticketclass
left outer join pluspsalesorder
on pluspsalesorder.salesordernum=pluspbillline.salesordernum
and pluspsalesorder.siteid=pluspbillline.siteid
In Oracle SQL Developer 4.0.0.13 (connected to a DB2 database), I get a squiggly line underneath the following italics: "from pluspbillline" and "left outer join workorder".
The warning says "pluspbillline is disconnected from the rest of the join graph". What does this mean?
I got this as well. I'm not exactly sure how to articulate it but the error seems to be based on the logical flow of the code.
Essentially because you mention the table pluspbillline before workorder I think it expects the join to be on pluspbillline.siteid=workorder.siteid etc.
It seems that the order of the conditions for joins should flow from the first identified tables to the latest ones. So the following should make it happy:
plusbillline to workorder on pluspbillline.siteid=workorder.siteid...
"" to ticket on pluspbillline.ticketid = ticket.ticketid...
"" to pluspsalesorder on pluspbillline.salesordernum = pluspsalesorder.salesordernum...
I don't believe this would change the work oracle does (assuming you don't use optimizer hints) so I'd only bother to change if you hate the squiggly lines.
I'm not sure what's causing Oracle SQL Developer to give the error. But I'm putting this comment here to format it properly.
A join graph might look something like this
pluspbillline ------+----< workorder
|
+----< ticket
|
+----< pluspsalesorder
The lines on the graph might be labeled with the join fields. But this gives you a basic idea.
I don't see any reason why you are getting this warning. A column name typo in your SQL perhaps? Or some quirk in Oracle's interface that it doesn't understand the DB2 metadata properly? I suggested trying IBM's tool to see if it's merely their program.
The issue is caused by the Oracle Procedure having the same named input parameter as the column on the table you are joining to.
i.e input parm named bank_nbr and a table BankDept.bank_nbr will cause the error if you have WHERE bank_nbr = BankDept.bank_nbr
I solved the issue by renaming the input parameter to in_bank_nbr and updating my where to read WHERE in_bank_nbr = BankDept.bank_nbr
I had the same message when hovering over the "LEFT" word, but the whole query ran without a problem. On the other hand, when I hovered over "WITH", I got a piece of advice about restructuring the whole query. So, that message about disconnection could be not a sign of an error, but a warning about a too complex sentence. SQLDeveloper's editor does not mention the level of the problem.

Querying for software using SQL query in SCCM

I am looking for specific pieces of software across our network by querying the SCCM Database. My problem is that, for various reasons, sometimes I can search by the program's name and other times I need to search for a specific EXE.
When I run the query below, does it take 13 seconds to run if the where clause contains an AND, but it will run for days with no results if the AND is replaced with OR. I'm assuming it is doing this because I am not properly joining the tables. How can I fix this?
select vrs.Name0
FROM v_r_system as vrs
join v_GS_INSTALLED_SOFTWARE as VIS on VIS.resourceid = vrs.resourceid
join v_GS_SoftwareFile as sf on SF.resourceid = vrs.resourceid
where
VIS.productname0 LIKE '%office%' AND SF.Filename LIKE 'Office2007%'
GROUP BY vrs.Name0
Thanks!
Your LIKE clause contains a wildcard match at the start of a string:
LIKE '%office%'
This prevents SQL Server from using an index on this column, hence the slow running query. Ideally you should change your query so your LIKE clause doesn't use a wildcard at the start.
In the case where the WHERE clause contains an AND its querying based on the Filename clause first (it is able to use an index here and so this is relatively quick) and then filtering this reduced rowset based on your productname0 clause. When you use an OR however it isn't restricted to just returning rows that match your Filename clause, and so it must search through the entire table checking to see if each productname0 field matches.
Here's a good Microsoft article http://msdn.microsoft.com/en-us/library/ms172984.aspx on improving indexes. See the section on Indexes with filter clauses (reiterates the previous answer.)
Have you tried something along these lines instead of a like query?
... where product name in ('Microsoft Office 2000','Microsoft Office xyz','Whateverelse')