I have less than basic knowledge of MS Access, as I only need to use it to pull down information irregularly before using R to do the manipulation. As a result, I have no SQL coding knowledge - I just use the Access GUI.
My problem: When I create a query that includes multiple tables Access seems to exclude the results that don't have values in all of the tables.
Solution: I'm looking for a simple way, through the GUI, to tell Access to include all the IDs in the parent table, irrespective of whether they have values in any of the child tables. Those IDs that have no values in the child tables should just return with blanks in those columns.
I know this is probably SQL 101 but my searching hasn't returned anything useful.
You should use LEFT JOIN or RIGHT JOIN, the direction meaning the table from which you want to get all rows. See the select below:
SELECT * FROM TABLE_A a LEFT JOIN TABLE_B b ON a.id=b.id
This will return all rows from TABLE_A linked to the corresponding rows from TABLE_B. When there is no match the TABLE_B columns will return NULL.
Related
I'm making a simple query :
SELECT * FROM Bench LEFT JOIN ASSIGNED_DOM
ON (Bench.B_id=ASSIGNED_DOM.B_id) WHERE Bench.B_type=0 ;
As expected all the lines of Bench table are returned BUT If I try to get the B_id field I discovered that was put to NULL.
Then I have tried with this other query that should be totally equivalent:
SELECT * FROM Bench LEFT JOIN ASSIGNED_DOM USING (B_id) WHERE Bench.B_type=0 ;
But in that case the B_id field is returned correctly.
What's wrong with the first query? What the difference between the two ?
The two queries are not equivalent. According to the documentation,
Natural joins and joins with USING, including outer join variants, are processed according to the SQL:2003 standard.
Redundant columns of a NATURAL join do not appear.
That specifically comes down to the following difference:
A USING clause can be rewritten as an ON clause that compares corresponding columns. However, although USING and ON are similar, they are not quite the same.
With respect to determining which rows satisfy the join condition, both joins are semantically identical.
With respect to determining which columns to display for SELECT * expansion, the two joins are not semantically identical. The USING join selects the coalesced value of corresponding columns, whereas the ON join selects all columns from all tables.
So your first query has two columns of the same name, bench.B_id, ASSIGNED_DOM.B_id, while the second one just has one, coalesce(bench.B_id, ASSIGNED_DOM.B_id) as B_id.
It will depend on your application/framework how exactly the first case will be handled. E.g. the MySQL client or phpmyadmin will just display all columns. Some frameworks may alter the names in some way to make them unique.
php in particular (and I assume you are using this) will not though: if you use $row['B_id'], it will return the last occurance (although that behaviour is not specified), so in your case you will get ASSIGNED_DOM.B_id. You can however still access both columns with their index (e.g. $row[0], $row[1]), but just one of those with their identical column name.
To prevent such problems, you can/should use aliases, e.g. select bench.B_id as bench_B_id, ASSIGNED_DOM.B_id as ASSIGNED_DOM_B_id, ....
Values in second table overwrites values in the first one if column name is the same. Try to use an alias in your query
SELECT Bench.B_id AS bid1, ASSIGNED_DOM.B_id AS bid2
FROM Bench
LEFT JOIN ASSIGNED_DOM ON (Bench.B_id=ASSIGNED_DOM.B_id)
WHERE Bench.B_type=0;
I'm thinking of switching to using temp tables and vba.
I want to do this. I have multiple tables, in these tables may or may not have fields with items that have a one to many or one to one relationship. I know what those relationships are (and will create multiple queries accordingly). What I'm hunting for is each value that DOES NOT EXIST in every other table. To make an example:
Say we have 3 single column tables, table 1 is {x, y, z}, table 2 is {a, x, z}, and table 3 is {a,b,x,y,z}, the result will be b for t3 (yes I need to know where the error is). Pretty much, I want to use the unequal wizard but for 3 or more tables.
I may want to look for any item that exists in some but not all other tables. If you want to speak on that, it would be helpful, but I think that is strictly in the vba realm.
I think the challenge here is the open-endedness of the problem you are trying to solve. Varying column names, table names, and uniqueness thresholds across all tables would make it a bit more difficult. In the way I show below, I don't think it would be the most efficient, query-wise, but would be relatively easy to script. The following code assumes values in the tables are unique within each table.
There are 3 queries total:
qry_001_TableValues_ALL
SELECT Table1.MyValue, "Table1" AS Source
FROM Table1
UNION
SELECT Table2.MyValue, "Table2" AS Source
FROM Table2
UNION SELECT Table3.MyValue, "Table3" AS Source
FROM Table3;
qry_002_TableValues_Unique:
SELECT qry_001_TableValues_ALL.MyValue
FROM qry_001_TableValues_ALL
GROUP BY qry_001_TableValues_ALL.MyValue
HAVING (((Count(qry_001_TableValues_ALL.MyValue))=1));
qry_003_TableValues_UniqueWithSource:
SELECT qry_002_TableValues_Unique.MyValue, qry_001_TableValues_ALL.Source
FROM qry_002_TableValues_Unique INNER JOIN qry_001_TableValues_ALL
ON qry_002_TableValues_Unique.MyValue = qry_001_TableValues_ALL.MyValue;
The first table is the one you would need to script out if columns\tables changed. It is looking across all tables and creating a unique list of values from the specified field. The second query looks to look up the Source table name against the original unique value query for all values which have a count of 1, post aggregation. This means of all tables involved, there is only one instace of the values returned, and it joins against the original unique value list again to determine what the source table is. You can script a change to the HAVING clause here to see if there are x tables which contain the value. The final query is simply the one you run to give you the final report of the values you are looking for and where they reside.
Hope this is in the ballpark of what you are trying to do.
I came across the following SQL statement and I was wondering if it was valid:
SELECT COUNT(*)
FROM
registration_waitinglist,
registration_registrationprofile
WHERE
registration_registrationprofile.activation_key = "ALREADY_ACTIVATED"
What does the two tables separated by a comma mean?
When you SELECT data from multiple tables you obtain the Cartesian Product of all the tuples from these tables. It can be illustrated in the following way:
This means you get each row from the first table paired with all the rows from the second table. Most of the time, it is not what you want. If you really want it, then it's clearer to use the CROSS JOIN notation:
SELECT * FROM A CROSS JOIN B;
In this context, it means that you are going to be joining every row from registration_waitinglist to every row in registration_registrationprofile
It's called a cartesian join
That query is 'syntactically' correct, meaning it will run. What the query will return is the entire product of every row in registration_waitinglist x registration_registrationprofile.
For example, if there were 2 rows in waitinglist and 3 rows in profile, then 6 rows will be returned.
From a practical matter, this is almost always a logical error and not intended. With rare exception, there should be either join criteria or criteria in the where clause.
I am using LLBLgen as ORM and want to achieve the following:
Table1:
SessionId
Table2:
SessionId
Timestamp
SELECT TOP 100 * FROM Table1
INNER JOIN Table2 ON Table1.SessionId = Table2.SessionId
ORDER BY Table2.Timestamp DESC
This code is running fine when executing it directly on SQL Server 2008 R2 - returning exactly 100 rows from Table1 if available, but somehow I am unable to achieve the same result with LLBLGen. Currently I'm using still 2.6, but updating is an option if needed.
Is there a possibility to achieve this behavior in LLBLGen?
This is the result if I use normal mechanisms in LLBLGen
SELECT * FROM Table1
INNER JOIN Table2 ON Table1.SessionId = Table2.SessionId
ORDER BY Table2.Timestamp DESC
BTW: I read that LLBLGen takes the TOP 100 results from the reader then kills the connection. Nonetheless the query takes A LOT longer using LLBLGen in comparison to just executing the SQL directly (this counts, to my surprise, also for latter query!)
It doesn't add TOP as that would maybe return duplicate rows as you have a join and there's a situation in your query (you didn't post the real query) where you have distinct violating typed fields in your projection.
In general, when fetching entities, llblgen pro will add TOP in your case and DISTINCT. If it can't add distinct, because your query returns fields of type image, ntext, text, or you sort on a field which isn't in the projection (so distinct can't be applied otherwise sqlserver will throw an error), it won't add TOP either as that could mean you get potential duplicate rows in the set limited by TOP, which are filtered out, as entities are always unique.
Example:
fetching Customers based on a filter on Order (so using a join), will create a Customers INNER JOIN Orders on northwind, but as this is a 1:n relationship, it will create duplicates. If Customers contains a text, image or ntext field, distinct can't be applied, so if we then would specify TOP, you'll get duplicate rows. As llblgen pro never materializes duplicate rows into entities, you'll get less entities back than the value you asked for.
So instead it switches, in THIS particular case, to client side limitation: it kills the connection once it has read the # of entities (not rows!) which you asked for. So if you ask for 10 entities and you have 10000 duplicate rows in the first 10010 rows, you'll get 10000 rows being fetched at least.
So my guess is the sort on table2 which is the issue, as that prevents DISTINCT from being emitted. This is an illegal query on sqlserver:
SELECT DISTINCT C.CompanyName FROM Customers C INNER JOIN Orders O on c.CustomerId = o.CustomerId
ORDER BY o.OrderDate DESC;
The reason is that ORDER BY appends a hidden column for all fields to sort on which aren't in the projection, which ruins the distinct. This is common in RDBMS-s.
So TL;DR: it's a feature :)
I am trying to make a query joining 4 tables. One table will only fill out some records, not all. How do I get the criteria to be:
If record is null still show the field..... because right now if the record is null in any one of the fields it will not show in my query results.
If records are missing in one table, then you must use an outer join. Say, you have a table A with 5 records and a table B with only 3 records and you want to make a query joining the two tables showing 5 records
SELECT * FROM
A
LEFT JOIN B
ON A.ID = B.FK
In the query designer, right click on the join-line and enter this:
It sounds like you want your filter conditions to ignore NULLs. (That is, by default a NULL wouldn't match your filter, but the desired output is that it should.)
If this is correct, you want to modify the filters to allow NULLs, for example by adding OR IS NULL.
It sounds like you need to use a LEFT (or "outer") Join instead of an INNER join.
Outer joins (like LEFT JOINs) will return all results whether there are matching records in the other table or not. You'll just have null column values in the results for the joined tables.
More info here: http://pcmcourseware.com/blog/2010/11/10/modifying-query-joins-in-microsoft-access/