SQL Multiple Tables - sql

I have 2 sets of 2 corresponding tables (4 tables total). The two sets only correspond in one column. I want the query to search through that one column in both joined tables, and be able to return the value in the selected column, even if that column doesn't exist in the other table.
Currently, my query looks like:
select z
FROM A1
INNER JOIN A2
ON A1.x=A2.x
WHERE A1.x= '25'
UNION
select z
FROM B1
INNER JOIN B2
ON B1.x=B2.x
WHERE B1.x= '25'
UNION works as long as I am looking for a column which both (joined) tables A and B have in common. I'd like to be able to get values from columns which only exist in A or in B, but not necessarily both of them.
Thanks in advance.
Edit:
Basically, I want two completely separate queries on separate tables, but in one query, with only one select.
Example:
Table A1
x | y
------
1 | a
2 | b
Table A2
x | z
------
1 | c
2 | d
Table B1
x | v
------
3 | e
4 | f
Table B2
x | w
------
3 | g
4 | h
So I want look for a column variable (such as v,w,y, or z), with a specified value of x. e.g. select w where x=4 should give me h; select z where x=2 should give me d.

You must have the same number of columns in each select statement when using UNION. You can add constant values for columns that are missing. You must also have the same data type for each column.
select Column1, null as Column2
from T1
union
select '', Column2
from T2
As per comment by #Adrian, you can of course use null as a constant value. Otherwise you need to pick a constant value of the data type that is used for the column.
select Column1, null as Column2
from T1
union
select null, Column2
from T2
Use the sample data provided in the question:
select A1.x, A2.z as 'y'
from A1
inner join A2
on A1.x=A2.x
where A1.x= 4
union
select B1.x, B2.w as 'y'
from B1
inner join B2
on B1.x=B2.x
where B1.x= 4
Result:
x y
4 h
With a 2 instead of a 4
Result:
x y
2 d

It would be something like that:
select Column1, ColumnThatOnlyExistsInContextA, null as ColumnThatOnlyExistsInContextB
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column1, null, ColumnThatOnlyExistsInContextB
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'

When using UNION, make sure all queries return result sets that have the same number of columns with the same type. If you want to return a column from the second query in a union that the first query doesn't have, you can modify your first query to have a NULL value for that column.

So you basically want to do:
select Column1
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column2
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'
right?
If so, your problem is probably just that Column1 and Column2 are different types. So, do something like
select cast(Column1 as varchar(255))
and
select cast(Column2 as varchar(255))
Should work!

Well, UNION's only requirement is that the number and type of the fields in each result set being UNIONed must match. So, if B has a Column2 and A doesn't, you can select Column1 from the joined As and Column2 from the joined Bs, and provided A.Column1 and B.Column2 are the same type (you can CAST or CONVERT if necessary) the statement will still work. Maybe I'm not understanding the problem, but I think it's pretty easy to solve.

Related

SQL query with both table columns-Oracle

There are two tables named, for an example A and B.
A and B has a unique column named key_ref. and key_ref is the primary key of both tables
I need to find records in A but not in B. Therefore I wrote a query like,
SELECT a.*,b* from A a,B b WHERE key_ref NOT IN (SELECT key_ref from B)
The issue with this is, I do not get the empty columns of table B for the result. My result should include all the columns of A and B.
If I write my query like following my results get wrong. Is there any way , where I can achieve this even with a join condition.
SELECT a.* from A a WHERE key_ref NOT IN (SELECT key_ref from B)
Please refer following example.
Table A Table B
key ref col1 key ref col2
A aaa A aaa
B bbb B bbb
C ccc C ccc
D ddd
My answer should be,
key ref col1 col2
D ddd
If I understand your request:
You can use a LEFT OUTER JOIN operation so you'll get all rows in A not present in B (with condition in WHERE b.key_ref IS NULL)
Try this:
SELECT *
FROM a
LEFT OUTER JOIN b
ON a.key_ref = b.key_ref
WHERE b.key_ref IS NULL
Is this what you need:
select * from A
except
select * from B
?
If the second table tableB doesn't have a record associated with first table, then how would you display record from second table tableB which are not exists in the first table tableA.
So, the one way is to include NULL as columns ref. to tableB like that :
select a.*, null col2
from tableA a
where not exists (select 1 from tableB b where b.key_ref = a.key_ref);

SQL query to delete/identify cross linked data in a table

