SQL UNION - illogical results - sql

I have an interesting problem with UNION in SQL.
My Statement is of this form:
with tab as (
(select FldA, FldB From Table1A inner join Table1B on Field1A=Field1B)
UNION
(select FldA, FldB From Table2A inner join Table2B on Field2A=Field2B)
)
select * from tab
where FldA="XYZ"
When I run this, I get only 1 row returned - which is not correct. I can verify it's not correct just by commenting the UNION and second Select statement:
with tab as (
(select FldA, FldB From Table1A inner join Table1B on Field1A=Field1B)
--UNION
--(select FldA, FldB From Table2A inner join Table2B on Field2A=Field2B)
)
select * from tab
where FldA="XYZ"
If I run this version, I get THREE rows returned! I assume I'm doing something stupid - but I can't imagine what.

UNION removes duplicates, to keep duplicates use UNION ALL.
In this sense, UNION works the same as DISTINCT. As with DISTINCT records are considered duplicates if the records are identical for every (selected) column.
UNION removes duplicates regardless of in which set the duplicates occur, since the DISTINCT is executed after the UNION.
If you have 2 queries/data sets A and B, if you UNION these together, you get the DISTINCT combination of both. If there are duplicates in A they are removed. If a record exists in A and in B, it is also returned uniquely (i.e., it only occurs once in your final result set).

union removes duplicates from the result. A common "gotcha" with it is that it removes any duplicates from the results, regardless of whether they're duplicate between the two result sets or within any one of the result sets.
If you need to preserve these duplicates, you could use union all instead.

Related

Combining two different result set into a single query

Two different queries, produce two different result set.
Query 1:
Select a.customer_name, b.salary, c.manager_name
from
table123 a
left join table456 b on a.id=b.id
left join table789 c on a.id=c.id
Query2:
Select d.prty_id, e.party_val, f.prty_nme
from
table111 d
Left join table222 e on d.id=e.id
Left join table333 f on d.id=f.id
Now I have to write one single query, which will merge this above two query's result set and display one single result set.
Can anyone please help me on this.
Output value I need to insert in a new table whose column will be like below:
customer_name salary manager_name prty_id party_val prty_nme
According to your expected result, you can use UNION or UNION ALL.
The Oracle UNION operator is used to combine the result sets of 2 or more Oracle SELECT statements. It removes duplicate rows between the various SELECT statements.
The Oracle UNION ALL operator is used to combine the result sets of 2 or more SELECT statements. It returns all rows from the query and it does not remove duplicate rows between the various SELECT statements.
Select con1,... , coln
from tab1
where...
union
Select con1,... , coln
from tab2
where...
Just make sure your data types match up.

Join new rows [SQL]

I have a left table with unique rows, and a right table that has those same unique rows + new unique ones. What's the right query to keep the unique rows from the left table (better quality data), and bring in only the new rows from the right table that don't exist in the left one already?
What about something like this?
SELECT a.id, a.data
FROM table_a
UNION ALL
SELECT b.id, b.data
FROM table_b
WHERE b.id NOT IN (SELECT id FROM table_a)
You could just UNION them. Depending on your DBMS, UNION will drop duplicates and UNION ALL will preserve them.
If you (for some reason) need to use joins instead of union, you could use a FULL JOIN and use ISNULL() or COALESCE() on each column.
This will leave everything from the left table plus everything from the right table that doesn't exist on the left.

SQL help, left join with filter

Please have a look at the SQL in the SQLFiddle link below.
http://sqlfiddle.com/#!9/22e094/4
My goal is to get all the records from Table1, and if SecId exists in Table2, join only if the status is 'Y'.
Result should be that it pulls from table 1: ID 1 and 2. And for ID 1, it successfully left joins Table2 and pulls 'Y'
As you can see in the fiddle, I tried 3 different ways but can't seem to get it.
It's got me stumped... Help would be awesome! :)
The left join, with just the join condition in the ON clause, is fine.
But then, you said you want to keep the rows where status is 'Y' only when the secid exists in table2. So this means you also want to keep the rows where the secid from table2 is NULL.
select * won't fly, because you have columns by the same name, secid, in both tables. You must distinguish them (by giving them aliases - or at least one of them; I gave aliases to both of them) if you need to reference them in the where clause, or anywhere else in the query, to break the ambiguity. And, since the aliases can only be given in the SELECT clause, which is evaluated after the WHERE clause, you need to do the left join in a subquery.
select id, secid_a, secid_b, status
from (
select a.id, a.secid as secid_a, b.secid as secid_b, b.status
from table1 a left join table2 b
on a.secid = b.secid
)
where status = 'Y' or secid_b is null;

