How to avoid using subquery in this situation Access SQL - sql

Hi I have a situation where I need to Join two tables but filter value from a third table. As below:
SELECT a.Key , (SELECT SUM(B.hours) FROM tableB as B
INNER JOIN tableC as C ON B.List=C.List
WHERE C.Status = 'Approved' AND B.Key LIKE A.key) ,
(SELECT SUM(B.hours) FROM tableB as B
INNER JOIN tableC as C ON B.List=C.List
WHERE C.Status = 'Pending' AND B.Key LIKE A.key)
FROM tableA as A GROUP BY A.key
is there another way to do this without using correlated subqueries? i'd like to use joins , but i just don't know how to link table C into this picture.
Thanks in advance.

The subquery may not be such a bad idea, but you can do this with conditional aggregation:
SELECT a.Key,
sum(iif(c.Status = "Approved", B.hours, 0)),
sum(iif(c.Status = "Pending", B.hours, 0))
FROM tableA as A left join
(tableB as b inner join
tableC as c
on b.list = c.list
)
on b.key like a.key
GROUP BY A.key;
MS Access has arcane syntax for joins, particularly for multiple joins. I think the above is correct.

Related

SQL Server : joining/ merging tables

Assume there are three total tables A,B, and C
Each table contains following attributes:
Table A: "date", "id", "tv_sales_amt"
Table B: "date", "id", "newspaper_sales_amt"
Table C: "date", "id", "radio_sales_amt"
Using join operators, I'm trying to achieve a single table view with:
Result table:
"date", "id", "tv_sales_amt", "newspaper_sales_amt", "radio_sales_amt"
Desired look of the result table:
date id tv_sales_amt newspaper_sales_amt radio_sales_amt
--------------------------------------------------------------------
20190101 012C 2000 1850 NULL
20190102 102D 1000 NULL 1300
.
.
.
Here are some queries that I've tried:
Query #1:
SELECT
A.date, A.id, tv_sales_amt, newspaper_sales_amt, radio_sales_amt
FROM A
INNER JOIN B ON A.id = B.id
INNER JOIN C ON A.id = C.id
Using inner inner-join, I get duplicated values, which is understandable but is not what I'm looking for.
Query #2:
SELECT
A.date, A.id, tv_sales_amt, newspaper_sales_amt, radio_sales_amt
FROM A
FULL OUTER JOIN B ON A.id = B.id
FULL OUTER JOIN C ON A.id = C.id
Since inner-join would only return results from Table B and C (newspaper_sales_amt and radio_sales_amt) that intersects with Table A, I tried full-outer-join in the hopes that it would give me overview of entire results, even though it includes null values.
With both options that I've tried, I wasn't able to get the expected result (Desired look described above).
Would someone be able to tell me what I'm doing wrong here?
I'm using the latest version of SQL Server Management Studio.
I do know that there must be lots of null values if I were to take an overview of tv_sales_amt, newspapers_sales_amt, and radio_sales_amt, but currently, there are no null values but with duplicates.
Your description implies that date also should be the part of joins.
select coalesce(a.date, b.date, c.date) [date],
coalesce(a.id, b.id, c.id) id,
a.tv_sales_amt, b.newspaper_sales_amt, c.radio_sales_amt
from tableA a
full join tableB b on a.id = b.id and a.date = b.date
full join tableC c on (c.id = b.id and c.date = b.date) or
(c.id = a.id and c.date = a.date);
EDIT: This is DbFiddle demo. Try removing coalesce() for date or id (removing in only one of them helps to see it better).
EDIT: Maybe this shows the need for coalesce() better:
select coalesce(a.date, b.date, c.date) [date],
a.id idA, b.id idB, c.id idC,
a.tv_sales_amt, b.newspaper_sales_amt, c.radio_sales_amt
from tableA a
full join tableB b on a.id = b.id and a.date = b.date
full join tableC c on (c.id = b.id and c.date = b.date) or
(c.id = a.id and c.date = a.date);
Full outer joins are tricky. I would suggest:
SELECT COALESCE(A.DATE, B.DATE, C.DATE) as date,
COALESCE(A.ID, B.ID, C.ID) as id,
A.tv_sales_amt, B.newspaper_sales_amt, C.radio_sales_amt
FROM A FULL JOIN
B
ON B.id = A.id AND
B.date = A.date FULL JOIN
C
ON C.id = COALESCE(A.id, B.id) AND
C.date = COALESCE(B.date, B.date);
I find that using COALESCE() in the ON clause simplifies adding more conditions. From a performance perspective, both COALESCE() and OR are pretty bad.

