Union with no duplicate only for first column - sql

I am using the UNION syntax to retrieve a product code and description from several databases.
I want to retrieve only a unique product code, even if this product code has several descriptions. I want to retreive only the first result.
To do that, I am using this script:
SELECT * FROM (SELECT tab1.code, tab1.description FROM tab1
UNION
SELECT tab2.code, tab2.description FROM tab2
UNION
SELECT tab3.code, tab3.description FROM tab3)
Unfortunately, this script will retrieve several product codes if the specific product has more than one description.
How can this be modified to retrieve only the first occurrence with a description?

If you want ANY one description, you can go with max or min like this:
select code, max(description) from (your set of unions)
group by code
In this case, you can change UNION to UNION ALL to skip on sorting.
If you really want the first one, you would need to indicate it:
select code, description from (
select code, description, ord, min(ord) over (partition by code) min_ord from (
select code, description, 1 as ord from table1
union all
select code, description, 2 as ord from table2
union all
select code, description, 3 as ord from table3
)
) where ord = min_ord

I think that this solution works but maybe it is not elegant.
SELECT * FROM
(
SELECT tab1.code, tab1.description FROM tab1
UNION
SELECT tab2.code, tab2.description FROM tab2 WHERE tab2.code not in
(SELECT tab1.code FROM tab1)
UNION
SELECT tab3.code, tab3.description FROM tab3 WHERE tab3.code not in
(SELECT tab1.code FROM tab1
UNION
SELECT tab2.code FROM tab2)
)

Your query might be more efficient with a full outer join, if there are no duplicates within a table and description does not take on NULL values:
SELECT coalesce(tab1.code, tab2.code, tab3.code) as code,
coalesce(tab1.description, tab2.description, tab3.description) as description
FROM tab1 full outer join
tab2
on tab2.code = tab1.code full outer join
tab3
on tab3.code = coalesce(tab1.code, tab2.code);
This saves the duplicate elimination step (or aggregation) and allows better use of indexes.

Related

Sql Server Query design

I have two tables in Sql Server Table1 and Table2.
The First Table has PartID, Code, Brand
The Second Table has ID, PartID, AddCode, AddBrand
The idea is that the first table is main table where Some Article is entered with his original code and Brand.
The Second Table is table where we can store additional Codes and Brands which original Article is related to them
Let say that in First Table We have following Data:
PartId Code Brand
100 15FY MCD
Second Table Has following data:
ID PartID AddCode AddData
1 100 1888 AddBrand1
2 100 FF0-1 AddBrand2
I want to display data with select like this:
PartId Code Brand
100 15FY MCD
100 1888 AddBrand1
100 FF0-1 AddBrand2
I've tried to use:
Select a.PartID, a.Code, a.Brand,b.AddCode,b.AddData
from table1 a left outer join
table2 b on a.PartId=b.PartId
but i cant figure out how to do it...
Thank you in advance
This sounds more like union all then join:
select PartId, Code, Brand
from ((select t1.PartId, t1.Code, t1.Brand, 1 as seq
from table1 t1
) union all
(select t2.PartId, t2.AddCode as Code, t2.AddBrand as brand, 2 as seq
from t2
)
) x
order by PartId, seq;
Note that this orders the results so all PartIds appear together in the result set, with the row from the first table appearing first.
Use UNION ALL Statement In SELECT Clause :
SELECT PartId, Code, Brand
FROM Table1
UNION ALL
SELECT PartID ,AddCode Code,AddData Brand
FROM Table2
SELECT *
FROM (
SELECT A.PARTID
,A.CODE
,A.BRAND
FROM TABLE1 A
UNION ALL
SELECT B.PARTID
,B.ADDCODE
,B.ADDDATA
FROM TABLE B
) RESULT
ORDER BY RESULT.PARTID
Use Union of both tables like this
Select PartId, Code, Brand from table1
UNION ALL
Select PartID, AddCode, addData
from table2

Union of multiple queries using the count function

I'm working on learning more about how the UNION function works in SQL Server.
I've got a query that is directed at a single table:
SELECT Category, COUNT(*) AS Number
FROM Table1
GROUP BY Category;
This returns the number of entries for each distinct line in the Category column.
I have multiple tables that are organized by this Category column and I'd like to be able to have the results for every table returned by one query.
It seems like UNION will accomplish what I want it to do but the way I've tried implementing the query doesn't work with COUNT(*).
SELECT *
FROM (SELECT Table1.Category
Table1.COUNT(*) AS Number
FROM dbo.Table1
UNION
SELECT Table2.Category
Table2.COUNT(*) AS Number
FROM dbo.Table2) AS a
GROUP BY a.Category
I'm sure there's an obvious reason why this doesn't work but can anyone point out what that is and how I could accomplish what I'm trying to do?
You cannot write a common Group by clause for two different select's. You need to use Group by clause for each select
SELECT TABLE1.Category, --missing comma here
COUNT(*) as Number -- Remove TABLE1. alias name
FROM dbo.TABLE1
GROUP BY Category
UNION ALL --UNION
SELECT TABLE2.Category, --missing comma here
COUNT(*) as Number -- Remove TABLE1. alias name
FROM dbo.TABLE2
GROUP BY Category
If you really want to remove duplicates in result then change UNION ALL to UNION
COUNT as any associated aggregation function has to have GROUP BY specified. You have to use group by for each sub query separately:
SELECT * FROM (
SELECT TABLE1.Category,
COUNT(*) as Number
FROM dbo.TABLE1
GROUP BY TABLE1.Category
UNION ALL
SELECT TABLE2.Category,
COUNT(*) as Number
FROM dbo.TABLE2
GROUP BY TABLE2.Category
) as a
It is better to use UNION ALL vs UNION - UNION eliminates duplicates from result sets, since - let say - you want to merge both results as they are it is safer to use UNION ALL

