where col1 from tab1 and col1 from tab2 in select from tab3 - sql

I wanna gets some records from table A and table B, they don't have any common records but my select is depends on from table C which have keys to A and B, for example:
I have 3 tables: A, B and C, something like that:
A
+----+-------+
| ID | NAME |
+----+-------+
| 1 | nameA |
+----+-------+
B
+----+-------+
| ID | NAME |
+----+-------+
| 1 | nameB |
+----+-------+
C
+-----+-----+-------+
| IDA | IDB | NAMEC |
+-----+-----+-------+
| 1 | 1 | nameC |
+-----+-----+-------+
and i wanna get sth like this:
+-------+-------+
| NameA | NameB |
+-------+-------+
| nameA | nameB |
+-------+-------+
so I am trying with:
select a.name, b.name
from tableA a, tableB b
join (select idA, idB
from tableC where nameC='nameC') tmp
on tmp.idA=a.id and tmp.idB=b.id
but its not working

This is just two joins and filtering:
select a.name as nameA, b.name as nameB
from tableC c join
tableA a
on c.idA = a.id join
tableB b
on c.idB = b.id
where c.nameC = 'nameC';
Your code does not work because you are mixing archaic join syntax (commas) with proper, explicit, standard, readable JOIN syntax. Never use commas. Always use JOIN.
The reason your code does not work is because of the scoping rules around commas. The ON clause does not recognize the first table reference.

Related

Oracle SQL: Exclude IDs from another table without subquery join

I would like to know if the following is possible without joining the same table twice:
Table A:
+----+------+
| ID | ColA |
+----+------+
| 1 | A1 |
| 2 | A2 |
| 3 | A3 |
| 4 | A4 |
+----+------+
Table B:
+----+------+
| ID | ColB |
+----+------+
| 1 | B1 |
| 2 | B2 |
| 3 | B3 |
| 4 | B4 |
| 5 | B5 |
| 6 | B6 |
+----+------+
Table C:
+----+
| ID |
+----+
| 1 |
| 2 |
+----+
Desired result: (A LEFT JOIN B WITHOUT C)
+----+------+------+
| ID | ColA | ColB |
+----+------+------+
| 3 | A3 | B3 |
| 4 | A4 | B4 |
+----+------+------+
So basically I need to add Column B to Table A, hence left join, and exclude all IDs which occur in Table C.
Current solution:
SELECT a.id, a.ColA, b.ColB
FROM tableA a
LEFT JOIN tableB b ON a.id = b.id
WHERE a.id NOT IN(
SELECT a2.id FROM tableA a2
LEFT JOIN tableC c on a2.id = c.id)
What's irritating me is, that the exclusion of table C requires an additional left join of table A with table C. Isn't there a more straight-forward approach, without having to join table A again as part of the subquery, if all I want to do is to exclude IDs which occur in table C from the resultset?.
Thanks
Use a not exists:
SELECT a.id, a.ColA, b.ColB
FROM tableA a
LEFT JOIN tableB b ON a.id = b.id
where not exists(select 1 from tablec c where a.id = c.id)
The issue with using a not in with a select in Oracle is that:
a) it has to return the whole subquery dataset
b) if there are nulls, it breaks
TOM link regarding these 2 issues
won't this work?
SELECT a.id, a.ColA, b.ColB
FROM tableA a
JOIN tableB b ON a.id = b.id
WHERE a.id NOT IN (SELECT c.Id FROM tableC c)
this can also be done in a join
SELECT a.id, a.ColA, b.ColB
FROM tableA a
JOIN tableB b ON a.id = b.id
LEFT JOIN tableC C ON a.id = c.id
WHERE c.Id is null

MS ACCESS Group Query