Join WHERE clause - table has row with defined value, or no entry

Can anyone help me figure out the correct WHERE clause for the following scenario:
select A.name
from tableA A, tableB B
where A.id = B.id
and
(
B.field = 5
OR
B.hasNoRowForJoinedID
)
I feel like I'm missing something really obvious here in how to accomplish this, but I can't for the life of me put my finger on it.
You are using an outdated SQL Syntax. To perform the LEFT OUTER JOIN based your your request above, you can do the following:
SELECT A.name
FROM A
LEFT OUTER JOIN B ON A.id = B.id
WHERE (B.field = 5 OR B.field IS NULL)
Use proper join syntax and not the outdated ones:
select A.name
from tableA A
left join tableB B on A.id = B.id and B.field = 5

How can you perform a join when also using a comma-separated list of tables in an SQL select statement?

This is evidently correct syntax in SQL Server:
SELECT a.id, b.name
FROM Table1 a, Table2 b
WHERE a.id = b.fk1
So is this:
SELECT a.id, c.status
FROM Table1 a
JOIN Table3 c ON a.id = c.fk2
But this apparently isn't:
SELECT a.id, b.name, c.status
FROM Table1 a, Table2 b
JOIN Table3 c ON a.id = c.fk2
WHERE a.id = b.fk1
I would NOT normally want to construct a query in the third case's style (and really not the first case's either), but it would probably be the path of least resistence in editing some code that's already been written at my company. Somebody used the first form with five different tables, and I really need to work in a sixth table through a JOIN statement, without taking chances of messing up what they already have. Even though I could re-write their stuff outright if I need to, I would really like to know how to do something like in the third case.
Running the code exactly as-is in the examples, the third case gives me this error message:
The multi-part identifier "a.id" could not be bound.
What is syntactically breaking the third case? What simple fix could be applied? Thanks!
I, likewise, would not recommend doing this. But, you can just change the , to a cross join:
SELECT a.id, b.name, c.status
FROM Table1 a cross join Table2 b
JOIN Table3 c ON a.id = c.fk2
WHERE a.id = b.fk1
This code:
SELECT a.id, b.name, c.status
FROM Table1 a, Table2 b
JOIN Table3 c ON a.id = c.fk2
WHERE a.id = b.fk1
is doing a cross join on a and the result of an inner join on b and c. c cannot access any of the fields in a because the join is being performed on b. what you should do is change your query to:
SELECT a.id, b.name, c.status
FROM Table1 a
inner join Table2 b on a.id = b.fk1
inner JOIN Table3 c ON a.id = c.fk2

Simulate a left join without using "left join"

