i have four tables which are related like this:
TABLE A: 1 to many with TABLE B
TABLE B: 1 to many with TABLE C
TABLE D: many to 1 with TABLE B
I would like to create a result set which contains no duplicates.
SELECT A.f1
A.f2
B.f1
C.f1
D.f1
from A LEFT JOIN (B INNER JOIN D on D.fk_b = B.id) on A.id = B.fk_a
LEFT JOIN C on C.fk_b = B.id
Some but not all records are duplicated. Only the records from TABLE D which have the same FK to TABLE B.
If there are 2 the same D.fk_B fields then i would like to select only the first one. My INNER JOIN would become something like:
B INNER JOIN TOP 1 D on.....
But that's not possible?
Thank you!
Assuming that the structure in question is near the one shown bellow,
The following SELECT statement will show you just the primary keys, briefly giving an idea about what data is being returned.
SELECT
A.id AS `A_id`,
B.id AS `B_id`,
COALESCE(C.id, 0) AS `C_id`,
COALESCE(
(SELECT D.id FROM D WHERE D.fk_b = B.id LIMIT 1), 0
) AS `D_id`
FROM B
INNER JOIN A ON (B.fk_a = A.id)
LEFT JOIN C ON (B.id = C.fk_b);
Now the select you've asked for:
SELECT
A.f1 AS `A_f1`,
A.f2 AS `A_f2`,
B.f1 AS `B_f1`,
COALESCE(C.f1, '-') AS `C_f1`,
COALESCE(
(SELECT D.f1 FROM D WHERE D.fk_b = B.id LIMIT 1), '-'
) AS `D_f1`
FROM B
INNER JOIN A ON (B.fk_a = A.id)
LEFT JOIN C ON (B.id = C.fk_b);
Code above was tested and worked fine on MySQL 5.6
It appears that you have cartesian join.
You could try just putting DISTINCT infront of you column definition or you could so subqueries to link the tables together.
Try
SELECT DISTINCT A.f1
A.f2
B.f1
C.f1
D.f1
from A LEFT JOIN (B INNER JOIN D on D.fk_b = B.id) on A.id = B.fk_a
LEFT JOIN C on C.fk_b = B.id
You can do this:
B INNER JOIN TOP 1 D on.....
Like this
B INNER JOIN (SELECT TOP 1 fields from table) D ON ...
Try this:
SELECT DISTINCT A.f1
A.f2
B.f1
C.f1
D.f1
from A
LEFT JOIN (B INNER JOIN (SELECT DISTINCT fk_b FROM D) D on D.fk_b = B.id)
on A.id = B.fk_a
LEFT JOIN C on C.fk_b = B.id
Related
I want join 6 tables:
Table A join Table B
Table A join Table C
Table A Join Table D
Table D Join Table E
Table E Join Table F
But I can't run it:
SELECT
A.ID, A.Name, A.SName,
B.tel, B.status,
C.ComCode, C.Comdes,
D.Type,
E.Des, E.AreaDes,
F.AreaID
FROM
((((Table A
INNER JOIN
Table B ON A.ID = B.ID)
INNER JOIN
Table C ON A.Concode = C.Comcode)
INNER JOIN
Table D ON A.Type = D.Type)
INNER JOIN
Table E ON D.Des = E.Des)
INNER JOIN
Table F ON E.AreaID = F.AreaID
Get rid of your parentheses and table and it should be vailid SQL, so
SELECT ...
FROM a INNER JOIN b ON a.a = b.a
INNER JOIN c ON b.b = c.a
...
Try this :
SELECT
A.ID, A.Name, A.SName,
B.tel, B.status,
C.ComCode, C.Comdes,
D.Type,
E.Des, E.AreaDes,
F.AreaID
FROM Table A
INNER JOIN Table B ON A.ID = B.ID
INNER JOIN Table C ON A.Concode = C.Comcode
INNER JOIN Table D ON A.Type = D.Type
INNER JOIN Table E ON D.Des = E.Des
INNER JOIN Table F ON E.AreaID = F.AreaID
It will help if you tell us what you database server is e.g., SQL Server, Oracle, MySQL, etc. When you say, "...I can't run it..." are you getting an error? If so, can you share that.
I ditched your parenthesis...
SELECT
A.ID,
A.Name,
A.SName,
B.tel,
B.status,
C.ComCode,
C.Comdes,
D.Type,
E.Des,
E.AreaDes,
F.AreaID
FROM
TableA A INNER JOIN TableB B ON A.ID = B.ID
INNER JOIN TableC C ON A.Concode = C.Comcode
INNER JOIN TableD D ON A.Type = D.Type
INNER JOIN TableE E ON D.Des = E.Des
INNER JOIN TableF F ON E.AreaID = F.AreaID
For clarity, I adjusted your table names (so it was clear what was Table A vs. Table B).
I have two tables Say A and B. A is master table and B is child table, from which I need values as below.
select A.Id, A.Name, B.Path from A,B where A.Id=B.Id
Now, I want to add column of 3rd table which is child of table 'B', say C i.e. C.File.
The value of C.File will be null if C.SubId=B.SubId is false else will return value when condition becomes true.
This is the exact definition of a left join:
SELECT a.id, b.name, b.path, c.file
FROM a
JOIN b ON a.id = b.id
LEFT JOIN c ON b.subid = c.subid
You need to LEFT JOIN your third table from what I can gather.
SELECT A.Id, A.Name, B.Path, C.file
FROM tableA a
INNER JOIN tableB b ON a.id = b.id
LEFT JOIN tableC c ON b.subid = c.subid
Simply Join all the three tables using INNER JOIN
select A.Id, A.Name, B.Path ,C.File
FROM A
INNER JOIN B
ON A.Id=B.Id
INNER JOIN C
ON C.SubId=B.SubId
I would like to add a field to a existing query that doesn't get affected from 'Where function'
For example,
This is the original code....
SELECT SHELL_Payables.PoolNum,
A.[Code], B.[Program] AS Program, A.PayableAmt, C.ReceivableAmt INTO [New Data]
FROM A INNER JOIN B ON A.ID=B.ID
INNER JOIN C ON A.Num=B.Num
WHERE (((A.AccountingPeriod)<=[AccountingYearMonth]));
I would like to add A.PayableAmt again but this time where clause (accountingperiod <= accountingyearMonth) should not be applied to this field...
Any ideas? It would be much appreciated.
To use union and select into, you would need to write your query something like this:
SELECT *
INTO [New Data]
FROM (
SELECT PoolNum
,A.[Code]
,B.[Program] AS Program
,A.PayableAmt
,C.ReceivableAmt
FROM A
INNER JOIN B ON A.ID = B.ID
INNER JOIN C ON A.Num = B.Num
WHERE A.AccountingPeriod <= AccountingYearMonth
UNION
SELECT PoolNum
,A.[Code]
,B.[Program] AS Program
,A.PayableAmt
,C.ReceivableAmt
FROM A
INNER JOIN B ON A.ID = B.ID
INNER JOIN C ON A.Num = B.Num
)
UPDATE
If you want to add another PayableAmt column to the same row, maybe you can join back to the table A something like this:
SELECT t.PoolNum
,a.[Code]
,a.[Program] AS Program
,t.PayableAmt
,a.PayableAmt AS NewPayableAmt
,C.ReceivableAmt
INTO [New Data]
FROM A
LEFT JOIN
(
SELECT
PoolNum
,A.[Code]
,B.[Program] AS Program
,A.PayableAmt
,C.ReceivableAmt
FROM A
INNER JOIN B ON A.ID = B.ID
INNER JOIN C ON A.Num = B.Num
WHERE A.AccountingPeriod <= AccountingYearMonth
) t
ON t.Code = A.Code --assuming this is unique
INNER JOIN B ON A.ID = B.ID
INNER JOIN C ON A.Num = B.Num
I have tables a, b, c, and d whereby:
There are 0 or more b rows for each a row
There are 0 or more c rows for each a row
There are 0 or more d rows for each a row
If I try a query like the following:
SELECT a.id, SUM(b.debit), SUM(c.credit), SUM(d.other)
FROM a
LEFT JOIN b on a.id = b.a_id
LEFT JOIN c on a.id = c.a_id
LEFT JOIN d on a.id = d.a_id
GROUP BY a.id
I notice that I have created a cartesian product and therefore my sums are incorrect (much too large).
I see that there are other SO questions and answers, however I'm still not grasping how I can accomplish what I want to do in a single query. Is it possible in SQL to write a query which aggregates all of the following data:
SELECT a.id, SUM(b.debit)
FROM a
LEFT JOIN b on a.id = b.a_id
GROUP BY a.id
SELECT a.id, SUM(c.credit)
FROM a
LEFT JOIN c on a.id = c.a_id
GROUP BY a.id
SELECT a.id, SUM(d.other)
FROM a
LEFT JOIN d on a.id = d.a_id
GROUP BY a.id
in a single query?
Your analysis is correct. Unrelated JOIN create cartesian products.
You have to do the sums separately and then do a final addition. This is doable in one query and you have several options for that:
Sub-requests in your SELECT: SELECT a.id, (SELECT SUM(b.debit) FROM b WHERE b.a_id = a.id) + ...
CROSS APPLY with a similar query as the first bullet then SELECT a.id, b_sum + c_sum + d_sum
UNION ALL as you suggested with an outer SUM and GROUP BY on top of that.
LEFT JOIN to similar subqueries as above.
And probably more... The performance of the various solutions might be slightly different depending on how many rows in A you want to select.
SELECT a.ID, debit, credit, other
FROM a
LEFT JOIN (SELECT a_id, SUM(b.debit) as debit
FROM b
GROUP BY a_id) b ON a.ID = b.a_id
LEFT JOIN (SELECT a_id, SUM(b.credit) as credit
FROM c
GROUP BY a_id) c ON a.ID = c.a_id
LEFT JOIN (SELECT a_id, SUM(b.other) as other
FROM d
GROUP BY a_id) d ON a.ID = d.a_id
Can also be done with correlated subqueries:
SELECT a.id
, (SELECT SUM(debit) FROM b WHERE a.id = b.a_id)
, (SELECT SUM(credit) FROM c WHERE a.id = c.a_id)
, (SELECT SUM(other) FROM d WHERE a.id = d.a_id)
FROM a
I would like to do something like this but can't get it to work:
SELECT A.*,B.*,C.* FROM tableA A LEFT JOIN
B ON A.ID = B.ID
C ON A.ID = C.ID
I.e. I need to use a field from the first table for all joins as tableB and tableC don't
has any fields to link them together.
Can this be done?
you missed a join !
SELECT A.*,B.*,C.* FROM tableA A
LEFT JOIN
B ON A.ID = B.ID
left join
C ON A.ID = C.ID
Try this one -
SELECT *
FROM dbo.tableA A
LEFT JOIN dbo.B ON A.ID = B.ID
LEFT JOIN dbo.C ON A.ID = C.ID