Home > Back-end >  Why do I get 0 rows when I join multiple table with a personal id?
Why do I get 0 rows when I join multiple table with a personal id?

Time:10-05

I have a table whose matching type of clothes and the name of the model for one owner. The table is given by a software I work with, I can't change the design of my model.

The owner of this wardrobe is Paul who has poa as a personal ID

ID owner_id cid Name Type Date_own_from Date_own_to
1 poa sho-1 The dragon Shoes 01-01-2021 01-10-2021
2 poa shi-1 SimpleT Shirt 01-01-2021 31-12-2099
3 poa so-21 White model Sockets 01-01-2021 31-12-2099
4 poa sho-3 Snake speed 3 Shoes 01-10-2021 31-12-2099

An Owner can only own one pair of each type of clothes. If Date_own_to is 31-12-2099 it means that the owner didn't bring the clothe back.

Each type correspond of one table which has more information about the product

Here is an example for Shoes :

ID Clothes_ID Size
1 sho-1 42

Here is for Shirts :

ID Clothes_ID Size
1 shi-1 M

And for Sockets :

ID Clothes_ID Size
1 so-21 M

What I'm trying to do is to list every clothes for each person like this :

ID Owner Shoes Shirt Sockets
1 poa SnakeSpeed SimpleT White model

So I tried to do this :

SELECT * FROM wardrobe w
JOIN shoes sho 
 on sho.clothes_id = w.cid 
where owner_id = 'poa'

With this request I got this :

ID Owner Shoes
1 poa SnakeSpeed

But now when I try to join an other table table with this request

SELECT * FROM wardrobe w
JOIN shoes sho 
 on sho.clothes_id = w.cid 
JOIN shirt shi
 on shi.clothes_id = w.cid
where owner_id = 'poa'

And the result of this is 0 rows.

I don't know how to properly join the values.

What I am doing wrong?

Multiple Rows

Since I only have one t-shirt owned for one period. If I want to look for the clothes owned by a person for a given period I would like to do something like this :

date_own_from = '01-01-2021' and date_own_to = '31-12-2021'

So the desired results would be :

ID Name Shoes Shirt Sockets
1 Paul SnakeSpeed SimpleT White model
2 Paul The Dragon SimpleT White model

A row 2 differents shoes owned during the year with the Shirt and the Socket owned when the persons owned the shoes.

CodePudding user response:

not sure why you need to join any table because they are not adding anything to your results...unless you have oversimplified.

based on your results this will do.

BUT....if an owner has more than one pair of shoes etc, you need to tell us what you want to see in your results

SELECT
  owner_id AS owner,
  MAX(CASE WHEN type = 'shoes' THEN name END) AS shoes,
  MAX(CASE WHEN type = 'shirt' THEN name END) AS shirt,
  MAX(CASE WHEN type = 'sockets' THEN name END) AS sockets
FROM w
GROUP BY owner_id

CodePudding user response:

Given the poor design you have to work with you have a struggle here.

Here is sample data and ddl in case anybody wants to play along.

create table Wardrobe
(
    ID int
    , owner_id varchar(10)
    , cid varchar(10)
    , Name varchar(20)
    , Type varchar(10)
)

insert Wardrobe
select 1, 'poa', 'sho-1', 'SnakeSpeed', 'Shoes' union all
select 2, 'poa', 'shi-1', 'SimpleT', 'Shirt' union all
select 3, 'poa', 'so-21', 'White model', 'Sockets'

insert Wardrobe
select 4, 'poa', 'so-22', 'green', 'Sockets'

create table Shoes
(
    ID int
    , Clothes_ID varchar(10)
    , Size varchar(10)
)

insert Shoes
select 1, 'sho-1', '42'

create table Shirts
(
    ID int
    , Clothes_ID varchar(10)
    , Size varchar(10)
)

insert Shirts
select 1, 'shi-1', 'M'

create table Sockets
(
    ID int
    , Clothes_ID varchar(10)
    , Size varchar(10)
)

insert Sockets
select 2, 'so-22', 'M'

There are probably some other ways to deal with this. But this example will work even if they a single person has only two shoes and a single shirt with no sockets. I started by isolating each set of rows using some ctes and row_number. Then munge them back together with some conditional aggregation.

declare @Owner varchar(10) = 'poa';

with cteShoes as
(
    select w.ID
        , w.owner_id
        , w.Name
        , sho.Size
        , RowNum = ROW_NUMBER() over(order by w.Name)
    from Wardrobe w     
    join Shoes sho on sho.Clothes_ID = w.cid and w.Type = 'Shoes'
    where w.owner_id = @Owner
)
, cteShirts as
(
    select w.ID
        , w.owner_id
        , w.Name
        , shi.Size
        , RowNum = ROW_NUMBER() over(order by w.Name)
    from Wardrobe w 
    join Shirts shi on shi.Clothes_ID = w.cid and w.Type = 'Shirt'
    where w.owner_id = @Owner
)
, cteSockets as
(
    select w.ID
        , w.owner_id
        , w.Name
        , soc.Size
        , RowNum = ROW_NUMBER() over(order by w.Name)
    from Wardrobe w 
    join Sockets soc on soc.Clothes_ID = w.cid and w.Type = 'Sockets'
    where w.owner_id = @Owner
)

select Owner = coalesce(sho.owner_id, shi.owner_id, soc.owner_id)
    , Shoes = max(case when sho.RowNum is not null then sho.Name end)
    , ShoesSize = max(case when sho.RowNum is not null then sho.Size end)
    , Shirt = max(case when shi.RowNum is not null then shi.Name end)
    , ShirtSize = max(case when shi.RowNum is not null then shi.Size end)
    , Sockets = max(case when soc.RowNum is not null then soc.Name end)
    , SocketsSize = max(case when soc.RowNum is not null then soc.Size end)
from cteShoes sho
full outer join cteShirts shi on shi.RowNum = sho.RowNum
full outer join cteSockets soc on soc.RowNum = sho.RowNum
group by coalesce(sho.ID, shi.ID, soc.ID)
    , coalesce(sho.owner_id, shi.owner_id, soc.owner_id)

CodePudding user response:

Use left joins since there are no shirts for this user

SELECT w.*, shoes.*, shirt.*
FROM (SELECT distinct cid FROM wardrobe) w
LEFT JOIN (SELECT cid, clothes_id
           FROM wardrobe WHERE type ='Shoes') shoelink ON shoelink.cid = w.cid
LEFT JOIN shoes sho on sho.clothes_id = shoelink.cid 
LEFT JOIN (SELECT cid, clothes_id
           FROM wardrobe WHERE type ='Shirt') shirtlink ON shirtlink.cid = w.cid
LEFT JOIN shirt shi on shi.clothes_id = shirtlink.cid
where owner_id = 'poa'
  • Related