Reputation: 1195
Let's say :
SELECT Item.Id, Item.ParentId FROM Item ..."
Returns me this data:
Id | ParentId
----------------
1 | NULL
2 | 17
3 | 13
Is there is a way to get this data as one column by using some kind of UNION
but on columns from only one SELECT
? Something like:
SELECT (Item.Id UNION Item.ParentId) AS Id FROM Item...
Result :
Id |
----
1 |
2 |
3 |
NULL
17 |
13 |
EDIT EXAMPLE:
I have Media Table:
Id | ParentId
----------------
1 | NULL
2 | 1
3 | 2
It have relations with itself, this is some kind of 3 level tree structure (Series -> Seasons -> Episodes)
There is another Table Offer which contain information about availability:
Id | MediaId | Availability
------------------------------
1 | 3 | true
I need to get id's of all media that are available, but also all parent's id, of all levels.
I was thinking about:
SELECT Media.Id, MediaSeason.Id, MediaSeries.Id FROM Media
LEFT JOIN Media AS MediaSeason ON MediaSeason.Id = Media.ParentId
LEFT JOIN Media AS MediaSeries ON MediaSeries.Id = MediaSeason.ParentId
LEFT JOIN Offer ON Offer.MediaId = Media.Id
WHERE Offer.Availability = true
This gives me all id's i need but in three different columns and I'm trying to find a way to put it into one, without repeating join and where login in 3 different SELECTS.
I'm using MSSQL.
Upvotes: 1
Views: 6005
Reputation: 3384
Nested selects can be avoided in UNION
create table tab (
Id int,
ParentId int
);
insert into tab
values
(1, NULL),
(2, 17),
(3, 13);
then do
select ID as ID
from tab
union all
select ParentId as ID
from tab
NOTE: DB queries can be conveniently tested live, e.g. http://sqlfiddle.com/#!17/7a3a8/2
Upvotes: 0
Reputation: 86808
SELECT DISTINCT
pivot_hierarchy.media_id
FROM
offers o
LEFT JOIN
media m1
ON m1.id = o.media_id
LEFT JOIN
media m2
ON m2.id = m1.parent_id
OUTER APPLY
(
SELECT o.media_id
UNION ALL
SELECT m1.parent_id WHERE m1.parent_id IS NOT NULL
UNION ALL
SELECT m2.parent_id WHERE m2.parent_id IS NOT NULL
)
AS pivot_hierarchy
WHERE
o.availability = 'true'
Everything up to the APPLY should be self explanatory. Get the offers, get the parent of that media if it has one, and the parent of that media if it has one.
The APPLY then joins each row on to a function that can return more than one row each. In this case the function returns 1, 2 or 3 rows. Those being the media id, it parent if it has one, and its grand-parent if it has one. To do that, the function unions the three input columns, provided that they’re not null.
This avoids having to join back on to the media table again.
Also, you need a distinct in the select. Otherwise the same series or season id could return multiple times.
Upvotes: 1
Reputation: 2798
If your children and parents are in the same table (Item)
SELECT Id FROM Item
Will retrieve all Items, including Parents because parents are also Items.
But if what you want is to not repeat the where clause and have Ids of any matched Media and its associated parents (even if the parent media does not match the where clause) you can try this:
SELECT
m.Id
FROM
Media m INNER JOIN (
SELECT
m2.Id, m2.ParentId
FROM
Media m2
LEFT JOIN Offer ON Offer.MediaId = m2.Id
WHERE
Offer.Availability = true
) tmp ON (tmp.Id = m.Id OR tmp.ParentId = m.Id)
Finally, for three levels:
SELECT
m.Id
FROM
Media m INNER JOIN (
SELECT
m2.Id, m2.ParentId, m3.ParentId AS GrandParentId
FROM
Media m2
LEFT JOIN Media m3 ON m2.ParentId = m3.Id
LEFT JOIN Offer ON Offer.MediaId = m2.Id
WHERE
Offer.Availability = true
) tmp ON (tmp.Id = m.Id OR tmp.ParentId = m.Id OR tmp.GrandParentId = m.Id)
Upvotes: 2
Reputation: 161
Try this:
SELECT * FROM (SELECT Item.Id FROM Item ...
UNION ALL
SELECT Item.ParentId FROM Item ...)
Upvotes: 5