I've a SQL DB table ABC, in that I've two columns i.e. column1 and column2.
In this table I have some data like.
column1 column2
-------------------
1 2
1 7
2 1
3 4
7 1
4 3
Now, I have to delete the data from this table which are cross linked to each other. for e.g.
(1,2) are cross linked to (2,1)
(1,7) are cross linked to (7,1)
(3,4) are cross linked to (4,3)
So, I need to delete one of value from this pair. My final output should be like:
column1 column2
-------------------
1 2
1 7
3 4
OR
column1 column2
-------------------
2 1
4 3
7 1
I want to write a sql query to do this. Anyone has any idea how can I achieved this?
Try this:
SQLFIDDLE
with pairs as (select
case when c1< c2 then c1 else c2 end as minc,
case when c1< c2 then c2 else c1 end as maxc
from t
group by
case when c1< c2 then c1 else c2 end ,
case when c1< c2 then c2 else c1 end
having count(*) >1)
select *
from t
where not exists
(select * from pairs
where c1= minc and c2= maxc
)
Explain
The CTE table returns all paired rows of one side.
Through NOT EXISTS, it returns all rows not paired
If you change the condition of where c1= minc and c2= maxc to where c2= minc and c1= maxc will get the opposite side of the pairs.
If you want delete one side of those pairs, with DELETE FROM T WHERE EXISTS instead of NOT EXISTS
There have some different ways to get paired rows.
SELECT A.* FROM test A LEFT JOIN test B
ON A.column1 = B.column2 AND A.column2 = B.column
WHERE B.column IS NULL;
This should work, assuming your OK with something like (2,2) also being excluded.

Select full outer join from many-to-many relationships

I am trying to do something in MSSQL which I suppose is a fairly simple and common thing in any database with many-to-many relationships. However I seem to always end up with a quite complicated select query, I seem to be repeating the same conditions several times to get the desired output.
The scenario is like this. I have 2 tables (table A and B) and a cross table with foreign keys to the ID columns of A and B. There can only be one unique pair of As and Bs in the crosstable (I guess the 2 foreign keys make up a primary key in the cross table ?!?). Data in the three tables could look like this:
TABLE A TABLE B TABLE AB
ID Type ID Type AID BID
--------------------------------------------------
R Up 1 IN R 3
S DOWN 2 IN T 3
T UP 3 OUT T 5
X UP 4 OUT Z 6
Y DOWN 5 IN
Z UP 6 OUT
Now let's say I select all rows in A of type UP and all rows in B of type OUT:
SELECT ID FROM A AS A1
WHERE Type = 'UP'
(Result: R, T, X, Z)
SELECT ID FROM B AS B1
WHERE Type = 'OUT'
(Result: 3, 4, 6)
What I want now is to fully outer join these 2 sub queries based on the relations listed in AB. Hence I want all IDs in A1 and B1 to be listed at least once:
A.ID B.ID
R 3
T 3
null 4
X null
Z 6
From this results set I want to be able to see:
- Which rows in A1 does not relate to any rows in B1
- Which rows in B1 does not relate to any rows in A1
- Relations between rows in A1 and B1
I have tried a couple of things such as:
SELECT A1.ID, B1.ID
FROM (
SELECT * FROM A
WHERE Type = 'UP') AS A1
FULL OUTER JOIN AB ON
A1.ID = AB.AID
FULL OUTER JOIN (
SELECT * FROM B
WHERE Type = 'OUT') AS B1
ON AB.BID = B1.ID
This doesn't work, since some of the relations listed in AB are between rows in A1 and rows NOT IN B1 OR between rows in B1 but NOT IN A1.
In other words - I seem to be forced to create a subquery for the AB table also:
SELECT A1.ID, B1.ID
FROM (
SELECT * FROM A
WHERE Type = 'UP') AS A1
FULL OUTER JOIN (
SELECT * FROM AB AS AB1
WHERE
AID IN (SELECT ID FROM A WHERE type = 'UP') AND
BID IN (SELECT ID FROM B WHERE type = 'OUT')
) AS AB1 ON
A1.ID = AB1.AID
FULL OUTER JOIN (
SELECT * FROM B
WHERE Type = 'OUT') AS B1
ON AB1.BID = B1.ID
That just seems like a rather complicated solution for a seemingly simply problem. Especially when you consider that for A1 and B1 subqueries with more (complex) conditions - possible involving joins to other tables (one-to-many) would require the same temporary joins and conditions to be repeated in the AB1 subquery.
I am thinking that there must be an obvious way to rewrite the above select statements in order to avoid having to repeat the same conditions several times. The solution is probably right there in front me, but I just can't see it.
Any help would be appreciated.
I think you could employ a CTE in this case, like this:
;WITH cte AS (
SELECT A.ID AS AID, A.Type AS AType, B.ID AS BID, B.Type AS BType
FROM A FULL OUTER JOIN AB ON A.ID = AB.AID
FULL OUTER JOIN B ON B.ID = AB.BID)
SELECT AID, BID FROM CTE WHERE AType = 'UP' OR BType = 'OUT'
The advantage of using a CTE is that it will be compiled once. Then you can add additional criteria to the WHERE clause outside the CTE
Check this SQL Fiddle

