Access Query Combine Records from Many-to-Many into one row - sql

This should be easy but I'm having a hard time.
I have a many-to-many relationship where, for example, many cars can have many components.
So I want a query to return all cars and the subsequent components used. If no component is used it should just return a NULL value.
Car | Engine | Tyre
----------------------
1 | Engine3 |
2 | Engine4 | Tyre3
3 | Engine1 | Tyre1
But with the following SQL:
SELECT Car.idCar, Engine.idEngine, Tyre.idTyre
FROM ((Component
RIGHT JOIN (Car
LEFT JOIN Car_Component ON Car.idCar = Car_Component.idCar) ON Component.idComponent = Car_Component.idComponent)
LEFT JOIN Engine ON Component.idComponent = Engine.idComponent)
LEFT JOIN Tyre ON Component.idComponent = Tyre.idComponent;
I get:
Car | Engine | Tyre
----------------------
1 | Engine3 |
2 | Engine4 |
2 | | Tyre3
3 | Engine1 |
3 | | Tyre1
I've been searching for a solution for quite some time now and I'm pretty sure I need to make subqueriesm but my knowledge of subqueries is limited and I don't know how to start.
Here is the problem in SQL Fiddle.

Does the following query work for you SQL Fiddle:
SELECT DISTINCT Car.idCar, Engine.idEngine, Tyre.idTyre
FROM (((Car
INNER JOIN Car_Component ON Car.idCar = Car_Component.idCar)
INNER JOIN Component ON Car_Component.idComponent = Component.idComponent)
LEFT JOIN Engine ON Component.idComponent = Engine.idComponent)
LEFT JOIN Tyre ON Component.idComponent = Tyre.idComponent;

Related

combine 2 sql's from different tables into one query

I have for example as first query: (ararnr = article number)
Select ararnr,ararir,aoarom from ar left join ao ON AR.ARARNR=AO.AOARNR WHERE AR.ARARKD=1389
the second query uses the result from the first column from the first query to search in another table
Select votgan, sum(ststan) as totalStock from vo INNER JOIN st on vo.voarnr=st.starnr where voarnr = ararnr
How could I combine both ?
Please note : Not all articlenumbers from the first query will be found in the second, but I need them in my result.
In the result I need the columns from both queries.
EDIT
for example :
first query returns article numbers and the description:
+---------+--------------+
| ararnr | aoarom |
+---------+--------------+
| a123456 | description1 |
| b123456 | description2 |
| 0123456 | description3 |
+---------+--------------+
second query returns the totalstock for those articles:
+---------+--------------+
| ararnr | totalstock |
+---------+--------------+
| a123456 | 12 |
| b123456 | |
| 0123456 | 6 |
+---------+--------------+
Note the second one doesn't return a value since the articlenumber doesn't exist in this table.
In my result I would like to get the articlenumber with corresponding description and stock.
+---------+--------------+-----------+---------+
| ararnr | aoarom | totalStock| vovoan |
+---------+--------------+-----------+---------+
| a123456 | description1 | 12 | 2 |
| b123456 | description2 | | 1 |
| 0123456 | description3 | 6 | |
+---------+--------------+-----------+---------+
I'm using sql on db2
SECOND EDIT
The first query will select some article numbers (ararnr) from table ar and find the corresponding description (aoarom) in another table ao.
The second query finds the stock (vovoan and sum ststan) from two differend tables vo and st for the article numbers found in the first query.
The result should have the article number with corresponding description with corresponding stock from vo and st
I can't fully understand what you're asking, but another join may assist you.
example:
SELECT ar.ararnr, ar.ararir, ar.ararom, vo.votgan, SUM(vo.ststan) as totalStock
FROM ar LEFT JOIN ao ON [id=id] LEFT JOIN vo ON [id=id]
Because I can't tell what your tables structure are, or what you're really asking for, this is the best response I can give you.
This also may be what you're looking for:
Combining 2 SQL queries and getting result set in one
You can use this query.
SELECT ar.ararnr, ar.ararir, ar.ararom, vo.votgan, SUM(vo.ststan) as totalStock
FROM ar
LEFT JOIN ao ON ao.ararnr = ar.ararnr
LEFT JOIN vo ON vo.voarnr = ao.ararnr
If you are using SQL Server as database then this can be done with help of OUTER APPLY
SELECT ararnr,aoarom ,temp.totalStock
FROM ar
LEFT JOIN ao ON AR.ARARNR=AO.AOARNR
OUTER APPLY(
SELECT sum(ststan) as totalStock
FROM vo
INNER JOIN st on vo.voarnr=st.starnr
where voarnr = ar.ararnr
)temp
WHERE AR.ARARKD=1389
You'd get a much more complete answer if you were to post the table structure and desired result, but..
You can use the first query as a resultset for your second query, and join to it. something like:
Select
votgan,
sum(ststan) as totalStock
from vo
inner join (Select
ararnr,
ararir,
ararom
from ar
left join ao .....) z on vo.voarnr = z.ararnr
EDIT:
Select
votgan,
sum(ststan) as totalStock,
z.ararnr,
z.aoarom
from vo
inner join (Select
ararnr,
ararir,
ararom
from ar
left join ao .....) z on vo.voarnr = z.ararnr