I need to simulate the left join effect without using the "left join" key.
I have two tables, A and B, both with id and name columns. I would like to select all the dbids on both tables, where the name in A equals the name in B.
I use this to make a synchronization, so at the beginning B is empty (so I will have couples with id from A with a value and id from B is null). Later I will have a mix of couples with value - value and value - null.
Normally it would be:
SELECT A.id, B.id
FROM A left join B
ON A.name = B.name
The problem is that I can't use the left join and wanted to know if/how it is possible to do the same thing.
you can use this approach, but you must be sure that the inner select only returns one row.
SELECT A.id,
(select B.id from B where A.name = B.name) as B_ID
FROM A
Just reverse the tables and use a right join instead.
SELECT A.id,
B.id
FROM B
RIGHT JOIN A
ON A.name = B.name
I'm not familiar with java/jpa. Using pure SQL, here's one approach:
SELECT A.id AS A_id, B.id AS B_id
FROM A INNER JOIN B
ON A.name = B.name
UNION
SELECT id AS A_id, NULL AS B_id
FROM A
WHERE name NOT IN ( SELECT name FROM B );
In SQL Server, for example, You can use the *= operator to make a left join:
select A.id, B.id
from A, B
where A.name *= B.name
Other databases might have a slightly different syntax, if such an operator exists at all.
This is the old syntax, used before the join keyword was introduced. You should of course use the join keyword instead if possible. The old syntax might not even work in newer versions of the database.
I can only think of two ways that haven't been given so far. My last three ideas have already been given (boohoo) but I put them here for posterity. I DID think of them without cheating. :-p
Calculate whether B has a match, then provide an extra UNIONed row for the B set to supply the NULL when there is no match.
SELECT A.Id, A.Something, B.Id, B.Whatever, B.SomethingElse
FROM
(
SELECT
A.*,
CASE
WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN 1
ELSE 0
END Which
FROM A
) A
INNER JOIN (
SELECT 1 Which, B.* FROM B
UNION ALL SELECT 0, B* FROM B WHERE 1 = 0
) B ON A.Which = B.Which
AND (
A.Which = 0
OR (
A.Which = 1
AND A.Id = b.Id
)
)
A slightly different take on that same query:
SELECT A.Id, B.Id
FROM
(
SELECT
A.*,
CASE
WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN A.Id
ELSE -1 // a value that does not exist in B
END PseudoId
FROM A
) A
INNER JOIN (
SELECT B.Id PseudoId, B.Id FROM B
UNION ALL SELECT -1, NULL
) B ON A.Which = B.Which
AND A.PseudoId = B.PseudoId
Only for SQL Server specifically. I know, it's really a left join, but it doesn't SAY LEFT in there!
SELECT A.Id, B.Id
FROM
A
OUTER APPLY (
SELECT *
FROM B
WHERE A.Id = B.Id
) B
Get the inner join then UNION the outer join:
SELECT A.Id, B.Id
FROM
A
INNER JOIN B ON A.name = B.name
UNION ALL
SELECT A.Id, NULL
FROM A
WHERE NOT EXISTS (
SELECT *
FROM B
WHERE A.Id = B.Id
)
Use RIGHT JOIN. That's not a LEFT JOIN!
SELECT A.Id, B.Id
FROM
B
RIGHT JOIN A ON B.name = A.name
Just select the B value in a subquery expression (let's hope there's only one B per A). Multiple columns from B can be their own expressions (YUCKO!):
SELECT A.Id, (SELECT TOP 1 B.Id FROM B WHERE A.Id = B.Id) Bid
FROM A
Anyone using Oracle may need some FROM DUAL clauses in any SELECTs that have no FROM.
You could use subqueries, something like:
select a.id
, nvl((select b.id from b where b.name = a.name), "") as bId
from a
you can use oracle + operator for left join :-
SELECT A.id, B.id
FROM A , B
ON A.name = B.name (+)
Find link :-
Oracle "(+)" Operator
SELECT A.id, B.id
FROM A full outer join B
ON A.name = B.name
where A.name is not null
I'm not sure if you just can't use a LEFT JOIN or if you're restricted from using any JOINS at all. But as far as I understand your requirements, an INNER JOIN should work:
SELECT A.id, B.id
FROM A
INNER JOIN B ON A.name = B.name
Simulating left join using pure simple sql:
SELECT A.name
FROM A
where (select count(B.name) from B where A.id = B.id)<1;
In left join there are no lines in B referring A so 0 names in B will refer to the lines in A that dont have a match
+ or A.id = B.id in where clause to simulate the inner join

3 table sql join

I need to join tableA, tableB, and tableC, but it's possible that tableB won't have a corresponding row. Posted below is how I am currently doing the query. The problem with it is that if tableB doesn't have a correspoinding row, it won't return a result. My sql skills are very rusty so I appreciate your help. Thanks.
SELECT [column names]
FROM tableA AS a, tableB AS b, tableC as c
WHERE b.blah = a.blah
AND c.foo = a.foo
AND [more where conditions]
Don't use the , syntax. Use JOIN to allow for a readable LEFT JOIN...
SELECT
*
FROM
tableA
LEFT JOIN
tableB
ON TableB.x = TableA.y
LEFT JOIN
tableC
ON TableC.x = TableB.y
AND TableC.y = TableA.z
Use a LEFT JOIN.
SELECT [column names]
FROM
tableA AS a
LEFT JOIN tableB AS b ON b.blah = a.blah
JOIN tableC as c ON c.foo = a.foo
SELECT [column names]
FROM tableA AS a INNER JOIN tableC as c ON (c.foo = a.foo)
LEFT OUTER JOIN tableB as B on (b.blah = a.blah)
WHERE [more where conditions]
If the [more where conditions] are on B, then you need to include them in the OUTER JOIN ON clause.
The terminology here (so you can look up more details) is an Outer Join. The other answer(s) are fine -- but watch out for whether you want an INNER or OUTER join on table c (do you want records returned if there are no matching rows in tableC)? Here is a link for the general issue.
http://www.w3schools.com/sql/sql_join_left.asp