I'm getting an #Error message in my Access join queries, but I'm not sure why

I'm attempting to merge two separate sets of data. Between the two sets of data, some entries may be duplicates.
Table 1:
Common Field A | Field 1 | Field 2
---------------------------------
a a1 a2
b b1 b2
Table 2:
Common Field B | Field 3 | Field 4
---------------------------------
c c1 c2
a a1 a2
I did a union query on the common field to get:
Common Field
---------------
a
b
c
Now I did 2 joins. One join between the union query and table 1, and one join between the union query and table 2. Basically each join is done so that all the entries of the union query will be listed, and the rows where the common fields from the tables matches the union query entries will be listed. After doing this I created a query with all the columns (keeping in mind the above two joins). Here is what I expected:
Common Field | Common Field A | Common Field B | Field 1 | Field 2 | Field 3 | Field 4
------------------------------------------------------------------------------------------
a a a a1 a2 a1 a2
b b b1 b2
c c c1 c2
Here's what I'm getting:
Common Field | Common Field A | Common Field B | Field 1 | Field 2 | Field 3 | Field 4
------------------------------------------------------------------------------------------
a a a a1 a2 a1 a2
b b #Error b1 b2
c #Error c c1 c2
I'm not sure why I'm getting the #Error signs, and I'm just as confused as to why I'm only getting them for the Common Field entries. If anything, I would have expected to at least get them like this:
Common Field | Common Field A | Common Field B | Field 1 | Field 2 | Field 3 | Field 4
------------------------------------------------------------------------------------------
a a a a1 a2 a1 a2
b b #Error b1 b2 #Error #Error
c #Error c #Error #Error c1 c2
Is there any way to get rid of them? I've tried using IIF(IsError(....)) but that hasn't worked. I found a couple of attempts online where people have tried to get to get rid of #Error message but were unable to solve it. I know it's better to get to the root of the problem, but at this point I'm okay with just getting rid of the #Error message itself. Any ideas on how I should approach this?
EDIT: Here's some example SQL:
SELECT qryUnion.CommonField, tbl1.CommonFieldA, tbl2.CommonFieldB, tbl1.Field1, tbl1.Field2, tbl2.Field3, tbl2.Field4
FROM tbl2 RIGHT JOIN ( tbl1 RIGHT JOIN qryUnion ON tbl1.CommonFieldA = qryUnion.CommonField) ON tbl2.CommonFieldB = qryUnion.CommonField;
EDIT2: Here's the SQL for the join if that's important:
SELECT tbl1.CommonFieldA FROM tbl1 UNION tbl2.CommonFieldB FROM tbl2
I'm guessing you've done this in a query window, given the displays of #error, and the syntax of your query.
Create a new query, get rid of the add table window, put it into SQL view, then put this logic in it:
select c.unique, a.commonfieldA, b.commonfieldB, a.field1, a.field2, b.field3, b.field4
from (
select distinct u as unique from (
select commonfieldA as u from tbl1
union all
select commonfieldB as u from tbl2
) combined ) c
left join tbl1 a on c.unique = a.commonfieldA
left join tbl2 b on c.unique = b.commonfieldB
This should work. I dont use the Union syntax you've got, and instead select distinct values from union-all'd composite (subquery "combined"). Left join means that the data must exist in the table on the left of the join condition (ie c, being the table which defined prior to the declaration of either tbl1 or tbl2) but data may or may not exist in the table on the right.
I would put your problem down to the syntax access generates for you, in it's attempt to understand what you're trying to do: That it showed "#Error" says to me that it didnt understand.

SQL Getting Data with extra row

I have two tables with columns of my interests as Table1.Column1 and Table2.Column2
Table1 is Kind of a Group Table and Table2 is items table. The join query of these two tables gets the data in the followinf format
Column1 Column2
A 1
A 2
B 1
B 2
B 3
What I want is to get data in the following format:
Column1 Column2
A 0
A 1
A 2
B 0
B 1
B 2
B 3
i.e. getting extra 0 for each group at the start each time. The 0 does not exits in the database.
Does anyone know how to achive this in SQL?
Many Thanks,
This is one way to do it.
SELECT DISTINCT Column1, [Column2] = 0
FROM (
YourOriginalQuery
) q
UNION ALL
YourOriginalQuery
Most likely, there are better solutions by incorporating this requirement into your original query. If you post your query, we can come up with better alternatives.
Or something like:
select C.CategoryId, drv.CategoryGroupId from Category as C
cross join (
select 0 as CategoryGroupId
UNION
select CG.CategoryGroupId from CategoryGroup as CG
)drv order by CategoryId, CategoryGroupId