Shouldn't a full join get both sides even if one side has a null of both tables

This is not the full query(it is a subquery in a larger query). However, I know this is the part that is causing me a problem as I have taken it own and sourced it to it. I am trying to get both sides of two tables that don't always have matching composite keys. In particular, the GKey is not always the same.
I am currently using a full join, but I still get gaps on both sides. There is an example of how the data should essentially come out. You can see that there are nulls on both sides of the two different tables.
Input
| A | B |
| 2 | NULL |
| NULL | 5 |
| 3 | 3 |
|Null | 6 |
Outcome
| A | B |
| 3 | 3 |
SELECT DISTINCT BudgetUnit / (WorkDaysInMonth * 8) AS B
,Unit / (WorkDaysInMonth * 8) AS A
FROM BFact AS BMF
FULL JOIN GFact AS GF ON
BMF.GLKey = GF.GKey
AND
BMF.DKey = GF.DKey
AND GF.AKey = BMF.BKey
AND GF.PKey = BMF.PKey
INNER JOIN DimDate AS DA ON GF.AKey = DA.DateKey
Because you are selecting FROM BFact, and then using GFact in an INNER JOIN after the FULL JOIN, you are turning your FULL JOIN into an INNER JOIN because no results that don't satisfy the last INNER JOIN will be returned.
You could make that last INNER JOIN into a LEFT OUTER JOIN to get the desired results.

How to cross join in Big Query using intervals?

How can I join two tables using intervals in Google Big Query?
I have two table:
Table CarsGPS:
ID | Car | Latitude | Longitude
1 | 1 | -22.123 | -43.123
2 | 1 | -22.234 | -43.234
3 | 2 | -22.567 | -43.567
4 | 2 | -22.678 | -43.678
...
Table Areas:
ID | LatitudeMin | LatitudeMax | LongitudeMin | LongitudeMax
1 | -22.124 | -22.120 | -43.124 | -43.120
2 | -22.128 | -22.124 | -43.128 | -43.124
...
I'd like to cross join these tables to check in which areas each car has passed by using Google Big Query.
In a regular SQL server I would make:
SELECT A.ID, C.Car
FROM Cars C, Areas A
WHERE C.Latitude BETWEEN A.LatitudeMin AND A.LatitudeMax AND
C.Longitude BETWEEN A.LongitudeMin AND A.LongitudeMax
But Google Big Query only allows me to do joins (even JOIN EACH) using exact matches among joined tables. And the "FROM X, Y" means UNION, not JOINS.
So, this is not an option:
SELECT A.ID, C.Car
FROM Cars C
JOIN EACH
Areas A
ON C.Latitude BETWEEN A.LatitudeMin AND A.LatitudeMax AND
C.Longitude BETWEEN A.LongitudeMin AND A.LongitudeMax
Then, how can I run something similar to it to identify which cars passed inside each area?
BigQuery now supports CROSS JOIN. Your query would look like:
SELECT A.ID, C.Car
FROM Cars C
CROSS JOIN Areas A
WHERE C.Latitude BETWEEN A.LatitudeMin AND A.LatitudeMax AND
C.Longitude BETWEEN A.LongitudeMin AND A.LongitudeMax

join on three tables? Error in phpMyAdmin