This one really has me scratching my head. It's sort of like a GROUP_CONCAT, but different. I'm pretty sure there is no way to do this with SQL only. I have a query that does a flip-table on a normalized table. The result looks like this:
|_Category_|_FieldA_|_FieldB_|_FieldC_|
|----------|--------|--------|--------|
| CAT1 | A | | |
|----------|--------|--------|--------|
| CAT1 | | B | |
|----------|--------|--------|--------|
| CAT1 | | | C |
|----------|--------|--------|--------|
| CAT1 | D | | |
|----------|--------|--------|--------|
| CAT1 | | | E |
|----------|--------|--------|--------|
| CAT1 | F | | |
|----------|--------|--------|--------|
My challenge is to compress it into as few rows as possible, but only have one value per cell.
|_Category_|_FieldA_|_FieldB_|_FieldC_|
|----------|--------|--------|--------|
| CAT1 | A | B | C |
|----------|--------|--------|--------|
| CAT1 | D | | E |
|----------|--------|--------|--------|
| CAT1 | F | | |
|----------|--------|--------|--------|
Any Ideas?
Thanks in advance.
Mark
As i mentioned in my comment to the question, normalized table should look like:
|_Category_|_F_Name_|_F_Val__|
|----------|--------|--------|
| CAT1 | FieldA | A |
|----------|--------|--------|
| CAT1 | FieldB | B |
|----------|--------|--------|
| CAT1 | FieldC | C |
|----------|--------|--------|
| CAT1 | FieldB | D |
|----------|--------|--------|
| CAT1 | FieldC | E |
|----------|--------|--------|
| CAT1 | FieldA | F |
|----------|--------|--------|
How to achieve that?
SELECT A.Category, "FieldA" AS FieldName, A.FieldA AS FieldValue
FROM TableA AS A
WHERE NOT A.FieldA IS NULL
UNION ALL
SELECT A.Category, "FieldB", A.FieldB
FROM TableA AS A
WHERE NOT A.FieldB IS NULL
UNION ALL
SELECT A.Category, "FieldC", A.FieldC
FROM TableA AS A
WHERE NOT A.FieldC IS NULL;
To export the data into new table, use query:
SELECT B.* INTO TableB
FROM (
--above query
) AS B;
Do not forget to add autonumber field (as primary key) to TableB to be able to identify each record.
As per my understanding, you want to pivot data. It's not so simple, becasue we need to simulate
ROW_NUMBER() OVER(PARTITION BY FieldName, ORDER BY ID)
which is not supported in MS Access. How to workaround it?
SELECT B.ID, B.Category, B.FieldName, B.FieldValue,
(SELECT COUNT(A.FieldName)
FROM TableB AS A
WHERE A.FieldName=B.FieldName AND A.ID >=B.ID
GROUP BY A.FieldName ) AS TRank
FROM TableB AS B;
It should produce below record set:
ID Category FieldName FieldValue TRank
1 CAT1 FieldA A 3
2 CAT1 FieldA D 2
3 CAT1 FieldA F 1
4 CAT1 FieldB B 1
5 CAT1 FieldC C 2
6 CAT1 FieldC E 1
But... you can't use above query as a source of pivot data, because of "The Microsoft Access database engine does not recognize as a valid field name or expression. (Error 3070)" error message. So, finally, you should export these data into another table (let's say TableC).
SELECT C.* INSERT INTO TableC
FROM TableB AS C
Now, you can pivot data:
TRANSFORM First(A.FieldValue) AS FirstOfFieldValue
SELECT A.Category, A.TRank
FROM TableC AS A
GROUP BY A.Category, A.TRank
PIVOT A.FieldName;
Result:
Category TRank FieldA FieldB FieldC
CAT1 1 F B E
CAT1 2 D C
CAT1 3 A
Cheers,
Maciej
I had the same problem. Take a look at: Microsoft Access condense multiple lines in a table
or get the cloud version here https://www.apponfly.com/en/application/microsoft-access-2013
Works pretty good

SQL query with two columns as foreign keys of the same table