Sum values from different tables

I read some topics about this but I'm not very good with sql. I have 10 tables with these fields:
value
type
date
I want to sum all the value fileds together when they have a specific type. I was trying to do something like this, but it's not working.
select sum(tab1.value) + sum(tab2.value)
from tab1, tab2
where tab1.type = tab2.type = 'box'
I guess I could do many simple queries like these and then sum all the results
select sum(value) from tab1 where type='box'
select sum(value) from tab2 where type='box'
but I wonder if I can do one single query
thanks
Having multiple tables with the same structure is usually a sign of poor database design.
I would suggest that you use your last approach, but put the subqueries in the from clause and then add the results in the select:
select t1.value + t2.value + . .
from (select sum(value) as value from tab1 where type='box') t1 cross join
(select sum(value) as value from tab2 where type='box') t2 cross join
. . .
Alternatively, you could union all them together in the from clause and then take the sum:
select sum(value)
from ((select sum(value) as value from tab1 where type='box') union all
(select sum(value) as value from tab2 where type='box') union all
. . .
) t;
If the tables are not linked via FK/PK you can use multiple sub-queries:
SELECT (SELECT SUM(tab1.value) FROM tab1 WHERE type='box') as Tab1Sum,
(SELECT SUM(tab2.value) FROM tab2 WHERE type='box') as Tab2Sum -- and so on...
This yields a single record where each column is the sum of each table.
1.Use single select;
DECLARE #type NVARCHAR(255) = N'Box';
SELECT (SELECT SUM(value) FROM tab1 WHERE type=#Box)
+ (SELECT SUM(value) FROM tab2 WHERE type=#Box)
+ (SELECT SUM(value) FROM tab3 WHERE type=#Box)
+ (...)
I think it's simplest one.
2.you create a view as
CREATE VIEW tabs
AS
SELECT value, type FROM tab1
UNION
SELECT value, type FROM tab2
UNION
SELECT value, type FROM tab3
UNION
...
Then
SELECT SUM(value) FROM tabs WHERE type = 'BOX'
3.Think why similar column are different tables. Can they be merged into single table?
If answer is No, and you have too many tables, consider concatenate SQL strings and use sp_executesql to execute it.

Case on union of multiple unions and issue with alias

I have 2 series of unions which I wish to join by another union. In the first one, I have 3 Selects and in the second one I have 2 different Selects.
Select id, min(value)
from table1 t1
join (Select id, value
Union
Select id, value
Union
Select id, value) as foo
on foo.id=t1.id
Group by id
Select id, max(value)
from table1 t1
join (Select id, value
Union
Select id, value) as bar
on bar.id=t1.id
Group by id
I tried to do a union between these two, but it made things pretty complicated. My biggest issue is with my alias. My second is with the case linked to my value columns, which I wish to name value.
Select (alias).id,
Case
When foo.value= 0 or bar.value=1 THEN 1
Else 0
End as value
from table1 t1
Join (Select id, min(value)
from table1 t1
join (Select id, value
Union
Select id, value
Union
Select id, value) as foo
on foo.id=t1.id
Group by id
UNION
Select id, max(value)
from table1 t1
join (Select id, value
Union
Select id, value) as bar
on bar.id=t1.id
Group by id) as (alias)
on ??.id=??.id
I wrote my case the way I think it should be written, but normally, when there are more than one column with the same name, SQL states it as ambiguous. I am still unsure if I should use UNION or INTERSECT, but I assume either of them would be done the same way. How should I deal with this?
I'm reading this right, you probably want something like this
SELECT ...
FROM ( ... union #1 ) AS u1
JOIN (... union #2 ) AS u2 ON u1.id = u2.id

Creating SQL UNION where second side of the union depends on first side

I would .like to perform a union of two queries where second query depends on first:
SELECT * FROM company_res t1
UNION
SELECT * FROM company_res t2
WHERE t2.company_id IN (
SELECT c.id
FROM company c
WHERE c.parent_id = t1.company_id
)
ORDER BY company_id, year_code
However, when I run this queries in psql I get an error to the effect that t1 in second query does have a FROM-clause.
Is it possible to have UNION of tow queries that depend on each other?
From your partial example I think you're trying to make a recursive query, and not a classical UNION query, that's an adavnced for of UNIONS if fact.
You need to perform some selections on company_res, and then to add parents of theses companies.
The basic form is:
WITH RECURSIVE t(n) AS (
SELECT 1
UNION ALL
SELECT n+1 FROM t
)
SELECT n FROM t LIMIT 100;
In you case something like that maybe:
WITH RECURSIVE rectable(
company_id,
field2,
field3,
parent_id) AS (
-- here the starting rows, t1 in your example
SELECT
company_res.company_id,
company_res.field2,
company_res.field3,
company.parent_id
FROM company_res
INNER JOIN company ON company_res.company_id=company.id
WHERE (here any condition on the starting points)
UNION ALL
-- here the recursive part
SELECT
orig.company_id,
orig.field2,
orig.field3,
orig.parent_id
FROM rectable rec,company_res orig
INNER JOIN company ON orig.company_id=company.id
WHERE company.parent_id=rec.company_id
-- here you could add some AND sections if you want
)
SELECT company_id,field2, field3,parent_id
FROM rectable
ORDER BY parent_id;
The SELECT * FROM company_res t1 in your query is going to provide you with everything from company_res, regardless of what else you UNION it with from company_res. I doubt that's what you're looking for. See the answer from shahkalpesh.