I'm trying to use a join on three tables query I found in another post (post #5 here). When I try to use this in the SQL tab of one of my tables in phpMyAdmin, it gives me an error:
#1066 - Not unique table/alias: 'm'
The exact query I'm trying to use is:
select r.*,m.SkuAbbr, v.VoucherNbr from arrc_RedeemActivity r, arrc_Merchant m, arrc_Voucher v
LEFT OUTER JOIN arrc_Merchant m ON (r.MerchantID = m.MerchantID)
LEFT OUTER JOIN arrc_Voucher v ON (r.VoucherID = v.VoucherID)
I'm not entirely certain it will do what I need it to do or that I'm using the right kind of join (my grasp of SQL is pretty limited at this point), but I was hoping to at least see what it produced.
(What I'm trying to do, if anyone cares to assist, is get all columns from arrc_RedeemActivity, plus SkuAbbr from arrc_Merchant where the merchant IDs match in those two tables, plus VoucherNbr from arrc_Voucher where VoucherIDs match in those two tables.)
Edited to add table samples
Table arrc_RedeemActivity
RedeemID | VoucherID | MerchantID | RedeemAmt
----------------------------------------------
1 | 2 | 3 | 25
2 | 6 | 5 | 50
Table arrc_Merchant
MerchantID | SkuAbbr
---------------------
3 | abc
5 | def
Table arrc_Voucher
VoucherID | VoucherNbr
-----------------------
2 | 12345
6 | 23456
So ideally, what I'd like to get back would be:
RedeemID | VoucherID | MerchantID | RedeemAmt | SkuAbbr | VoucherNbr
-----------------------------------------------------------------------
1 | 2 | 3 | 25 | abc | 12345
2 | 2 | 5 | 50 | def | 23456
The problem was you had duplicate table references - which would work, except for that this included table aliasing.
If you want to only see rows where there are supporting records in both tables, use:
SELECT r.*,
m.SkuAbbr,
v.VoucherNbr
FROM arrc_RedeemActivity r
JOIN arrc_Merchant m ON m.merchantid = r.merchantid
JOIN arrc_Voucher v ON v.voucherid = r.voucherid
This will show NULL for the m and v references that don't have a match based on the JOIN criteria:
SELECT r.*,
m.SkuAbbr,
v.VoucherNbr
FROM arrc_RedeemActivity r
LEFT JOIN arrc_Merchant m ON m.merchantid = r.merchantid
LEFT JOIN arrc_Voucher v ON v.voucherid = r.voucherid

SQL INNER JOIN syntax

the two bits of SQL below get the same result
SELECT c.name, o.product
FROM customer c, order o
WHERE c.id = o.cust_id
AND o.value = 150
SELECT c.name, o.product
FROM customer c
INNER JOIN order o on c.id = o.cust_id
WHERE o.value = 150
I've seen both styles used as standard at different companies. From what I've seen, the 2nd one is what most people recommend online. Is there any real reason for this other than style? Does using an Inner Join sometimes have better performance?
I've noticed Ingres and Oracle developers tend to use the first style, whereas Microsoft SQL Server users have tended to use the second, but that might just be a coincidence.
Thanks for any insight, I've wondered about this for a while.
Edit: I've changed the title from 'SQL Inner Join versus Cartesian Product' as I was using the incorrect terminlogy. Thanks for all the responses so far.
Both queries are an inner joins and equivalent. The first is the older method of doing things, whereas the use of the JOIN syntax only became common after the introduction of the SQL-92 standard (I believe it's in the older definitions, just wasn't particularly widely used before then).
The use of the JOIN syntax is strongly preferred as it separates the join logic from the filtering logic in the WHERE clause. Whilst the JOIN syntax is really syntactic sugar for inner joins it's strength lies with outer joins where the old * syntax can produce situations where it is impossible to unambiguously describe the join and the interpretation is implementation-dependent. The [LEFT | RIGHT] JOIN syntax avoids these pitfalls, and hence for consistency the use of the JOIN clause is preferable in all circumstances.
Note that neither of these two examples are Cartesian products. For that you'd use either
SELECT c.name, o.product
FROM customer c, order o
WHERE o.value = 150
or
SELECT c.name, o.product
FROM customer c CROSS JOIN order o
WHERE o.value = 150
To answer part of your question, I think early bugs in the JOIN ... ON syntax in Oracle discouraged Oracle users away from that syntax. I don't think there are any particular problems now.
They are equivalent and should be parsed into the same internal representation for optimization.
Actually these examples are equivalent and neither is a cartesian product. A cartesian product is returned when you join two tables without specifying a join condition, such as in
select *
from t1,t2
There is a good discussion of this on Wikipedia.
Oracle was late in supporting the JOIN ... ON (ANSI) syntax (not until Oracle 9), that's why Oracle developers often don't use it.
Personally, I prefer using ANSI syntax when it is logically clear that one table is driving the query and the others are lookup tables. When tables are "equal", I tend to use the cartesian syntax.
The performance should not differ at all.
The JOIN... ON... syntax is a more recent addition to ANSI and ISO specs for SQL. The JOIN... ON... syntax is generally preferred because it 1) moves the join criteria out of the WHERE clause making the WHERE clause just for filtering and 2) makes it more obvious if you are creating a dreaded Cartesian product since each JOIN must be accompanied by at least one ON clause. If all the join criteria are just ANDed in the WHERE clause, it's not as obvious when one or more is missing.
Both queries are performing an inner join, just different syntax.
TL;DR
An INNER JOIN statement can be rewritten as a CROSS JOIN with a WHERE clause matching the same condition you used in the ON clause of the INNER JOIN query.
Table relationship
Considering we have the following post and post_comment tables:
The post has the following records:
| id | title |
|----|-----------|
| 1 | Java |
| 2 | Hibernate |
| 3 | JPA |
and the post_comment has the following three rows:
| id | review | post_id |
|----|-----------|---------|
| 1 | Good | 1 |
| 2 | Excellent | 1 |
| 3 | Awesome | 2 |
SQL INNER JOIN
The SQL JOIN clause allows you to associate rows that belong to different tables. For instance, a CROSS JOIN will create a Cartesian Product containing all possible combinations of rows between the two joining tables.
While the CROSS JOIN is useful in certain scenarios, most of the time, you want to join tables based on a specific condition. And, that's where INNER JOIN comes into play.
The SQL INNER JOIN allows us to filter the Cartesian Product of joining two tables based on a condition that is specified via the ON clause.
SQL INNER JOIN - ON "always true" condition
If you provide an "always true" condition, the INNER JOIN will not filter the joined records, and the result set will contain the Cartesian Product of the two joining tables.
For instance, if we execute the following SQL INNER JOIN query:
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1
We will get all combinations of post and post_comment records:
| p.id | pc.id |
|---------|------------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
So, if the ON clause condition is "always true", the INNER JOIN is simply equivalent to a CROSS JOIN query:
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id
SQL INNER JOIN - ON "always false" condition
On the other hand, if the ON clause condition is "always false", then all the joined records are going to be filtered out and the result set will be empty.
So, if we execute the following SQL INNER JOIN query:
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id
We won't get any result back:
| p.id | pc.id |
|---------|------------|
That's because the query above is equivalent to the following CROSS JOIN query:
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id
SQL INNER JOIN - ON clause using the Foreign Key and Primary Key columns
The most common ON clause condition is the one that matches the Foreign Key column in the child table with the Primary Key column in the parent table, as illustrated by the following query:
SELECT
p.id AS "p.id",
pc.post_id AS "pc.post_id",
pc.id AS "pc.id",
p.title AS "p.title",
pc.review AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id
When executing the above SQL INNER JOIN query, we get the following result set:
| p.id | pc.post_id | pc.id | p.title | pc.review |
|---------|------------|------------|------------|-----------|
| 1 | 1 | 1 | Java | Good |
| 1 | 1 | 2 | Java | Excellent |
| 2 | 2 | 3 | Hibernate | Awesome |
So, only the records that match the ON clause condition are included in the query result set. In our case, the result set contains all the post along with their post_comment records. The post rows that have no associated post_comment are excluded since they can not satisfy the ON Clause condition.
Again, the above SQL INNER JOIN query is equivalent to the following CROSS JOIN query:
SELECT
p.id AS "p.id",
pc.post_id AS "pc.post_id",
pc.id AS "pc.id",
p.title AS "p.title",
pc.review AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id
The non-struck rows are the ones that satisfy the WHERE clause, and only these records are going to be included in the result set. That's the best way to visualize how the INNER JOIN clause works.
| p.id | pc.post_id | pc.id | p.title | pc.review |
|------|------------|-------|-----------|-----------|
| 1 | 1 | 1 | Java | Good |
| 1 | 1 | 2 | Java | Excellent |
| 1 | 2 | 3 | Java | Awesome |
| 2 | 1 | 1 | Hibernate | Good |
| 2 | 1 | 2 | Hibernate | Excellent |
| 2 | 2 | 3 | Hibernate | Awesome |
| 3 | 1 | 1 | JPA | Good |
| 3 | 1 | 2 | JPA | Excellent |
| 3 | 2 | 3 | JPA | Awesome |
Not that this only applies to INNER JOIN, not for OUTER JOIN.