I have two tables
Table A
id ! name ! fk_1_table_B_1 ! fk_2_table_B_2
-------|------|----------------|--------------
1 | John | 1 | 3
2 | Paul | 2 | 1
3 | Anna | 4 | 2
4 | Alan ! 3 | 1
Table B
id | code
-------|------
1 | EN
2 | US
3 | FR
4 | IT
The idea is to obtain the following query
id ! name ! code (fk_1_table_B_1) ! code (fk_1_table_B_2)
-------!------!-----------------------!-----------------
1 | John | EN | FR
2 | Paul | US | EN
3 | Anna | IT | US
4 | Alan ! FR | EN
If Table A had only one FK Column from Table B I would do
SELECT tableA, name, tableB.code
FROM tableA, table B
WHERE tableA.fk_1_table_B_1 = tableB.id
How can I do this with Table A having two columns as FK from B? What should I select in the SELECT?EN
Thanks
You should join to the same table twice, giving it two different aliases:
SELECT a.id, a.name, b1.code, b2.code
FROM tableA a
JOIN tableB b1 ON b1.id = a.fk_1_table_B_1
JOIN tableB b2 ON b2.id = a.fk_2_table_B_2
Note how this query uses ANSI join syntax for better clarity: rather than listing all tables in the FROM clause, it puts each of the aliased tableBs in its own JOIN clause.
Maybe this?
select a.id, a.name,
(select b.code from B b where b.id = a.fk_1_table_B_1),
(select c.code from B c where c.id = a.fk_1_table_B_2),
from A a

join table in sqlalchemy with filtering by groups

table A must be outer-joinned with B.
A
id | ...
---|-----
1 |
2 |
3 |
---|-----
B
id| a_id | b | ...
--|------|----------
1 |1 | special |
2 |1 | normal |
3 |2 | normal |
4 |2 | normal |
--------------------
so I want:
A.outerjoin(B)
like this:
a_id | b.id | ...
-----|------|--------
2 | 3 |normal |
2 | 4 |normal |
3 | None |
-----|------|
what should i use to filter entire group of B with the same a_id having at least one "special" value?
I dont want lose outerjoin - None for a.id = 3.
my first idea is to use nested select, but it's not optimal.
select distinct a.*
from a join b on a.id=b.a_id
where b.b='special';
excludes a groups with 'special'
select a.*
from a outer join
(select distinct a.*
from a join b on a.id=b.a_id
where b.b='special') excluded on a.id=excluded.id
having excluded.id is null;
leaves only valid a rows.
select *
from (select a.*
from a outer join
(select distinct a.*
from a join b on a.id=b.a_id
where b.b='special') excluded on a.id=excluded.id
having excluded.id is null) outer join b on a.id=b.a_id;
valid rows outer joined with b

Distinct multi-columns

For this table:
mysql> select * from work;
+------+---------+-------+
| code | surname | name |
+------+---------+-------+
| 1 | John | Smith |
| 2 | John | Smith |
+------+---------+-------+
I'd like to get the pair of code where the names are equal, so I do this:
select distinct A.code, B.code from work A, work B where A.name = B.name group by A.code, B.code;
However, I get the follow result back:
+------+------+
| code | code |
+------+------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
+------+------+
As you can see, This result has 2 duplicates, obviously from a cartesian product. I'd like to find out how I can do this such that it outputs only:
+------+------+
| code | code |
+------+------+
| 1 | 2 |
+------+------+
Any clue? Thanks!
This should work (assuming code is the primary key):
SELECT A.code, B.code
FROM work A, work B
WHERE A.name = B.name AND A.code < B.code
try this
Select A.Code, B.Code
From work a
Join work b
On A.surname = b.surname
And A.Name = B.Name
And A.Code > B.Code
You need to use A.Code > B.Code rather than != to eliminate dupes of the type
{1, 2} and {2, 1}
(If you only care about when the name is the same and not the surname, eliminate that predicate from the join condition)