Comparing two datasets SQL SSRS 2005

I have two datasets on two seperate servers. They both pull one column of information each.
I would like to build a report showing the values of the rows that only appear in one of the datasets.
From what I have read, it seems I would like to do this on the SQL side, not the reporting side; I am not sure how to do that.
If someone could shed some light on how that is possible, I would really appreciate it.
You can use the NOT EXISTS clause to get the differences between the two tables.
SELECT
Column
FROM
DatabaseName.SchemaName.Table1
WHERE
NOT EXISTS
(
SELECT
Column
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
Table1.Column = Table2.Column --looks at equalities, and doesn't
--include them because of the
--NOT EXISTS clause
)
This will show the rows in Table1 that don't appear in Table2. You can reverse the table names to find the rows in Table2 that don't appear in Table1.
Edit: Made an edit to show what the case would be in the event of linked servers. Also, if you wanted to see all of the rows that are not shared in both tables at the same time, you can try something as in the below.
SELECT
Column, 'Table1' TableName
FROM
DatabaseName.SchemaName.Table1
WHERE
NOT EXISTS
(
SELECT
Column
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
Table1.Column = Table2.Column --looks at equalities, and doesn't
--include them because of the
--NOT EXISTS clause
)
UNION
SELECT
Column, 'Table2' TableName
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
NOT EXISTS
(
SELECT
Column
FROM
DatabaseName.SchemaName.Table1
WHERE
Table1.Column = Table2.Column
)
You can also use a left join:
select a.* from tableA a
left join tableB b
on a.PrimaryKey = b.ForeignKey
where b.ForeignKey is null
This query will return all records from tableA that do not have corresponding records in tableB.
If you want rows that appear in exactly one data set and you have a matching key on each table, then you can use a full outer join:
select *
from table1 t1 full outer join
table2 t2
on t1.key = t2.key
where t1.key is null and t2.key is not null or
t1.key is not null and t2.key is null
The where condition chooses the rows where exactly one match.
The problem with this query, though, is that you get lots of columns with nulls. One way to fix this is by going through the columns one by one in the SELECT clause.
select coalesce(t1.key, t2.key) as key, . . .
Another way to solve this problem is to use a union with a window function. This version brings together all the rows and counts the number of times that key appears:
select t.*
from (select t.*, count(*) over (partition by key) as keycnt
from ((select 'Table1' as which, t.*
from table1 t
) union all
(select 'Table2' as which, t.*
from table2 t
)
) t
) t
where keycnt = 1
This has the additional column specifying which table the value comes from. It also has an extra column, keycnt, with the value 1. If you have a composite key, you would just replace with the list of columns specifying a match between the two tables.

SQL select sum from multiple tables without JOIN

I have several tables with the same structure. How can I select SUM(field) from these tables without JOIN (just simply union the tables)?
For example, if I run:
SELECT SUM(views) FROM tb1, tb2 WHERE 1
It tells me "Column 'views' in field list is ambiguous".
Is there a way to use UNION?
I think this should get you:
SELECT SUM(views)
FROM (
SELECT views FROM table1
UNION ALL
SELECT views FROM table2
) A
The reason you're getting an error is because you're making a Cartesian product (all rows in one table are matched to all rows in the other table), and since both tables have a view column, it doesn't know which you're taking about. However, that Cartesian join will (probably) not give you the sum you're looking for.
If the structure is the same:
SELECT SUM(views)
FROM (tb1 UNION tb2)
WHERE 1
If that doesn't work, try (I don't have a mysql handy to test it):
SELECT SUM(views)
FROM (
(SELECT views FROM tb1)
UNION
(SELECT views FROM tb2)
)
WHERE 1
SELECT SUM(views) FROM
(
SELECT views FROM tb1
UNION ALL
SELECT views FROM tb2
) t