SQL, Union queries, and removing "duplicates"

I’m having a bit of difficulty using the union query exactly as I would like.

Say I have two tables, one containing my friends’ favorite liquors, and one with their favorite flowers. I want to combine the tables to make “gifts”: I prefer to buy flowers, but if there is no favorite flower in the table, I’ll buy their favorite liquor.

For example

Inputs:



LIQUORS TABLE
FRIEND   LIQUOR
Alice    Tequila
Bob      Whiskey

FLOWERS TABLE
FRIEND  FLOWER
Alice   Roses
Cheryl  Daisies

Then I want to do a query which displays



GIFTS TABLE
FRIEND   GIFT
Alice    Roses
Bob      Whiskey
Cherly   Daisies

I’ve gotten this to work before, but maybe I had primary keys set… how do I avoid the duplicating the Friend field?

You didn’t say what kind of database you’re using, which makes giving suggestions difficult.

I’d say your best bet is to select the appropriate entries in the queries before you merge the results. The syntax below may or may not work, depending on your database.
SELECT FRIEND, FLOWER as Gift FROM FLOWERS

UNION

SELECT FRIEND, LIQUOR as Gift FROM LIQUORS LEFT OUTER JOIN FLOWERS
ON FLOWERS.FRIEND = LIQUORS.FRIEND
WHERE FLOWERS.FRIEND IS NULL

It’s possible you could do a NVL to a subquery(by the way I think in Oracle sqlplus).

Something like:

Select friend, NVL(Flower,(select Liquor from liquor B where A.friend = B.friend) )from Flower A;

But I don’t have access to a DB right now to test it. I know I’ve tried to do things like that, But I can’t remember if I ever got it to work. :slight_smile: I’ve tried a lot of wierd things.

I think you could use a subquery of


WHERE NOT EXISTS <select friend by flower query here>

to pull out flowers in preference to booze.

I’m supposed to be writing real code at work, maybe back later if I get time.

Edit timeout before comepltion, trying again.
It’s possible you could do a NVL to a subquery(by the way I think in Oracle sqlplus).

Something like:

Select friend, NVL(Flower,(select Liquor from liquor B where A.friend = B.friend) )from Flower A;

Union
select friend, liquor from liquor where friend NOT IN (select friend from flower);

But I don’t have access to a DB right now to test it. I know I’ve tried to do things like that, But I can’t remember if I ever got it to work. :slight_smile: I’ve tried a lot of wierd things.

This returned exactly what you wanted in SQL Server 2005:

SELECT COALESCE(f.friend, l.friend) AS ‘Friend’, COALESCE(f.flower, l.liquor) AS ‘Gift’
FROM #tmpFlowers F FULL JOIN #tmpLiquors l ON f.[Friend] = l.[Friend]

What a full join does is give you everything from both tables.

SELECT * FROM #tmpFlowers F FULL JOIN #tmpLiquors l ON f.[Friend] = l.[Friend]

Friend Flower Friend Liquor
Cheryl Daisies NULL NULL
Alice Roses Alice Tequila
NULL NULL Bob Whiskey

And the COALESCE gives you the first non null values from the list provided in the parenthesis.

Of course, there about 10 different ways to do this. If this was a hypothetical example for something you need to do in production, you may want to look at a few different ways, compare the execution plan and performance. If you do it this way, be careful about the order you put things in in the COALESCE - it is important.

Sorry about the edit - I wasn’t done typing and I accidentally posted

Yeah, this should work(it does on Postgres).

My data


SQL> select * from flower;

CHUM       FLOWER
---------- --------------------
Bob        Red Roses
Alice      Pansies
Edna       Peones

SQL> select * from booze;

CHUM       TIPPLE
---------- --------------------
Bob        Gordons
Alice      Laphraig
Charlie    Absinthe
Dave       Beer
Edna       Cinzano
Fran       Vodka Martini

Union query



select chum, tipple
from booze
where chum not in (select chum from flower)
union
select chum, flower
from flower

Result


CHUM       TIPPLE
---------- --------------------
Alice      Pansies
Bob        Red Roses
Charlie    Absinthe
Dave       Beer
Edna       Peones
Fran       Vodka Martini

If you’re worried about the column headings alias ‘TIPPLE’ to ‘GIFT’